Skip to content

Latest commit

 

History

History
144 lines (129 loc) · 9.36 KB

File metadata and controls

144 lines (129 loc) · 9.36 KB

Thor App Manager - Project Context

Thor is a modern, lightweight, and privacy-focused Android App Manager. It is free and open-source (FOSS), with no ads, trackers, or telemetry, providing advanced app management capabilities through Shizuku, Dhizuku, and Root access.

🏗 Architecture

The project follows Clean Architecture principles combined with MVVM (Model-View-ViewModel) for the presentation layer.

Modules:

  • app/: The core application module.
    • Presentation: Built with Jetpack Compose. ViewModels manage state using StateFlow and Koin for dependency injection.
    • Domain: Pure Kotlin layer containing business logic, Use Cases, and repository interfaces. Platform-agnostic where possible.
    • Data: Implementation of repositories, interacting with Android's PackageManager, Shizuku/Dhizuku APIs, DataStore for preferences, and Room (thor_database) for the app metadata cache, the freezer watchlist and extension data.
    • DI: Koin Annotations, generated by the Koin compiler plugin (io.insert-koin.compiler.plugin) — a Kotlin compiler plugin, not KSP. di/Modules.kt declares a single @Module @ComponentScan("com.valhalla.thor") root; classes opt in with @Single/@Factory/@KoinViewModel rather than being listed in a module. The root supplies only what scanning cannot infer — three @Named dispatchers ("io"/"default"/"main"), PackageManager, the database and its DAOs, and Odin's ShellRepository. compileSafety, strictSafety and unsafeDslChecks are all on, so a missing or ambiguous binding is a compile error, not a runtime crash.
  • Odin (com.trinadhthatakula:odin): Root shell management, consumed from Maven Central rather than built in-tree. A Kotlin-refactored version of the libsu core module by topjohnwu, optimized for modern Kotlin idioms and memory safety, now maintained as a standalone library. It replaced the former suCore/ module; settings.gradle.kts can substitute a local checkout via -PodinDir for cross-repo work.
  • bypass/: A core utility module for bypassing Android's hidden API restrictions using VMRuntime exemptions and enhanced reflection.
  • vm-runtime/: Compile-only Java stubs required for the bypass module to interface with internal Android classes like VMRuntime. Intentionally a pure Java library (not Kotlin) to ensure correct class shadowing behaviour at compile time.

🛠 Tech Stack

  • Language: Kotlin (all modules except vm-runtime, which is pure Java for stub compatibility)
  • UI Framework: Jetpack Compose with MaterialExpressiveTheme + MotionScheme.expressive(). Static "Asgardian" color scheme by default; optional Material You dynamic color on Android 12+. Navigation uses a custom ThorNavigationBar with spring animations + HorizontalPager for swipe-between-screens.
  • Dependency Injection: Koin Annotations via the Koin compiler plugin
  • Asynchronous Programming: Kotlin Coroutines & Flow
  • Image Loading: Coil 3
  • Animation: Lottie + Compose AnimatedVisibility/AnimatedContent
  • Persistence:
    • Jetpack Room: High-performance caching of AppInfo metadata, invalidated via lastUpdateTime.
    • Jetpack DataStore: User preferences including theme, AMOLED mode, biometric lock, and preferred privilege mode.
  • Security: Android Biometrics via BiometricPrompt API directly (no androidx.biometric dependency). HomeActivity extends ComponentActivity.
  • Elevated Privileges:
    • Root (su): Via the Odin library (Kotlin-refactored fork of libsu).
    • Shizuku: Shell-command-first (am, pm, appops) with reflection fallback via :bypass.
    • Dhizuku: Device Owner API with reflection fallback via :bypass.
    • Work Mode (PrivilegeMode): User-selectable privilege engine (ROOT / SHIZUKU / DHIZUKU) with automatic fallback strategy (Root → Shizuku → Dhizuku).
    • Internal Bypass (:bypass): Custom Kotlin implementation using VMRuntime exemptions and reflection, backed by Java stubs in :vm-runtime.
  • Build System: Gradle Kotlin DSL with Version Catalog (libs.versions.toml). Exact tool and library versions defined in libs.versions.toml; do not hardcode them in docs.
  • Distribution: Two product flavors: store (Play Store compliant) and foss (fully libre/open).

✨ Key Features

  • App Management: Install, uninstall, freeze (disable/enable), suspend/unsuspend, and background-restrict apps. Tracks isSuspended and isDebuggable flags directly on AppInfo.
  • Work Mode: User-selectable privilege engine (PrivilegeMode: ROOT, SHIZUKU, DHIZUKU) stored in UserPreferences. Falls back automatically if the preferred mode is unavailable.
  • Batch Operations: Batch freeze/unfreeze, reinstall, uninstall, kill, suspend/unsuspend, and clear data — all logged in real time through the terminal logger dialog.
  • App Suspension: Uses IPackageManager reflection to suspend apps, showing a custom "Thor" -branded system dialog. Supports Android 10 through 13+ with version-specific fallbacks.
  • Background Restriction: Restricts an app's background activity via setAppRestricted.
  • Fix Store (Reinstall with Google): Reassigns installer to Play Store. Available in all privilege modes (Root, Shizuku, Dhizuku).
  • Clear Data / Clear Cache: Available in all privilege modes; clearAppData uses pm clear with multi-user support.
  • Advanced Insights: Installer source (resolved from package labels, not hardcoded), split APK indicators, version codes, SDK targets, isSuspended, isDebuggable.
  • System App Support: Uninstall or freeze system apps (requires any privilege mode). A freeze disables the package and keeps its data. Only where the platform actually refused the disable does it fall back to pm uninstall -k --user N — a per-user removal, not a real uninstall: the APK stays on the read-only partition, the package record survives, and -k keeps both the data directories and the runtime permission grants, so pm install-existing --user N restores the app intact. That refusal is an OEM restriction, not an Android version. Dhizuku is the one exception still on the old path: its gateway is not yet converted, so it removes for the current user unconditionally and without -k. Note the fallback is unavailable to Shizuku at shell uid on API 37, which answers it with only root can delete system app for a particular user. domain/model/FreezePolicy.kt owns the rule; every reader of freeze state must handle both mechanics, since devices carry system apps frozen the old way, when the removal ran first, unconditionally, and without -k.
  • Security: Biometric/device-credential lock for app access. Per-session authentication state.
  • App Metadata Caching: Room DB cache for AppInfo, invalidated via lastUpdateTime.
  • Preferences (UserPreferences): theme, AMOLED, dynamic color, biometric lock, sort/filter state, privilege mode, and language — all persisted via DataStore.
  • Customization: Dark/Light/System + AMOLED themes. "Asgardian" static color scheme is the default; Material You dynamic color opt-in. Preferred privilege mode persisted across sessions.
  • Search: Live search by app name or package name in App List and Freezer screens.
  • Multi-language: Supports English, Spanish, French, Arabic, and Chinese. Runtime locale switching via LocaleManager (util/LocaleManager.kt); language preference stored in UserPreferences.language (null = system default).
  • Privacy: No ads, no trackers, no analytics, FOSS (GPL-3.0). The app declares android.permission.INTERNET; the only network access is the optional Extensions store, which fetches its catalog and verified extension APKs over HTTPS. Every other feature works offline.

⚠️ Limitations

  • Privilege Dependency: Advanced features (freeze, suspend, system app removal) require at least one of Root, Shizuku, or Dhizuku. Work Mode selection with automatic fallback mitigates partial availability.
  • Suspension Compatibility: setAppSuspended uses reflection against internal APIs; behaviour may vary across Android 10–14+ due to API signature changes.
  • No Cloud Sync: No cloud backup or remote synchronization (by design, for privacy).
  • Android Constraints: Subject to evolving Android security restrictions (hidden API policy, target SDK requirements).
  • Feature Gap: App data backup is not yet implemented.

🚀 Opportunities

  • Data Backup: Implementing local app data backup and restoration.
  • Package Editing: Direct editing of packages.xml for advanced users.
  • Batch Install: Installing multiple APKs in one operation.
  • Automation: Scheduled freezing/unfreezing or automated cleanup tasks.
  • Installer Integration: Expanding support for third-party installers (e.g., F-Droid, Aurora Store).

🛡 Threats

  • Play Store Policies: As an "App Manager" with elevated privileges, it faces strict scrutiny from Google Play.
  • Android OS Changes: Future Android updates might further restrict Shizuku or root-level access methods.
  • Competition: Several established open-source app managers exist; maintaining a niche in " lightweight & privacy-first" is key.