From e8187f8086a28f106c802f22c08eb20f3042eccb Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 00:48:41 +0300 Subject: [PATCH 001/162] Push initial Zygisk module, remove LSPosed support (WIP) --- .github/workflows/main.yml | 3 +- CREDITS.md | 1 + README.md | 2 +- README_id.md | 2 +- README_ja.md | 2 +- README_tr.md | 2 +- README_zh_CN.md | 2 +- app/build.gradle.kts | 13 +- app/proguard-rules.pro | 3 - app/src/main/AndroidManifest.xml | 12 - app/src/main/res/values/strings.xml | 6 +- build.gradle.kts | 3 +- .../icu/nullptr/hidemyapplist/common/Utils.kt | 4 + .../common/app_presets/XposedModulesPreset.kt | 5 +- gradle/libs.versions.toml | 11 +- settings.gradle.kts | 10 +- xposed/build.gradle.kts | 29 -- xposed/proguard-rules.pro | 24 -- xposed/src/main/assets/xposed_init | 1 - .../hidemyapplist/xposed/Utils4Xposed.kt | 31 -- .../hidemyapplist/xposed/XposedEntry.kt | 68 ---- .../xposed/hook/AccessibilityHook.kt | 80 ----- .../hidemyapplist/xposed/hook/ActivityHook.kt | 156 --------- .../xposed/hook/AppDataIsolationHook.kt | 220 ------------- .../xposed/hook/ContentProviderHook.kt | 172 ---------- .../xposed/hook/IFrameworkHook.kt | 8 - .../hidemyapplist/xposed/hook/ImmHook.kt | 190 ----------- .../xposed/hook/PmsHookTarget29.kt | 107 ------- .../xposed/hook/PmsHookTarget30.kt | 159 ---------- .../xposed/hook/PmsHookTarget31.kt | 184 ----------- .../xposed/hook/PmsHookTargetBase.kt | 261 --------------- .../xposed/hook/PmsPackageEventsHook.kt | 57 ---- .../hidemyapplist/xposed/hook/ZygoteHook.kt | 51 --- zygote/.gitignore | 1 + zygote/build.gradle.kts | 42 +++ zygote/proguard-rules.pro | 28 ++ zygote/src/main/AndroidManifest.xml | 2 + .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 300 ++++++++++++++++++ .../frknkrc44/hma_oss/zygote}/HMAService.kt | 47 +-- .../org/frknkrc44/hma_oss/zygote}/Logcat.kt | 8 +- .../hma_oss/zygote/SystemServerHook.kt | 72 +++++ .../frknkrc44/hma_oss/zygote}/UserService.kt | 35 +- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 157 +++++++++ .../hma_oss/zygote/ZygoteConstants.kt | 5 +- .../frknkrc44/hma_oss/zygote/ZygoteEntry.java | 37 +++ .../hma_oss/zygote/hook/AccessibilityHook.kt | 75 +++++ .../hma_oss/zygote/hook/ActivityHook.kt | 134 ++++++++ .../zygote/hook/AppDataIsolationHook.kt | 204 ++++++++++++ .../zygote/hook/ContentProviderHook.kt | 167 ++++++++++ .../hma_oss/zygote/hook/IFrameworkHook.kt | 10 + .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 177 +++++++++++ .../zygote}/hook/PlatformCompatHook.kt | 37 +-- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 106 +++++++ .../hma_oss/zygote/hook/PmsHookTarget30.kt | 152 +++++++++ .../hma_oss/zygote/hook/PmsHookTarget31.kt | 178 +++++++++++ .../hma_oss/zygote}/hook/PmsHookTarget33.kt | 63 ++-- .../hma_oss/zygote}/hook/PmsHookTarget34.kt | 89 +++--- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 251 +++++++++++++++ .../zygote/hook/PmsPackageEventsHook.kt | 56 ++++ .../hma_oss/zygote/hook/ZygoteHook.kt | 39 +++ 60 files changed, 2355 insertions(+), 1996 deletions(-) delete mode 100644 xposed/build.gradle.kts delete mode 100644 xposed/proguard-rules.pro delete mode 100644 xposed/src/main/assets/xposed_init delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/IFrameworkHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt create mode 100644 zygote/.gitignore create mode 100644 zygote/build.gradle.kts create mode 100644 zygote/proguard-rules.pro create mode 100644 zygote/src/main/AndroidManifest.xml create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt rename {xposed/src/main/java/icu/nullptr/hidemyapplist/xposed => zygote/src/main/java/org/frknkrc44/hma_oss/zygote}/HMAService.kt (94%) rename {xposed/src/main/java/icu/nullptr/hidemyapplist/xposed => zygote/src/main/java/org/frknkrc44/hma_oss/zygote}/Logcat.kt (90%) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt rename {xposed/src/main/java/icu/nullptr/hidemyapplist/xposed => zygote/src/main/java/org/frknkrc44/hma_oss/zygote}/UserService.kt (75%) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt rename xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedConstants.kt => zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt (90%) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt rename {xposed/src/main/java/icu/nullptr/hidemyapplist/xposed => zygote/src/main/java/org/frknkrc44/hma_oss/zygote}/hook/PlatformCompatHook.kt (65%) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt rename {xposed/src/main/java/icu/nullptr/hidemyapplist/xposed => zygote/src/main/java/org/frknkrc44/hma_oss/zygote}/hook/PmsHookTarget33.kt (63%) rename {xposed/src/main/java/icu/nullptr/hidemyapplist/xposed => zygote/src/main/java/org/frknkrc44/hma_oss/zygote}/hook/PmsHookTarget34.kt (62%) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9e6902b2c..11eca0f52 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -69,7 +69,8 @@ jobs: - name: Build all id: buildAll run: | - ./gradlew assemble + ./gradlew :app:assemble + ./gradlew :zygote:assemble echo "releaseName=$(ls app/build/outputs/apk/release/*.apk | awk -F '(/|.apk)' '{print $6}')" >> $GITHUB_OUTPUT echo "debugName=$(ls app/build/outputs/apk/debug/*.apk | awk -F '(/|.apk)' '{print $6}')" >> $GITHUB_OUTPUT echo "releaseFile=$(ls app/build/outputs/apk/release/*.apk)" >> $GITHUB_OUTPUT diff --git a/CREDITS.md b/CREDITS.md index 32e178516..3a3a2ddd1 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -5,6 +5,7 @@ - [IAmNotADeveloper](https://github.com/xfqwdsj/IAmNotADeveloper) - hiding developer options idea - [BetterKnownInstalled](https://github.com/Pixel-Props/BetterKnownInstalled) - package installer spoofing idea - [0bbedCode](https://github.com/0bbedCode) - ID checker +- [vova7878](https://github.com/vova7878) - ZygoteLoader, AndroidVMTools and PanamaPort - All translators - All root community - You (if you are not a robot 🤖) diff --git a/README.md b/README.md index d34e87135..818192de1 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Although it's bad practice to detect the installation of specific apps, not ever Additionally, some apps use various loopholes to acquire your app list, in order to use it as fingerprinting data or for other nefarious purposes. -This module can work as an Xposed module to hide apps or reject app list requests. +This module can work as an Zygisk module to hide apps or reject app list requests. ## About HMA-OSS diff --git a/README_id.md b/README_id.md index ae6e66e14..f79da5981 100644 --- a/README_id.md +++ b/README_id.md @@ -45,7 +45,7 @@ Meskipun merupakan praktik yang buruk untuk mendeteksi pemasangan aplikasi terte Selain itu, beberapa aplikasi menggunakan berbagai celah untuk memperoleh daftar aplikasi anda, untuk menggunakannya sebagai data fingerprinting atau untuk tujuan lain yang tidak diinginkan. -Modul ini dapat berfungsi sebagai modul Xposed untuk menyembunyikan aplikasi atau menolak permintaan daftar aplikasi. +Modul ini dapat berfungsi sebagai modul Zygisk untuk menyembunyikan aplikasi atau menolak permintaan daftar aplikasi. ## Saya ingin berkontribusi dalam terjemahan Anda dapat berkontribusi dalam penerjemahan [Di Sini](https://crowdin.com/project/frknkrc44-hma-oss). diff --git a/README_ja.md b/README_ja.md index 16cbd172f..ce182b6ca 100644 --- a/README_ja.md +++ b/README_ja.md @@ -45,7 +45,7 @@ さらに、一部のアプリはさまざまな抜け穴を利用してアプリリストを取得し、それをフィンガープリンティングデータとして使用したり、その他の不正な目的に使用したりします。 -このモジュールは、アプリを非表示にしたり、アプリリストの要求を拒否したりする Xposed モジュールとして機能します。 +このモジュールは、アプリを非表示にしたり、アプリリストの要求を拒否したりする Zygisk モジュールとして機能します。 ## 翻訳に貢献する [こちら](https://crowdin.com/project/frknkrc44-hma-oss)から翻訳に貢献することができます。 diff --git a/README_tr.md b/README_tr.md index e03ad8356..7c1d07f82 100644 --- a/README_tr.md +++ b/README_tr.md @@ -45,7 +45,7 @@ Belirli uygulamaların kurulu olup olmadığını tespit etmek kötü bir yönte Ayrıca bazı uygulamalar uygulama listenizi ele geçirmek, parmak izi verileri olarak kullanmak veya başka kötü niyetli amaçlar için çeşitli açıklardan yararlanır. -Bu modül, uygulamaları gizlemek veya uygulama listesi isteklerini reddetmek için çalışabilen bir Xposed modülüdür. +Bu modül, uygulamaları gizlemek veya uygulama listesi isteklerini reddetmek için çalışabilen bir Zygisk modülüdür. ## Çeviriye katkıda bulunmak istiyorum [Buraya tıklayarak](https://crowdin.com/project/frknkrc44-hma-oss) çeviriye katkıda bulunabilirsiniz. diff --git a/README_zh_CN.md b/README_zh_CN.md index 1895672ca..da1df1b8e 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -42,7 +42,7 @@ ## 关于该模块 虽然“检测安装的应用”是不正确的做法,但是并不是所有的与 root 相关联的插件类应用都提供了随机包名支持。这就意味着检测到安装了此类应用(如 Fake Location 、存储空间隔离)与检测到了 root 本身区别不大。(会使用检测手段的 app 可不会认为你是在“我就蹭蹭不进去”) 与此同时,部分“不安分”的应用会使用各种漏洞绕过系统权限来获取你的应用列表,从而对你建立用户画像。(如陈叔叔将安装了 V2Ray 的用户分为一类),或是类似于某某校园某某乐跑的软件会要求你卸载作弊软件。 -该模块提供了一些检测方式用于测试您是否成功地隐藏了某些特定的包名,如 Magisk/Edxposed Manager;同时可作为 Xposed 模块用于隐藏应用列表或特定应用,保护隐私。 +该模块提供了一些检测方式用于测试您是否成功地隐藏了某些特定的包名,如 Magisk Manager;同时可作为 Zygisk 模块用于隐藏应用列表或特定应用,保护隐私。 ## 更新日志 [参考发布页面](https://github.com/frknkrc44/HMA-OSS/commits) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d2635004b..dc13a0aef 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -122,6 +122,10 @@ android { viewBinding = true } + base { + archivesName = "${rootProject.name}-${defaultConfig.versionName}" + } + packaging { dex.useLegacyPackaging = true resources { @@ -148,7 +152,6 @@ autoResConfig { dependencies { implementation(projects.common) - runtimeOnly(projects.xposed) implementation(libs.androidx.navigation.fragment.ktx) implementation(libs.androidx.navigation.ui.ktx) @@ -165,11 +168,3 @@ dependencies { implementation(libs.androidx.appcompat.appcompat) implementation(libs.material) } - -android.applicationVariants.all { - outputs.all { - (this as BaseVariantOutputImpl).apply { - outputFileName = "${rootProject.name.replace(" ", "_")}-${versionName}-${buildType.name}.apk" - } - } -} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index d5645a4a9..91fee77c4 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -4,9 +4,6 @@ public static ** valueOf(java.lang.String); } --keep class icu.nullptr.hidemyapplist.data.UpdateData { *; } --keep class icu.nullptr.hidemyapplist.data.UpdateData$* { *; } - -keep,allowoptimization class * extends androidx.preference.PreferenceFragmentCompat -keepclassmembers class org.frknkrc44.hma_oss.databinding.** { public ; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9a0d6799c..0c62d6ff1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -81,17 +81,5 @@ android:exported="true" tools:ignore="ExportedContentProvider" /> - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 62accfa92..999f9ac04 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -176,7 +176,7 @@ Detail log for debugging Logger buffer sizes Hide module icon in launcher - You can still open the app in Xposed manager + You can still open the app in root manager Bypass risky package warning Note that the devs are not responsible for risky package related issues before or after you enabled this feature Disable Activity launch protection @@ -220,14 +220,14 @@ - Although It is incorrect to detect specific app installation, yet not every app using root provides random package name support. In this case, detected apps that use root (such as Fake Location and Storage Isolation) is equal to detected root itself.\n\nAt the same time, some smart apps use various loopholes to acquire your app list, so that it can draw a persona for you.\n\nThis module provides some methods to test whether you have already hidden your applist nicely. Also, it can work as an Xposed module to hide some apps or reject app list requests to protect your privacy. + Although It is incorrect to detect specific app installation, yet not every app using root provides random package name support. In this case, detected apps that use root (such as Fake Location and Storage Isolation) is equal to detected root itself.\n\nAt the same time, some smart apps use various loopholes to acquire your app list, so that it can draw a persona for you.\n\nThis module provides some methods to test whether you have already hidden your applist nicely. Also, it can work as an Zygisk module to hide some apps or reject app list requests to protect your privacy. The original HMA project has become closed-source and their latest code didn\'t contain some of the latest changes, so I created this fork to continue it as open-source again. How to use this module - You can create templates in \"Manage templates\".\nThen apply the templates to apps in \"Manage apps\". (You can also select extra apps for targets.)\nYou should and ONLY should check \"System Framework\" in Xposed module scope / whitelist. + You can create templates in \"Manage templates\".\nThen apply the templates to apps in \"Manage apps\". (You can also select extra apps for targets.) Config modification effective in real time. diff --git a/build.gradle.kts b/build.gradle.kts index 9593931b7..4d1f2be3f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,13 @@ import com.android.build.api.dsl.ApplicationExtension import com.android.build.gradle.BaseExtension -import org.jetbrains.kotlin.konan.properties.Properties +import java.util.Properties plugins { alias(libs.plugins.kotlin) apply false alias(libs.plugins.agp.app) apply false alias(libs.plugins.agp.lib) apply false alias(libs.plugins.nav.safeargs.kotlin) apply false + alias(libs.plugins.com.github.aerathstuff.zygoteloader) apply false } fun String.execute(currentWorkingDir: File = file("./")): String { diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index 98e61f27f..6aab2b801 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -121,4 +121,8 @@ object Utils { return false } } + + inline fun MutableMap.removeIf(predicate: (K, V) -> Boolean) { + this.filter { (key, value) -> predicate(key, value) }.forEach { this.remove(it.key) } + } } diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/XposedModulesPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/XposedModulesPreset.kt index 34bdc5b3f..00b9c6fb1 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/XposedModulesPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/XposedModulesPreset.kt @@ -2,13 +2,16 @@ package icu.nullptr.hidemyapplist.common.app_presets import android.content.pm.ApplicationInfo import icu.nullptr.hidemyapplist.common.Utils.checkSplitPackages +import org.frknkrc44.hma_oss.common.BuildConfig class XposedModulesPreset : BasePreset(NAME) { companion object { const val NAME = "xposed" } - override val exactPackageNames = setOf() + override val exactPackageNames = setOf( + BuildConfig.APP_PACKAGE_NAME, + ) override fun canBeAddedIntoPreset(appInfo: ApplicationInfo): Boolean { return checkSplitPackages(appInfo) { _, zipFile -> diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c79a72b4..7b251f920 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,14 @@ [versions] #noinspection AndroidGradlePluginVersion agp = "8.13.2" -kotlin = "2.3.0" +kotlin = "2.3.10" material = "1.13.0" hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" +r8_annotations = "v1.0.0" +androidvmtools = "85bc140b50" +zygoteloader = "bf5078e182" [plugins] agp-app = { id = "com.android.application", version.ref = "agp" } @@ -16,6 +19,7 @@ nav-safeargs-kotlin = { id = "androidx.navigation.safeargs.kotlin", version.ref autoresconfig = { id = "dev.rikka.tools.autoresconfig", version = "1.2.2" } refine = { id = "dev.rikka.tools.refine", version = "4.4.0" } materialthemebuilder = { id = "dev.rikka.tools.materialthemebuilder", version = "1.5.1" } +com-github-aerathstuff-zygoteloader = { id = "com.github.aerath-stuff.ZygoteLoader", version.ref = "zygoteloader" } [libraries] androidx-appcompat-appcompat = { group = "androidx.appcompat", name = "appcompat", version = "1.7.1" } @@ -27,12 +31,11 @@ androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefre com-github-bumptech-glide = { module = "com.github.bumptech.glide:glide", version = "5.0.5" } dev-androidbroadcast-vbpd = { module = "dev.androidbroadcast.vbpd:vbpd", version.ref = "vbpd" } dev-androidbroadcast-vbpd-reflection = { module = "dev.androidbroadcast.vbpd:vbpd-reflection", version.ref = "vbpd" } -#noinspection NewerVersionAvailable -com-github-kyuubiran-ezxhelper = { module = "com.github.kyuubiran:EzXHelper", version = "1.0.3" } com-github-topjohnwu-libsu-core = { module = "com.github.topjohnwu.libsu:core", version = "6.0.0" } -de-robv-android-xposed-api = { module = "de.robv.android.xposed:api", version = "82" } dev-rikka-hidden-compat = { module = "dev.rikka.hidden:compat", version.ref = "hidden-api" } dev-rikka-hidden-stub = { module = "dev.rikka.hidden:stub", version.ref = "hidden-api" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.10.0" } material = { module = "com.google.android.material:material", version.ref = "material" } me-zhanghai-android-appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" } +io-github-vova7878-androidvmtools = { module = "com.github.aerath-stuff:AndroidVMTools", version.ref = "androidvmtools" } +io-github-vova7878-r8annotations = { module = "io.github.vova7878:R8Annotations", version.ref = "r8_annotations" } diff --git a/settings.gradle.kts b/settings.gradle.kts index c775091d7..7b57ac3e4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,8 @@ pluginManagement { gradlePluginPortal() google() mavenCentral() + mavenLocal() + maven("https://jitpack.io") maven("https://mirrors.cloud.tencent.com/nexus/repository/maven-public") maven("https://maven.aliyun.com/repository/public") } @@ -15,10 +17,10 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + mavenLocal() + maven("https://jitpack.io") maven("https://mirrors.cloud.tencent.com/nexus/repository/maven-public") maven("https://maven.aliyun.com/repository/public") - maven("https://jitpack.io") - maven("https://api.xposed.info/") } } @@ -26,6 +28,6 @@ rootProject.name = "HMA-OSS" include( ":app", - ":common", - ":xposed" + ":common" ) +include(":zygote") diff --git a/xposed/build.gradle.kts b/xposed/build.gradle.kts deleted file mode 100644 index 0a2d5701a..000000000 --- a/xposed/build.gradle.kts +++ /dev/null @@ -1,29 +0,0 @@ -plugins { - alias(libs.plugins.agp.lib) - alias(libs.plugins.refine) - alias(libs.plugins.kotlin) -} - -val appPackageName: String by rootProject.extra - -android { - namespace = "$appPackageName.xposed" - - buildFeatures { - buildConfig = false - } -} - -kotlin { - jvmToolchain(21) -} - -dependencies { - implementation(projects.common) - - implementation(libs.androidx.annotation.jvm) - implementation(libs.com.github.kyuubiran.ezxhelper) - implementation(libs.dev.rikka.hidden.compat) - compileOnly(libs.de.robv.android.xposed.api) - compileOnly(libs.dev.rikka.hidden.stub) -} diff --git a/xposed/proguard-rules.pro b/xposed/proguard-rules.pro deleted file mode 100644 index fc2c1b4c9..000000000 --- a/xposed/proguard-rules.pro +++ /dev/null @@ -1,24 +0,0 @@ --keep class com.github.kyuubiran.ezxhelper.utils.** { *; } --keep class icu.nullptr.hidemyapplist.xposed.XposedEntry { *; } --dontwarn java.lang.invoke.StringConcatFactory --dontwarn android.content.res.XModuleResources --dontwarn android.content.res.XResources --dontwarn de.robv.android.xposed.IXposedHookLoadPackage --dontwarn de.robv.android.xposed.IXposedHookZygoteInit$StartupParam --dontwarn de.robv.android.xposed.IXposedHookZygoteInit --dontwarn de.robv.android.xposed.XC_MethodHook$MethodHookParam --dontwarn de.robv.android.xposed.XC_MethodHook$Unhook --dontwarn de.robv.android.xposed.XC_MethodHook --dontwarn de.robv.android.xposed.XC_MethodReplacement --dontwarn de.robv.android.xposed.XposedBridge --dontwarn de.robv.android.xposed.XposedHelpers --dontwarn de.robv.android.xposed.callbacks.XC_LoadPackage$LoadPackageParam --dontwarn org.bouncycastle.jsse.BCSSLParameters --dontwarn org.bouncycastle.jsse.BCSSLSocket --dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider --dontwarn org.conscrypt.Conscrypt$Version --dontwarn org.conscrypt.Conscrypt --dontwarn org.conscrypt.ConscryptHostnameVerifier --dontwarn org.openjsse.javax.net.ssl.SSLParameters --dontwarn org.openjsse.javax.net.ssl.SSLSocket --dontwarn org.openjsse.net.ssl.OpenJSSE diff --git a/xposed/src/main/assets/xposed_init b/xposed/src/main/assets/xposed_init deleted file mode 100644 index 013e21419..000000000 --- a/xposed/src/main/assets/xposed_init +++ /dev/null @@ -1 +0,0 @@ -icu.nullptr.hidemyapplist.xposed.XposedEntry diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt deleted file mode 100644 index 5b2715868..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt +++ /dev/null @@ -1,31 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed - -import android.app.ActivityThread -import android.os.Binder -import android.os.Build -import com.github.kyuubiran.ezxhelper.utils.findField -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils - -object Utils4Xposed { - fun getPackageNameFromPackageSettings(packageSettings: Any): String? { - return runCatching { - findField(packageSettings::class.java, true) { - name == if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) "mName" else "name" - }.get(packageSettings) as? String - }.getOrNull() - } - - fun getPackageManager() = ActivityThread.currentActivityThread().application.packageManager!! - - fun getCallingApps(service: HMAService): Array { - return getCallingApps(service, Binder.getCallingUid()) - } - - fun getCallingApps(service: HMAService, callingUid: Int): Array { - if (callingUid == Constants.UID_SYSTEM) return arrayOf() - return Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: arrayOf() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt deleted file mode 100644 index 8a2cb8fc2..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt +++ /dev/null @@ -1,68 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed - -import android.content.pm.IPackageManager -import com.github.kyuubiran.ezxhelper.init.EzXHelperInit -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.IXposedHookLoadPackage -import de.robv.android.xposed.IXposedHookZygoteInit -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.callbacks.XC_LoadPackage -import icu.nullptr.hidemyapplist.common.Constants -import kotlin.concurrent.thread - -private const val TAG = "HMA-XposedEntry" - -@Suppress("unused") -class XposedEntry : IXposedHookZygoteInit, IXposedHookLoadPackage { - var targetsLeft = mutableListOf("package", "package_native") - var targetStorage = mutableMapOf() - - override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { - EzXHelperInit.initZygote(startupParam) - } - - override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { - if (lpparam.packageName == Constants.ANDROID_PACKAGE_NAME) { - EzXHelperInit.initHandleLoadPackage(lpparam) - logI(TAG, "Hook entry") - - var serviceManagerHook: XC_MethodHook.Unhook? = null - serviceManagerHook = findMethod("android.os.ServiceManager") { - name == "addService" - }.hookBefore { param -> - val name = param.args[0] as String - if (targetsLeft.contains(name)) { - when (name) { - "package", "package_native" -> { - targetStorage[name] = param.args[1] - targetsLeft.remove(name) - } - else -> { - // skip if there is no package_native available - if (targetStorage.containsKey("package")) { - targetsLeft.remove("package_native") - } - } - } - } - - if (targetsLeft.isEmpty()) { - serviceManagerHook?.unhook() - val pms = targetStorage["package"] as IPackageManager - val pmn = targetStorage["package_native"] - logD(TAG, "Got pms: $pms, $pmn") - thread { - runCatching { - UserService.register(pms, pmn) - targetStorage.clear() - logI(TAG, "User service started") - }.onFailure { - logE(TAG, "System service crashed", it) - } - } - } - } - } - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt deleted file mode 100644 index 3ce2d6e0e..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt +++ /dev/null @@ -1,80 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.accessibilityservice.AccessibilityServiceInfo -import android.content.pm.ParceledListSlice -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACCESSIBILITY_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI - -// Big credits: https://github.com/Nitsuya/DoNotTryAccessibility/blob/main/app/src/main/java/io/github/nitsuya/donottryaccessibility/hook/AndroidFrameworkHooker.kt -class AccessibilityHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "AccessibilityHook" - } - - private val hookList = mutableSetOf() - - override fun load() { - logI(TAG, "Load hook") - - hookList += findMethod(ACCESSIBILITY_SERVICE_CLASS) { - name == "getInstalledAccessibilityServiceList" - }.hookBefore { param -> hookedMethod(param, true) } - - hookList += findMethod(ACCESSIBILITY_SERVICE_CLASS) { - name == "getEnabledAccessibilityServiceList" - }.hookBefore { param -> hookedMethod(param, false) } - - hookList += findMethod(ACCESSIBILITY_SERVICE_CLASS) { - name == "addClient" - }.hookBefore { param -> - val callingApps = Utils4Xposed.getCallingApps(service) - if (callingApps.isEmpty()) return@hookBefore - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - param.result = 0L - // service.increasePMFilterCount(caller) - } - } - } - - private fun callerIsSpoofed(caller: String) = - service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) - - private fun hookedMethod(param: XC_MethodHook.MethodHookParam, returnParcel: Boolean) { - try { - val callingApps = Utils4Xposed.getCallingApps(service) - if (callingApps.isEmpty()) return - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - val returnedList = java.util.ArrayList() - - logD(TAG, "@${param.method.name} returned empty list for ${callingApps.contentToString()}") - - param.result = if (returnParcel) { - ParceledListSlice(returnedList) - } else { - returnedList - } - - // service.increasePMFilterCount(caller) - } - } catch (e: Throwable) { - logE(TAG, "Fatal error occurred, ignore hooks", e) - } - } - - override fun unload() { - hookList.forEach(XC_MethodHook.Unhook::unhook) - hookList.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt deleted file mode 100644 index 87ecfceb7..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt +++ /dev/null @@ -1,156 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.Intent -import android.content.pm.ResolveInfo -import android.os.Build -import com.github.kyuubiran.ezxhelper.init.InitFields -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedHelpers.findClass -import de.robv.android.xposed.XposedHelpers.getObjectField -import de.robv.android.xposed.XposedHelpers.getStaticIntField -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACTIVITY_STACK_SUPERVISOR_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACTIVITY_STARTER_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACTIVITY_TASK_SUPERVISOR_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.COMPUTER_ENGINE_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI -import icu.nullptr.hidemyapplist.xposed.logV - -class ActivityHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "ActivityHook" - private val fakeReturnCode by lazy { - getStaticIntField( - findClass( - "android.app.ActivityManager", - InitFields.ezXClassLoader - ), - "START_CLASS_NOT_FOUND" - ) - } - } - - private val hooks = mutableListOf() - - override fun load() { - logI(TAG, "Load hook") - - hooks += findMethod(ACTIVITY_STARTER_CLASS) { - name == "execute" - }.hookBefore { param -> - runCatching { - val request = getObjectField(param.thisObject, "mRequest") - val caller = getObjectField(request, "callingPackage") as String? - val intent = getObjectField(request, "intent") as Intent? - val targetApp = intent?.component?.packageName - - if (service.shouldHideActivityLaunch(caller, targetApp)) { - logD( - TAG, - "@executeRequest: insecure query from $caller, target: ${intent?.component}" - ) - param.result = fakeReturnCode - service.increaseALFilterCount(caller) - } - }.onFailure { - logE(TAG, "Fatal error occurred, ignore hook\n", it) - // unload() - } - } - - findMethodOrNull(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - ACTIVITY_TASK_SUPERVISOR_CLASS - } else { - ACTIVITY_STACK_SUPERVISOR_CLASS - }) { - name == "checkStartAnyActivityPermission" - }?.hookAfter { param -> - var throwable = param.throwable - - while (throwable != null) { - val newTrace = throwable.stackTrace.filter { item -> - !Utils.containsMultiple( - item.className, - "HookBridge", - "LSPHooker", - "LSPosed", - ) - } - - if (newTrace.size != throwable.stackTrace.size) { - throwable.stackTrace = newTrace.toTypedArray() - - val callingUid = param.args.lastOrNull { it is Int } as Int? - - logD(TAG, "@checkStartAnyActivityPermission: ${throwable.stackTrace.size - newTrace.size} remnants cleared for $callingUid!") - - service.increaseALFilterCount(callingUid) - } - - throwable = throwable.cause - } - }?.let { - hooks += it - logD(TAG, "Loaded ${it.hookedMethod.name} hook from ${it.hookedMethod.declaringClass}!") - } - - if (!Utils.isSamsung()) { - hooks += findMethod( - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - COMPUTER_ENGINE_CLASS - } else { - PACKAGE_MANAGER_SERVICE_CLASS - }, - findSuper = Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU, - ) { - name == "applyPostResolutionFilter" - }.hookBefore { param -> - @Suppress("UNCHECKED_CAST") // I know what I do - val list = param.args.first() as List? - if (list.isNullOrEmpty()) return@hookBefore - - val callingUid = param.args.first { it is Int } as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller != null) { - logV(TAG, "@${param.method.name}: $caller requested a resolve info") - - val filteredList = list.filter { resolveInfo -> - val targetApp = Utils.getPackageNameFromResolveInfo(resolveInfo) - - logV(TAG, "@${param.method.name}: Checking $targetApp for $caller") - - (!service.shouldHideActivityLaunch(caller, targetApp)).apply { - if (!this) { - logD(TAG, "@${param.method.name}: Filtered $targetApp from $caller") - } - } - } - - if (filteredList.size != list.size) { - param.args[0] = filteredList.toList() - - service.increasePMFilterCount(caller) - } - } - } - } - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt deleted file mode 100644 index 10e4d0630..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt +++ /dev/null @@ -1,220 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.os.Build -import android.os.SystemProperties -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedHelpers -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.XposedConstants.STORAGE_MANAGER_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI -import org.frknkrc44.hma_oss.common.BuildConfig - -@RequiresApi(Build.VERSION_CODES.R) -class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { - - companion object { - private const val TAG = "AppDataIsolationHook" - private const val APPDATA_ISOLATION_ENABLED = "mAppDataIsolationEnabled" - private const val VOLD_APPDATA_ISOLATION_ENABLED = "mVoldAppDataIsolationEnabled" - private const val FUSE_PROP = "persist.sys.fuse" - } - - private val hooks = mutableListOf() - private var voldHookSkipped = false - - override fun load() { - if (!(service.config.altAppDataIsolation || service.config.altVoldAppDataIsolation)) return - logI(TAG, "Load hook") - - findMethodOrNull( - "com.android.server.am.ProcessList" - ) { - name == "startProcess" - }?.hookBefore { param -> - if (service.config.altAppDataIsolation) { - val isEnabled = XposedHelpers.getBooleanField( - param.thisObject, - APPDATA_ISOLATION_ENABLED - ) - - if (!isEnabled) { - XposedHelpers.setBooleanField( - param.thisObject, - APPDATA_ISOLATION_ENABLED, - true - ) - - logI(TAG, "ProcessList - App data isolation is forced") - } - } - - if (service.config.altVoldAppDataIsolation && !voldHookSkipped) { - val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) - - if (!fuseEnabled) { - voldHookSkipped = true - logE(TAG, "ProcessList - FUSE storage is not enabled, skip vold hook") - } else { - val isolationEnabled = XposedHelpers.getBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED - ) - - if (!isolationEnabled) { - XposedHelpers.setBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED, - true - ) - - logI(TAG, "ProcessList - Vold app data isolation is forced") - } - } - } - }?.let { - hooks += it - } - - findMethodOrNull( - "com.android.server.am.ProcessList" - ) { - name == "needsStorageDataIsolation" - }?.hookAfter { param -> - if (service.config.altVoldAppDataIsolation) { - val app = param.args.find { it.javaClass.simpleName == "ProcessRecord" } - val uid = XposedHelpers.getIntField(app, "uid") - val processName = runCatching { - XposedHelpers.getObjectField(app, "processName") - }.getOrDefault("") - val mountNode = runCatching { - XposedHelpers.getIntField(app, "mMountMode") - }.getOrDefault(0) - val isolated = runCatching { - XposedHelpers.getBooleanField(app, "isolated") - }.getOrDefault(false) - val appZygote = runCatching { - XposedHelpers.getBooleanField(app, "appZygote") - }.getOrDefault(false) - - val apps = Utils.binderLocalScope { - service.pms.getPackagesForUid(uid) - } ?: return@hookAfter - - logD( - TAG, - "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" - ) - - // Do not isolate this module for safety - if (apps.contains(BuildConfig.APP_PACKAGE_NAME)) { - param.result = false - return@hookAfter - } - - if (apps.any { service.isAppDataIsolationExcluded(it) }) { - param.result = false - } - - if (service.config.skipSystemAppDataIsolation) { - val isSystemApp = service.systemApps.any { apps.contains(it) } - logD( - TAG, - "@needsStorageDataIsolation $uid and ${apps.contentToString()} - isSystemApp: $isSystemApp" - ) - - if (isSystemApp) { - param.result = false - return@hookAfter - } - } - } - }?.let { - hooks += it - } - - findMethodOrNull(STORAGE_MANAGER_SERVICE_CLASS) { - name == "onVolumeStateChangedLocked" - }?.hookBefore { param -> - runCatching { - if (service.config.altVoldAppDataIsolation) { - val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) - - if (!fuseEnabled) { - logE(TAG, "StorageManagerService - FUSE storage is not enabled, disable hooks") - unload() - return@hookBefore - } - - val isolationEnabled = XposedHelpers.getBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED - ) - - if (!isolationEnabled) { - XposedHelpers.setBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED, - true - ) - - logI(TAG, "StorageManagerService - Vold app data isolation is forced") - } - } - }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) - unload() - } - }?.let { - hooks += it - } - - findMethodOrNull(STORAGE_MANAGER_SERVICE_CLASS) { - name == "remountAppStorageDirs" - }?.hookBefore { param -> - if (service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { - @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - val pidPkgMap = param.args[0] as java.util.Map<*, *> - val userId = param.args[1] as Int - - val keysToRemove = mutableSetOf() - - for (entry in pidPkgMap.entrySet()) { - val pid = entry.key - val packageName = entry.value as String - - val apps = Utils.binderLocalScope { - val uid = Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) - service.pms.getPackagesForUid(uid) - } ?: continue - - for (app in apps) { - if (app in service.systemApps || app == BuildConfig.APP_PACKAGE_NAME) { - logD( - TAG, - "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" - ) - keysToRemove += pid - break - } - } - } - - keysToRemove.forEach { pidPkgMap.remove(it) } - } - }?.let { - hooks += it - } - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt deleted file mode 100644 index e61264108..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt +++ /dev/null @@ -1,172 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.AttributionSource -import android.database.Cursor -import android.database.MatrixCursor -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.provider.Settings -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.CONTENT_PROVIDER_TRANSPORT_CLASS -import icu.nullptr.hidemyapplist.xposed.logD - -class ContentProviderHook(private val service: HMAService): IFrameworkHook { - companion object { - private const val TAG = "ContentProviderHook" - private val NV_PAIR = arrayOf("name", "value") - } - - private val hooks = mutableListOf() - - @Suppress("UNCHECKED_CAST") - override fun load() { - hooks += findMethod(CONTENT_PROVIDER_TRANSPORT_CLASS) { - name == "query" - }.hookAfter { param -> - val callingApps = getCallingPackages(param) - - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller == null) return@hookAfter - - val uri = param.args[1] as Uri? - val projection = param.args[2] as Array? - val args = param.args[3] as Bundle? - - if (uri?.authority != "settings") return@hookAfter - - val segments = uri.pathSegments - if (segments.isEmpty()) return@hookAfter - - logD(TAG, "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args") - - val database = segments[0] - - if (segments.size >= 2) { - val name = segments[1] - - logD(TAG, "@spoofSettings QUERY received caller: $caller, database: $database, name: $name") - - val replacement = service.getSpoofedSetting(caller, name, database) - if (replacement != null) { - logD(TAG, "@spoofSettings QUERY $name in $database replaced for $caller") - param.result = MatrixCursor(arrayOf("name", "value"), 1).apply { - addRow(arrayOf(replacement.name, replacement.value)) - } - - service.increaseSettingsFilterCount(caller) - } - } else { - logD(TAG, "@spoofSettings LIST_QUERY received caller: $caller, database: $database") - - val result = param.result as Cursor? ?: return@hookAfter - - val columns = mutableMapOf>().apply { - for (i in 0 ..< result.columnCount) { - put(result.getColumnName(i), mutableListOf()) - } - } - - logD(TAG, "@spoofSetting LIST_QUERY columns: ${columns.keys}") - - val keyColumn = columns["name"] - val valueColumn = columns["value"] - - if (keyColumn == null || valueColumn == null) { - logD(TAG, "@spoofSettings LIST_QUERY invalid query: $caller ($keyColumn, $valueColumn)") - return@hookAfter - } - - while (result.moveToNext()) { - val name = result.getString(columns.keys.indexOf("name")) - keyColumn.add(name) - - val replacement = service.getSpoofedSetting(caller, name, database) - val value = if (replacement != null) { - logD(TAG, "@spoofSettings QUERY $name in $database replaced for $caller") - - service.increaseSettingsFilterCount(caller) - - replacement.value - } else { - result.getString(columns.keys.indexOf("value")) - } - - valueColumn.add(value) - - if (columns.keys.size > 2) { - for (otherCol in columns.keys.filter { it !in NV_PAIR }) { - val other = result.getString(columns.keys.indexOf(otherCol)) - - columns[otherCol]!!.add(other) - } - } - } - - param.result = MatrixCursor(columns.keys.toTypedArray(), columns.size).apply { - val size = columns.values.first().size - for (i in 0 ..< size) { - val innerList = mutableListOf() - - columns.values.forEach { colVal -> - innerList.add(colVal[i]) - } - - addRow(innerList) - } - } - } - } - - // Credit: https://github.com/Nitsuya/DoNotTryAccessibility/blob/main/app/src/main/java/io/github/nitsuya/donottryaccessibility/hook/AndroidFrameworkHooker.kt - hooks += findMethod(CONTENT_PROVIDER_TRANSPORT_CLASS) { - name == "call" - }.hookBefore { param -> - val callingApps = getCallingPackages(param) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller == null) return@hookBefore - - val method = param.args[2] as String? - val name = param.args[3] as String? - - logD(TAG, "@spoofSettings CALL received caller: ${callingApps.contentToString()}, method: $method, name: $name") - - when (method) { - "GET_global", "GET_secure", "GET_system" -> { - val database = method.substring(method.indexOf('_') + 1) - val replacement = service.getSpoofedSetting(caller, name, database) - if (replacement != null) { - logD(TAG, "@spoofSettings CALL $name in $database replaced for $caller") - param.result = Bundle().apply { - putString(Settings.NameValueTable.VALUE, replacement.value) - putInt("_generation_index", -1) - } - - service.increaseSettingsFilterCount(caller) - } - } - } - } - } - - private fun getCallingPackages(param: XC_MethodHook.MethodHookParam) = try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val attrSource = param.args.first() as AttributionSource - arrayOf(attrSource.packageName) - } else { - arrayOf(param.args.first() as String) - } - } catch (_: Throwable) { - Utils4Xposed.getCallingApps(service) - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/IFrameworkHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/IFrameworkHook.kt deleted file mode 100644 index cbea16b2d..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/IFrameworkHook.kt +++ /dev/null @@ -1,8 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -interface IFrameworkHook { - - fun load() - fun unload() - fun onConfigChanged() {} -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt deleted file mode 100644 index f8d45dbe7..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt +++ /dev/null @@ -1,190 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.ComponentName -import android.os.Build -import android.provider.Settings -import android.view.inputmethod.InputMethodInfo -import android.view.inputmethod.InputMethodSubtype -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.common.settings_presets.InputMethodPreset -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.IMM_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI -import java.util.Collections - -class ImmHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "ImmHook" - } - - private val hooks = mutableListOf() - - // TODO: Find a method to get settings activity - fun getFakeInputMethodInfo(packageName: String): InputMethodInfo { - val defaultInputMethod = service.getSpoofedSetting( - packageName, - Settings.Secure.DEFAULT_INPUT_METHOD, - Constants.SETTINGS_SECURE, - ) - - if (defaultInputMethod?.value != null) { - try { - val component = ComponentName.unflattenFromString(defaultInputMethod.value!!)!! - logD(TAG, "Package component: \"$component\"") - - val pkgManager = Utils4Xposed.getPackageManager() - val kbdPackage = Utils.binderLocalScope { - pkgManager.getApplicationInfo(component.packageName, 0) - } - - return InputMethodInfo( - component.packageName, - component.className, - kbdPackage.loadLabel(pkgManager), - null, - ) - } catch (e: Throwable) { - logE(TAG, e.message ?: "", e) - } - } - - return InputMethodInfo( - "com.google.android.inputmethod.latin", - "com.android.inputmethod.latin.LatinIME", - "Gboard", - null, - ) - } - - override fun load() { - logI(TAG, "Load hook") - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getCurrentInputMethodInfoAsUser" - }?.hookBefore { param -> - val callingApps = Utils4Xposed.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG, "@${param.method.name} spoofed input method for $caller") - - param.result = getFakeInputMethodInfo(caller) - service.increaseSettingsFilterCount(caller) - } - }?.let { - logD(TAG, "@${it.hookedMethod.name} is hooked!") - hooks += it - } - } - - (findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getInputMethodListInternal" - } ?: findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getInputMethodList" && returnType.simpleName != "InputMethodInfoSafeList" - })?.hookBefore { param -> - listHook(param) - }?.let { - logD(TAG, "@${it.hookedMethod.name} is hooked!") - hooks += it - } - - (findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodListInternal" - } ?: findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodList" && returnType.simpleName != "InputMethodInfoSafeList" - })?.hookBefore { param -> - listHook(param) - }?.let { - logD(TAG, "@${it.hookedMethod.name} is hooked!") - hooks += it - } - - findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getCurrentInputMethodSubtype" - }?.hookBefore { param -> - subtypeHook(param) - }?.let { - logD(TAG, "@${it.hookedMethod.name} is hooked!") - hooks += it - } - - findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getLastInputMethodSubtype" - }?.hookBefore { param -> - subtypeHook(param) - }?.let { - logD(TAG, "@${it.hookedMethod.name} is hooked!") - hooks += it - } - - (findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodSubtypeListInternal" - } ?: findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodSubtypeList" - })?.hookBefore { param -> - subtypeListHook(param) - }?.let { - logD(TAG, "@${it.hookedMethod.name} is hooked!") - hooks += it - } - } - - private fun listHook(param: XC_MethodHook.MethodHookParam) { - val callingApps = if (param.method.name.endsWith("Internal")) { - val callingUid = param.args.last() as Int - Utils4Xposed.getCallingApps(service, callingUid) - } else { - Utils4Xposed.getCallingApps(service) - } - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG, "@${param.method.name} spoofed input method for $caller") - - param.result = listOf(getFakeInputMethodInfo(caller)) - service.increaseSettingsFilterCount(caller) - } - } - - private fun subtypeHook(param: XC_MethodHook.MethodHookParam) { - val callingApps = Utils4Xposed.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG, "@${param.method.name} spoofed input method subtype for ${callingApps.contentToString()}") - - // TODO: Find a method to get exact value for spoofed input method - param.result = null - service.increaseSettingsFilterCount(caller) - } - } - - private fun subtypeListHook(param: XC_MethodHook.MethodHookParam) { - val callingApps = Utils4Xposed.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG, "@${param.method.name} spoofed input method subtype for ${callingApps.contentToString()}") - - // TODO: Find a method to get exact list for spoofed input method - param.result = Collections.emptyList() - service.increaseSettingsFilterCount(caller) - } - } - - private fun callerIsSpoofed(caller: String) = - service.getEnabledSettingsPresets(caller).contains(InputMethodPreset.NAME) - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt deleted file mode 100644 index 2ce2ae7d0..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt +++ /dev/null @@ -1,107 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI -import icu.nullptr.hidemyapplist.xposed.logV - -class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget29" - - // not required until SDK 30 - override val fakeSystemPackageInstallSourceInfo = null - override val fakeUserPackageInstallSourceInfo = null - - @Suppress("UNCHECKED_CAST") - override fun load() { - logI(TAG, "Load hook") - - hooks += findMethod(service.pms::class.java, findSuper = true) { - name == "filterAppAccessLPr" && parameterCount == 5 - }.hookBefore { param -> - runCatching { - val callingUid = param.args[1] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val packageSettings = param.args[0] ?: return@hookBefore - val targetApp = Utils4Xposed.getPackageNameFromPackageSettings(packageSettings) - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@filterAppAccessLPr caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: return@hookBefore - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@filterAppAccessLPr query from $caller") - logD(TAG, "@filterAppAccessLPr caller: $callingUid $caller, target: $targetApp") - } - }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) - unload() - } - } - - hooks += findMethod(PACKAGE_MANAGER_SERVICE_CLASS) { - name == "getPackageInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.first() as String? ?: return@hookBefore - val callingUid = param.args[3] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - hooks += findMethod(PACKAGE_MANAGER_SERVICE_CLASS) { - name == "getApplicationInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.first() as String? ?: return@hookBefore - val callingUid = param.args[2] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt deleted file mode 100644 index 089e94a61..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt +++ /dev/null @@ -1,159 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.os.Binder -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI -import icu.nullptr.hidemyapplist.xposed.logV - -@RequiresApi(Build.VERSION_CODES.R) -class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget30" - - override val fakeSystemPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - null, - null, - null, - null, - ) - } - - override val fakeUserPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - VENDING_PACKAGE_NAME, - psPackageInfo?.signingInfo, - VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, - ) - } - - override fun load() { - logI(TAG, "Load hook") - - findMethodOrNull(PACKAGE_MANAGER_SERVICE_CLASS, findSuper = true) { - name == "getPackageSetting" - }?.hookBefore { param -> - val targetApp = param.args[0] as String - val callingUid = Binder.getCallingUid() - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@getPackageSetting - PkgMgr cache: insecure query from $callingUid to $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@getPackageSetting - PkgMgr: insecure query from $caller to $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - }?.let { - hooks += it - } - - hooks += findMethod(APPS_FILTER_CLASS) { - name == "shouldFilterApplication" - }.hookBefore { param -> - runCatching { - val callingUid = param.args[0] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Xposed.getPackageNameFromPackageSettings(param.args[2]) - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: return@hookBefore - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") - logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") - } - }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) - unload() - } - } - - hooks += findMethod(PACKAGE_MANAGER_SERVICE_CLASS) { - name == "getPackageInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.first() as String? ?: return@hookBefore - val callingUid = param.args[3] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - hooks += findMethod(PACKAGE_MANAGER_SERVICE_CLASS) { - name == "getApplicationInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.first() as String? ?: return@hookBefore - val callingUid = param.args[2] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt deleted file mode 100644 index 9a24bbdda..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt +++ /dev/null @@ -1,184 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.os.Binder -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PMS_COMPUTER_TRACKER_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI -import icu.nullptr.hidemyapplist.xposed.logV - -@RequiresApi(Build.VERSION_CODES.S) -class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget31" - - override val fakeSystemPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - null, - null, - null, - null, - ) - } - - override val fakeUserPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - VENDING_PACKAGE_NAME, - psPackageInfo?.signingInfo, - VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, - ) - } - - override fun load() { - logI(TAG, "Load hook") - - findMethodOrNull(PMS_COMPUTER_TRACKER_CLASS) { - name == "getPackageSetting" - }?.hookBefore { param -> - val targetApp = param.args[0] as String - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@getPackageSetting - Computer cache: insecure query from $callingUid to $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@getPackageSetting - Computer: insecure query from $caller to $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - }?.let { - hooks += it - } - - findMethodOrNull(PMS_COMPUTER_TRACKER_CLASS) { - name == "getPackageSettingInternal" - }?.hookBefore { param -> - val targetApp = param.args[0] as String - val callingUid = param.args[1] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@getPackageSettingInternal - Computer cache: insecure query from $callingUid to $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@getPackageSettingInternal - Computer: insecure query from $caller to $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - }?.let { - hooks += it - } - - hooks += findMethod(APPS_FILTER_CLASS) { - name == "shouldFilterApplication" - }.hookBefore { param -> - runCatching { - val callingUid = param.args[0] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Xposed.getPackageNameFromPackageSettings(param.args[2]) - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: return@hookBefore - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") - logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") - } - }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) - unload() - } - } - - hooks += findMethod(PMS_COMPUTER_TRACKER_CLASS) { - name == "getPackageInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.first() as String? ?: return@hookBefore - val callingUid = param.args[3] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - hooks += findMethod(PMS_COMPUTER_TRACKER_CLASS) { - name == "getApplicationInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.first() as String? ?: return@hookBefore - val callingUid = param.args[2] as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt deleted file mode 100644 index 4461293ae..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt +++ /dev/null @@ -1,261 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.pm.PackageManager -import android.os.Binder -import android.os.Build -import android.os.UserHandle -import android.util.ArrayMap -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedHelpers -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.COMPUTER_ENGINE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logV -import java.util.concurrent.atomic.AtomicReference - -abstract class PmsHookTargetBase(protected val service: HMAService) : IFrameworkHook { - - @Suppress("PropertyName") - abstract val TAG: String - - protected val hooks = mutableListOf() - protected var lastFilteredApp: AtomicReference = AtomicReference(null) - - protected val psPackageInfo by lazy { - try { - Utils.getPackageInfoCompat( - service.pms, - VENDING_PACKAGE_NAME, - PackageManager.GET_SIGNING_CERTIFICATES.toLong(), - 0 - ) - } catch (_: Throwable) { - null - } - } - - abstract val fakeSystemPackageInstallSourceInfo: Any? - abstract val fakeUserPackageInstallSourceInfo: Any? - - override fun load() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "getPackageStates" - }.hookAfter { param -> - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookAfter - - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller != null) { - logD(TAG, "@getPackageStates: incoming query from $caller") - - val result = param.result as ArrayMap<*, *> - val markedToRemove = mutableListOf() - - for (pair in result.entries) { - val value = pair.value - val packageName = XposedHelpers.callMethod(value, "getPackageName") as String - if (service.shouldHide(caller, packageName)) { - markedToRemove.add(pair.key) - } - } - - if (markedToRemove.isNotEmpty()) { - val copyResult = ArrayMap(result) - copyResult.removeAll(markedToRemove) - logD(TAG, "@getPackageStates: removed ${markedToRemove.size} entries from $caller") - param.result = copyResult - service.increasePMFilterCount(caller) - } - } - } - - findMethodOrNull(COMPUTER_ENGINE_CLASS) { - name == "addPackageHoldingPermissions" - }?.hookBefore { param -> - val callingUid = Binder.getCallingUid() - val packageState = param.args[1] ?: return@hookBefore - val targetApp = XposedHelpers.callMethod(packageState, "getPackageName") as String? ?: return@hookBefore - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@addPackageHoldingPermissions caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@addPackageHoldingPermissions caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - }?.let { - logD(TAG, "CE addPackageHoldingPermissions is hooked!") - hooks += it - } - - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "isCallerInstallerOfRecord" - }.hookBefore { param -> - val pkg = param.args.first() - val query = XposedHelpers.callMethod(pkg, "getPackageName") as String - - val callingUid = param.args.last() as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = callingUid == psPackageInfo?.applicationInfo?.uid - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = false - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - } - - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "getPackageInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.firstOrNull { it is String } as? String ?: return@hookBefore - val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "getApplicationInfoInternal" - }.hookBefore { param -> - val targetApp = param.args.firstOrNull { it is String } as? String ?: return@hookBefore - val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.method.name} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.method.name} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.method.name} caller: $callingUid $caller, target: $targetApp") - param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - } - - if (service.pmn != null) { - findMethodOrNull(service.pmn::class.java, findSuper = true) { - name == "getInstallerForPackage" - }?.hookBefore { param -> - val query = param.args[0] as String? - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = "preload" - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - }?.let { - logD(TAG, "PMN getInstallerForPackage is hooked!") - hooks.add(it) - } - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - findMethodOrNull(service.pms::class.java, findSuper = true) { - name == "getInstallSourceInfo" - }?.hookBefore { param -> - val query = param.args[0] as String? - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = fakeUserPackageInstallSourceInfo - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = fakeSystemPackageInstallSourceInfo - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - }?.let { - hooks.add(it) - } - } - - hooks += findMethod(service.pms::class.java, findSuper = true) { - name == "getInstallerPackageName" - }.hookBefore { param -> - val query = param.args[0] as String? - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - } - } - - final override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt deleted file mode 100644 index 268be0b7f..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt +++ /dev/null @@ -1,57 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.Intent -import android.os.Build -import android.os.Bundle -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS - -class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { - private var hook: XC_MethodHook.Unhook? = null - - override fun load() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - try { - hook = findMethod("com.android.server.pm.BroadcastHelper") { - name == "sendPackageBroadcastAndNotify" - }.hookBefore { param -> - service.handlePackageEvent( - param.args[0] as String?, - param.args[1] as String?, - param.args[2] as Bundle?, - ) - } - } catch (_: Throwable) { - hook = findMethod("com.android.internal.content.PackageMonitor") { - name == "onReceive" - }.hookBefore { param -> - val intent = param.args[1] as Intent? ?: return@hookBefore - - service.handlePackageEvent( - intent.action, - intent.data?.encodedSchemeSpecificPart, - intent.extras, - ) - } - } - } else { - hook = findMethod(PACKAGE_MANAGER_SERVICE_CLASS) { - name == "sendPackageBroadcast" - }.hookBefore { param -> - service.handlePackageEvent( - param.args[0] as String?, - param.args[1] as String?, - param.args[2] as Bundle?, - ) - } - } - } - - override fun unload() { - hook?.unhook() - hook = null - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt deleted file mode 100644 index 03fe00b1e..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt +++ /dev/null @@ -1,51 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ZYGOTE_PROCESS_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logV - -class ZygoteHook(private val service: HMAService): IFrameworkHook { - companion object { - private const val TAG = "ZygoteHook" - } - - private val hooks = mutableListOf() - - override fun load() { - findMethodOrNull(ZYGOTE_PROCESS_CLASS) { - name == "start" - }?.hookBefore { param -> - logV(TAG, "@startZygoteProcess: Starting ${param.args.contentToString()}") - - // ignore if the GIDs array is null - val gIDsIndex = param.args.indexOfFirst { it is IntArray } - if (gIDsIndex < 0) return@hookBefore - - val caller = param.args.lastOrNull { it is String } as String? ?: return@hookBefore - var perms = service.getRestrictedZygotePermissions(caller) ?: return@hookBefore - if (perms.isNotEmpty()) { - val gIDs = param.args[gIDsIndex] as IntArray - - // add more security, reject if not available in GID_PAIRS - perms = perms.filter { Constants.GID_PAIRS.containsValue(it) } - - logD(TAG, "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now") - param.args[gIDsIndex] = gIDs.filter { it !in perms }.toIntArray() - service.increaseOthersFilterCount(caller) - } - }?.let { - logD(TAG, "Loaded ZygoteProcess start hook!") - hooks += it - } - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/zygote/.gitignore b/zygote/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/zygote/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/zygote/build.gradle.kts b/zygote/build.gradle.kts new file mode 100644 index 000000000..70f10ccc5 --- /dev/null +++ b/zygote/build.gradle.kts @@ -0,0 +1,42 @@ +import com.v7878.zygisk.gradle.ZygoteLoader + +plugins { + alias(libs.plugins.agp.app) + alias(libs.plugins.kotlin) + alias(libs.plugins.com.github.aerathstuff.zygoteloader) +} + +val appPackageName: String by rootProject.extra + +android { + namespace = "$appPackageName.zygote" + + defaultConfig { + applicationId = namespace + } +} + +zygisk { + // inject to system_server + packages(ZygoteLoader.PACKAGE_SYSTEM_SERVER) + + // module properties + id = "hma_oss_zygisk" + name = "HMA-OSS Zygisk" + author = "frknkrc44" + description = "A Zygisk backend for HMA-OSS" + entrypoint = "org.frknkrc44.hma_oss.zygote.ZygoteEntry" + archiveName = "${rootProject.name}-ZYGISK-${android.defaultConfig.versionName}" + isAddVariantToArchiveName = true +} + +dependencies { + implementation(projects.common) + + implementation(libs.androidx.annotation.jvm) + implementation(libs.io.github.vova7878.androidvmtools) + implementation(libs.io.github.vova7878.r8annotations) + implementation(libs.dev.rikka.hidden.compat) + + compileOnly(libs.dev.rikka.hidden.stub) +} \ No newline at end of file diff --git a/zygote/proguard-rules.pro b/zygote/proguard-rules.pro new file mode 100644 index 000000000..614ce8411 --- /dev/null +++ b/zygote/proguard-rules.pro @@ -0,0 +1,28 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-keep class org.frknkrc44.hma_oss.zygote.ZygoteEntry { main(); } +-dontwarn android.content.pm.IPackageManager +-dontwarn android.content.pm.ParceledListSlice +-dontwarn android.os.SystemProperties +-dontwarn com.v7878.r8.annotations.KeepCodeAttribute +-keep class org.frknkrc44.hma_oss.zygote.** \ No newline at end of file diff --git a/zygote/src/main/AndroidManifest.xml b/zygote/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8072ee00d --- /dev/null +++ b/zygote/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt new file mode 100644 index 000000000..645697141 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -0,0 +1,300 @@ +package org.frknkrc44.hma_oss.zygote + +import android.util.Log +import com.v7878.unsafe.Reflection +import com.v7878.unsafe.invoke.EmulatedStackFrame +import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX +import com.v7878.unsafe.invoke.Transformers +import com.v7878.vmtools.HookTransformer +import com.v7878.vmtools.Hooks +import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.ZygoteEntry.TAG +import java.lang.invoke.MethodHandle +import java.lang.reflect.Executable +import java.util.regex.Pattern +import java.util.stream.Stream + + +class BulkHooker private constructor() { + companion object { + val instance: BulkHooker by lazy { BulkHooker() } + } + + private val hooks: MutableMap> = + HashMap>() + + fun findHookElement(clazz: String, methodName: String) = hooks[clazz]?.first { + it.pattern == String.format("%s\\(.*\\).*", Pattern.quote(methodName)) + } + + private fun addPattern(clazz: String, pattern: String, hookFirst: Boolean, paramCount: Int, impl: HookTransformer) { + hooks.computeIfAbsent(clazz) { _ -> mutableListOf() } + .add(HookElement( + impl = impl, + pattern = pattern, + hookFirst = hookFirst, + paramCount = paramCount, + )) + } + + private fun addAll(clazz: String, methodName: String, hookFirst: Boolean, paramCount: Int, impl: HookTransformer) { + addPattern( + clazz, + String.format("%s\\(.*\\).*", Pattern.quote(methodName)), + hookFirst, + paramCount, + impl, + ) + } + + internal fun hookBefore( + clazz: String, + methodName: String, + dumpArgs: Boolean = true, + autoApply: Boolean = true, + hookFirst: Boolean = true, + paramCount: Int = -1, + hook: (param: HookParam) -> Unit, + ) { + addAll(clazz, methodName, hookFirst, paramCount) { original, frame -> + val args = if (dumpArgs) Utils4Zygote.dumpArgs(frame) else null + val value = ReturnValue() + + runCatching { + hook(HookParam(clazz, original, frame, methodName, args, value)) + }.onFailure { + logE(TAG, it.message ?: "Unknown error on hook", it) + } + + if (!value.replace) { + if (!dumpArgs) { + Transformers.invokeExact(original, frame) + } else { + value.value = original.invokeWithArguments(*args!!) + } + } + + if (value.replace && frame.type().returnType() != Void::class.java) { + frame.accessor().setValue(RETURN_VALUE_IDX, value.value) + } + } + + if (autoApply) { + applyHooks() + } + } + + internal fun hookAfter( + clazz: String, + methodName: String, + dumpArgs: Boolean = true, + autoApply: Boolean = true, + hookFirst: Boolean = true, + paramCount: Int = -1, + hook: (param: HookParam) -> Unit, + ) { + addAll(clazz, methodName, hookFirst, paramCount) { original, frame -> + var throwable: Throwable? = null + + runCatching { + Transformers.invokeExact(original, frame) + }.onFailure { + throwable = it + } + + val args = if (dumpArgs) Utils4Zygote.dumpArgs(frame) else null + val value = ReturnValue(if (throwable == null) { + frame.accessor().getValue(RETURN_VALUE_IDX) + } else null) + value.throwable = throwable + + runCatching { + hook(HookParam(clazz, original, frame, methodName, args, value)) + }.onFailure { + logE(TAG, it.message ?: "Unknown error on hook", it) + } + + if (throwable != null) { + throw throwable + } + + if (value.replace && frame.type().returnType() != Void::class.java) { + frame.accessor().setValue(RETURN_VALUE_IDX, value.value) + } + } + + if (autoApply) { + applyHooks() + } + } + + internal fun applyHooks(loader: ClassLoader? = SystemServerHook.classLoader) { + for (entry in hooks.entries) { + var curClazz: Class<*>? + try { + curClazz = Class.forName(entry.key, true, loader) + } catch (ex: ClassNotFoundException) { + Log.e(TAG, java.lang.String.format("Class %s not found", entry.key), ex) + continue + } + + fun apply(clazz: Class<*>?) { + val executables = Reflection.getHiddenExecutables(clazz).sortedWith { v1, v2 -> + v1.parameterCount.compareTo(v2.parameterCount) + }.toTypedArray() + for (element in entry.value) { + Stream.of(*executables) + .filter(Utils4Zygote.filter(element.pattern)) + .forEach { executable: Executable -> + if (element.paramCount != -1 && executable.parameterCount != element.paramCount) { + return@forEach + } + + if (!element.hookFirst || element.applyCount < 1) { + if (BuildConfig.DEBUG) { + logI(TAG, "Hooked: $executable") + } + val invoker = Hooks.hook( + executable, Hooks.EntryPointType.DIRECT, + element.impl, Hooks.EntryPointType.DIRECT + ) + + element.unhooks.add(Unhook(executable, invoker)) + element.applyCount++ + } + } + } + } + + while ( + curClazz != null && + entry.value.any { it.applyCount < 1 } && + curClazz.javaClass.simpleName != "Object" + ) { + apply(curClazz) + curClazz = curClazz.superclass + } + + // remove invalid entries + entry.value.removeIf { + (it.applyCount < 1).apply { + if (this@apply) { + logI(TAG, "Invalid hook removed: ${it.pattern}") + } + } + } + } + } + + fun unhook(element: HookElement) { + for (unhook in element.unhooks) { + unhook.unhook() + } + + element.unhooks.clear() + } + + fun unhookAll() { + // TODO: Not working yet, find a way to implement unhook properly + /* + for (entry in hooks.entries) { + for (element in entry.value) { + unhook(element) + } + } + + hooks.clear() + */ + } + + data class HookElement( + val impl: HookTransformer, + val unhooks: MutableList = mutableListOf(), + val pattern: String, + val hookFirst: Boolean, + val paramCount: Int = -1, + var applyCount: Int = 0, + ) + + class Unhook(private val backup: Executable, private val invoker: Executable) { + fun unhook() { + // TODO: Not working yet, find a way to implement unhook properly + Hooks.hookSwap( + backup, + Hooks.EntryPointType.DIRECT, + invoker, + Hooks.EntryPointType.DIRECT, + ) + } + } + + class ReturnValue(initialValue: Any? = null) { + var replace: Boolean = false + private set + + var value: Any? = initialValue + set(value) { + field = value + replace = true + } + + var throwable: Throwable? = null + } + + data class HookParam( + val clazz: String, + val original: MethodHandle, + val frame: EmulatedStackFrame, + val methodName: String, + + /** + * - `args[0] == thisObject` + * - `args[1:] == function args` + * + * Note that this variable is null when `dumpArgs == false` + */ + val args: Array?, + val returnValue: ReturnValue, + ) { + var result: Any? + get() = returnValue.value + set(newValue) { returnValue.value = newValue } + + /** + * Returns the first argument, can throw an exception when `dumpArgs == false` + */ + val thisObject get() = args?.first()!! + + var throwable: Throwable? + get() = returnValue.throwable + set(newValue) { returnValue.throwable = newValue } + + // -- BEGIN OF GENERATED FUNCTIONS -- + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as HookParam + + if (clazz != other.clazz) return false + if (original != other.original) return false + if (frame != other.frame) return false + if (methodName != other.methodName) return false + if (!args.contentEquals(other.args)) return false + if (returnValue != other.returnValue) return false + + return true + } + + override fun hashCode(): Int { + var result1 = clazz.hashCode() + result1 = 31 * result1 + original.hashCode() + result1 = 31 * result1 + frame.hashCode() + result1 = 31 * result1 + methodName.hashCode() + result1 = 31 * result1 + (args?.contentHashCode() ?: 0) + result1 = 31 * result1 + returnValue.hashCode() + return result1 + } + // -- END OF GENERATED FUNCTIONS -- + } +} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt similarity index 94% rename from xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index d60618e77..8a0b47314 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -1,4 +1,4 @@ -package icu.nullptr.hidemyapplist.xposed +package org.frknkrc44.hma_oss.zygote import android.content.Intent import android.content.pm.ApplicationInfo @@ -8,8 +8,6 @@ import android.os.Bundle import android.os.UserHandle import android.provider.Settings import android.util.Log -import com.github.kyuubiran.ezxhelper.utils.isStatic -import com.github.kyuubiran.ezxhelper.utils.removeIf import icu.nullptr.hidemyapplist.common.AppPresets import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.FilterHolder @@ -24,29 +22,30 @@ import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat import icu.nullptr.hidemyapplist.common.Utils.getInstalledPackagesCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageUidCompat +import icu.nullptr.hidemyapplist.common.Utils.removeIf import icu.nullptr.hidemyapplist.common.app_presets.DetectorAppsPreset import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem -import icu.nullptr.hidemyapplist.xposed.hook.AccessibilityHook -import icu.nullptr.hidemyapplist.xposed.hook.ActivityHook -import icu.nullptr.hidemyapplist.xposed.hook.AppDataIsolationHook -import icu.nullptr.hidemyapplist.xposed.hook.ContentProviderHook -import icu.nullptr.hidemyapplist.xposed.hook.IFrameworkHook -import icu.nullptr.hidemyapplist.xposed.hook.ImmHook -import icu.nullptr.hidemyapplist.xposed.hook.PlatformCompatHook -import icu.nullptr.hidemyapplist.xposed.hook.PmsHookTarget29 -import icu.nullptr.hidemyapplist.xposed.hook.PmsHookTarget30 -import icu.nullptr.hidemyapplist.xposed.hook.PmsHookTarget31 -import icu.nullptr.hidemyapplist.xposed.hook.PmsHookTarget33 -import icu.nullptr.hidemyapplist.xposed.hook.PmsHookTarget34 -import icu.nullptr.hidemyapplist.xposed.hook.PmsPackageEventsHook -import icu.nullptr.hidemyapplist.xposed.hook.ZygoteHook import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.hook.AccessibilityHook +import org.frknkrc44.hma_oss.zygote.hook.ActivityHook +import org.frknkrc44.hma_oss.zygote.hook.AppDataIsolationHook +import org.frknkrc44.hma_oss.zygote.hook.ContentProviderHook +import org.frknkrc44.hma_oss.zygote.hook.IFrameworkHook +import org.frknkrc44.hma_oss.zygote.hook.ImmHook +import org.frknkrc44.hma_oss.zygote.hook.PlatformCompatHook +import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget29 +import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget30 +import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget31 +import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget33 +import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget34 +import org.frknkrc44.hma_oss.zygote.hook.PmsPackageEventsHook +import org.frknkrc44.hma_oss.zygote.hook.ZygoteHook import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.UserManagerApis import java.io.File +import java.lang.reflect.Modifier import java.util.concurrent.ExecutorService import java.util.concurrent.Executors -import kotlin.concurrent.thread class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { @@ -96,9 +95,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logWithLevel(level, "AppPresets", msg) } - thread { - reloadPresets(false) - } + reloadPresets(false) } private fun searchDataDir() { @@ -250,9 +247,11 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { caller, amount, FilterHolder.FilterType.PACKAGE_MANAGER ) + /* fun increaseALFilterCount(callingUid: Int?, amount: Int = 1) = increaseFilterCount( callingUid, amount, FilterHolder.FilterType.ACTIVITY_LAUNCH ) + */ fun increaseALFilterCount(caller: String?, amount: Int = 1) = increaseFilterCount( caller, amount, FilterHolder.FilterType.ACTIVITY_LAUNCH @@ -441,6 +440,9 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun stopService(cleanEnv: Boolean) { + // It is an unimplemented method + if (true) return + logI(TAG, "Stop service") synchronized(loggerLock) { logcatAvailable = false @@ -448,6 +450,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { synchronized(configLock) { frameworkHooks.forEach(IFrameworkHook::unload) frameworkHooks.clear() + BulkHooker.instance.unhookAll() if (cleanEnv) { logI(TAG, "Clean runtime environment") File(dataDir).deleteRecursively() @@ -598,7 +601,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } val readableVariables = settingClass.declaredFields.mapNotNull { field -> - if (field.isStatic && field.type.simpleName == "String") field.get(null) as String else null + if (Modifier.isStatic(field.modifiers) && field.type.simpleName == "String") field.get(null) as String else null } return readableVariables.sorted().toTypedArray() diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Logcat.kt similarity index 90% rename from xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Logcat.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Logcat.kt index 8f9121e34..1ace7e7d2 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Logcat.kt @@ -1,7 +1,6 @@ -package icu.nullptr.hidemyapplist.xposed +package org.frknkrc44.hma_oss.zygote import android.util.Log -import de.robv.android.xposed.XposedBridge import org.frknkrc44.hma_oss.common.BuildConfig import java.text.SimpleDateFormat import java.util.Date @@ -27,12 +26,13 @@ fun logWithLevel(level: Int, tag: String, msg: String, cause: Throwable? = null) if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return if (level == Log.VERBOSE && !BuildConfig.DEBUG) return + val parsedLog = parseLog(level, tag, msg, cause) HMAService.instance?.executor?.execute { HMAService.instance?.addLog(parsedLog) - XposedBridge.log("[HMA-OSS] $parsedLog") - } ?: XposedBridge.log("[HMA-OSS] $parsedLog") + Log.println(Log.INFO, "HMA-OSS", parsedLog) + } ?: Log.println(Log.INFO, "HMA-OSS", parsedLog) } fun logV(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.VERBOSE, tag, msg, cause) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt new file mode 100644 index 000000000..2e1b4e7de --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt @@ -0,0 +1,72 @@ +package org.frknkrc44.hma_oss.zygote + +import android.annotation.SuppressLint +import android.content.pm.IPackageManager +import com.v7878.r8.annotations.DoNotShrink +import com.v7878.unsafe.invoke.EmulatedStackFrame +import com.v7878.unsafe.invoke.Transformers +import com.v7878.vmtools.Hooks +import org.frknkrc44.hma_oss.common.BuildConfig +import kotlin.concurrent.thread + +@SuppressLint("PrivateApi") +object SystemServerHook { + private const val TAG = "SystemServerHook" + private const val SYSTEM_SERVER: String = "com.android.server.SystemServer" + private const val RUNTIME_INIT: String = "com.android.internal.os.RuntimeInit" + + var classLoader: ClassLoader? = null + + @Throws(Throwable::class) + fun onSystemServer(loader: ClassLoader?) { + if (BuildConfig.DEBUG) { + logI(TAG, "loader: $loader") + } + + classLoader = loader + + thread { + val pms = Utils4Zygote.waitForService("package") as IPackageManager + val pmn = Utils4Zygote.waitForService("package_native") + logD(TAG, "Got pms: $pms, $pmn") + + runCatching { + UserService.register(pms, pmn) + logI(TAG, "User service started") + }.onFailure { + logE(TAG, "System service crashed", it) + } + } + } + + @Throws(Throwable::class) + private fun checkSystemServer(frame: EmulatedStackFrame) { + val accessor = frame.accessor() + if (SYSTEM_SERVER == accessor.getReference(0)) { + val loader: ClassLoader? = accessor.getReference(2) + onSystemServer(loader) + } + } + + @SuppressLint("PrivateApi") + @DoNotShrink + @Throws(Throwable::class) + @JvmStatic + fun init() { + val method = Utils4Zygote.findMethod( + RUNTIME_INIT, "findStaticMain", true, false, + String::class.java, Array::class.java, ClassLoader::class.java + ).apply { + Hooks.deoptimize(this@apply) + } + + Hooks.hook(method, Hooks.EntryPointType.CURRENT, { original, frame -> + try { + checkSystemServer(frame) + } catch (th: Throwable) { + logE(TAG, "An exception occurred while checkSystemServer", th) + } + Transformers.invokeExact(original, frame) + }, Hooks.EntryPointType.DIRECT) + } +} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt similarity index 75% rename from xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/UserService.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt index dcce98cac..0f27c6464 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt @@ -1,15 +1,13 @@ -package icu.nullptr.hidemyapplist.xposed +package org.frknkrc44.hma_oss.zygote -import android.app.ActivityManagerHidden import android.content.AttributionSource import android.content.pm.IPackageManager import android.os.Build import android.os.Bundle -import android.os.ServiceManager -import de.robv.android.xposed.XposedHelpers import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getStaticIntField import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.adapter.UidObserverAdapter @@ -69,34 +67,19 @@ object UserService { logD(TAG, "Client uid: $appUid") - waitActivityService() + Utils4Zygote.waitForService("activity") ActivityManagerApis.registerUidObserver( uidObserver, - ActivityManagerHidden.UID_OBSERVER_ACTIVE, - ActivityManagerHidden.PROCESS_STATE_TOP, + getActMgrField("UID_OBSERVER_ACTIVE"), + getActMgrField("PROCESS_STATE_TOP"), null ) logI(TAG, "Registered observer") } - private fun waitActivityService() { - // use the new Android method for 11+ - // but use the getService fallback if fails to run - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - try { - XposedHelpers.callStaticMethod( - ServiceManager::class.java, - "waitForService", - "activity" - ) - - return - } catch (_: Throwable) {} - } - - while (ServiceManager.getService("activity") == null) { - Thread.sleep(250) - } - } + private fun getActMgrField(name: String) = getStaticIntField( + "android.app.ActivityManager", + name, + ) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt new file mode 100644 index 000000000..c0941c5e0 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -0,0 +1,157 @@ +package org.frknkrc44.hma_oss.zygote + +import android.app.ActivityThread +import android.os.Binder +import android.os.Build +import android.os.IBinder +import android.os.ServiceManager +import com.v7878.unsafe.Reflection.getDeclaredField +import com.v7878.unsafe.Reflection.getDeclaredMethod +import com.v7878.unsafe.invoke.EmulatedStackFrame +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Utils +import java.lang.reflect.Constructor +import java.lang.reflect.Executable +import java.lang.reflect.Method +import java.lang.reflect.Modifier +import java.util.function.Predicate +import java.util.regex.Pattern + + +object Utils4Zygote { + fun dumpArgs(frame: EmulatedStackFrame): Array { + return mutableListOf().let { + for (i in 0 ..< frame.type().parameterCount()) { + val accessor = frame.accessor() + + it.add( + when (accessor.getArgumentShorty(i)) { + 'L' -> accessor.getReference(i) + 'Z' -> accessor.getBoolean(i) + 'B' -> accessor.getByte(i) + 'C' -> accessor.getChar(i) + 'S' -> accessor.getShort(i) + 'I' -> accessor.getInt(i) + 'J' -> accessor.getLong(i) + 'F' -> accessor.getFloat(i) + 'D' -> accessor.getDouble(i) + else -> throw Exception("Should not reach here") + } + ) + } + + it.toTypedArray() + } + } + + fun filter(pattern: String): Predicate { + val compiledPattern = Pattern.compile(pattern) + return Predicate { executable: Executable? -> + compiledPattern.matcher(printExecutable(executable)).matches() + } + } + + @Throws(InterruptedException::class) + fun waitForService(name: String?): IBinder? { + var service: IBinder? = null + + do { + Thread.sleep(250) + } while ((ServiceManager.getService(name).also { service = it }) == null) + + return service + } + + fun getPackageNameFromPackageSettings(packageSettings: Any): String? { + return runCatching { + packageSettings::class.java.getField( + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) "mName" else "name" + ).apply { isAccessible = true }.get(packageSettings) as? String + }.getOrNull() + } + + fun getPackageManager() = ActivityThread.currentActivityThread().application.packageManager!! + + fun getCallingApps(service: HMAService): Array { + return getCallingApps(service, Binder.getCallingUid()) + } + + fun getCallingApps(service: HMAService, callingUid: Int): Array { + if (callingUid == Constants.UID_SYSTEM) return arrayOf() + return Utils.binderLocalScope { + service.pms.getPackagesForUid(callingUid) + } ?: arrayOf() + } + + fun getStaticIntField(className: String, name: String) = getDeclaredField( + Class.forName(className), + name, + ).getInt(null) + + fun getIntField(obj: Any, name: String) = getDeclaredField(obj.javaClass, name).getInt(obj) + + fun getBooleanField(obj: Any, name: String) = getDeclaredField(obj.javaClass, name).getBoolean(obj) + + fun getObjectField(obj: Any, name: String): Any? = getDeclaredField(obj.javaClass, name).get(obj) + + fun setBooleanField(obj: Any, name: String, value: Boolean) { + val field = getDeclaredField(obj.javaClass, name).apply { isAccessible = true } + field.setBoolean(obj, value) + } + + fun callMethod(obj: Any, name: String, vararg args: Any): Any? { + return getDeclaredMethod( + obj.javaClass, + name, + *args.map { it.javaClass }.toTypedArray() + ).apply { isAccessible = true }.invoke(obj, *args) + } + + fun findConstructor(className: String, paramCount: Int = -1): Constructor<*>? { + val clazz = Class.forName(className, true, SystemServerHook.classLoader) + + return clazz.constructors.firstOrNull { + paramCount == -1 || it.parameterCount == paramCount + } + } + + fun findMethod(className: String, name: String, isDeclared: Boolean = false, systemClassLoader: Boolean = false, vararg args: Class<*>): Method { + val clazz = if (systemClassLoader) Class.forName(className, true, SystemServerHook.classLoader) else Class.forName(className) + return if (isDeclared) { + clazz.getDeclaredMethod(name, *args) + } else { + clazz.getMethod(name, *args) + } + } + + private fun getClassName(clazz: Class<*>): String { + val component = clazz.componentType + if (component != null) { + return getClassName(component) + "[]" + } + return clazz.name + } + + private fun getExecName(executable: Executable?): String { + if (executable is Method) { + return executable.name + } + assert(executable is Constructor<*>) + return if (Modifier.isStatic(executable!!.modifiers)) "" else "" + } + + private fun getReturnType(executable: Executable?): String { + if (executable is Method) { + return getClassName(executable.returnType) + } + assert(executable is Constructor<*>) + return getClassName(Void.TYPE) + } + + private fun printExecutable(executable: Executable?): String { + val paramTypes = + executable?.parameterTypes?.joinToString(separator = ", ") { getClassName(it) } + + return "${getExecName(executable)}(${paramTypes})${getReturnType(executable)}" + } +} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedConstants.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt similarity index 90% rename from xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedConstants.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt index 26ef55165..bebae4138 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedConstants.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt @@ -1,6 +1,6 @@ -package icu.nullptr.hidemyapplist.xposed +package org.frknkrc44.hma_oss.zygote -object XposedConstants { +object ZygoteConstants { const val COMPUTER_ENGINE_CLASS = "com.android.server.pm.ComputerEngine" const val PACKAGE_MANAGER_SERVICE_CLASS = "com.android.server.pm.PackageManagerService" const val PMS_COMPUTER_TRACKER_CLASS = $$"com.android.server.pm.PackageManagerService$ComputerTracker" @@ -15,4 +15,5 @@ object XposedConstants { const val ACTIVITY_TASK_SUPERVISOR_CLASS = "com.android.server.wm.ActivityTaskSupervisor" const val ACTIVITY_STACK_SUPERVISOR_CLASS = "com.android.server.wm.ActivityStackSupervisor" const val ZYGOTE_PROCESS_CLASS = "android.os.ZygoteProcess" + const val PROCESS_LIST_CLASS = "com.android.server.am.ProcessList" } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java new file mode 100644 index 000000000..d83e5d9f0 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java @@ -0,0 +1,37 @@ +package org.frknkrc44.hma_oss.zygote; + +import static org.frknkrc44.hma_oss.zygote.LogcatKt.logE; +import static org.frknkrc44.hma_oss.zygote.LogcatKt.logI; + +import com.v7878.r8.annotations.DoNotObfuscate; +import com.v7878.r8.annotations.DoNotObfuscateType; +import com.v7878.r8.annotations.DoNotShrink; +import com.v7878.r8.annotations.DoNotShrinkType; +import com.v7878.zygisk.ZygoteLoader; + +@SuppressWarnings("all") +@DoNotObfuscateType +@DoNotShrinkType +public class ZygoteEntry { + public static final String TAG = "ZygoteEntry"; + + @DoNotObfuscate + @DoNotShrink + public static void premain() throws Throwable { + + } + + @DoNotObfuscate + @DoNotShrink + public static void main() throws Throwable { + logI(TAG, "Injected into " + ZygoteLoader.getPackageName(), null); + + try { + SystemServerHook.init(); + } catch (Throwable th) { + logE(TAG, "An exception occurred while SystemServerHook init", th); + } + + logI(TAG, "Done", null); + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt new file mode 100644 index 000000000..35f5d11da --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -0,0 +1,75 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.accessibilityservice.AccessibilityServiceInfo +import android.content.pm.ParceledListSlice +import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logE + +class AccessibilityHook(private val service: HMAService) : IFrameworkHook { + companion object { + private const val TAG = "AccessibilityHook" + } + + override fun load() { + BulkHooker.instance.apply { + hookBefore( + ACCESSIBILITY_SERVICE_CLASS, + "getInstalledAccessibilityServiceList", + dumpArgs = false, + ) { param -> hookedMethod(param, true) } + + hookBefore( + ACCESSIBILITY_SERVICE_CLASS, + "getEnabledAccessibilityServiceList", + dumpArgs = false, + ) { param -> hookedMethod(param, false) } + + hookBefore( + ACCESSIBILITY_SERVICE_CLASS, + "addClient", + dumpArgs = false, + ) { param -> + val callingApps = Utils4Zygote.getCallingApps(service) + if (callingApps.isEmpty()) return@hookBefore + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + param.result = 0L + // service.increasePMFilterCount(caller) + } + } + } + } + + private fun callerIsSpoofed(caller: String) = + service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) + + private fun hookedMethod(param: BulkHooker.HookParam, returnParcel: Boolean) { + try { + val callingApps = Utils4Zygote.getCallingApps(service) + if (callingApps.isEmpty()) return + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + val returnedList = java.util.ArrayList() + + logD(TAG, "@${param.methodName} returned empty list for ${callingApps.contentToString()}") + + param.result = if (returnParcel) { + ParceledListSlice(returnedList) + } else { + returnedList + } + + // service.increasePMFilterCount(caller) + } + } catch (e: Throwable) { + logE(TAG, "Fatal error occurred, ignore hooks", e) + } + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt new file mode 100644 index 000000000..703e08c0a --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -0,0 +1,134 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.content.Intent +import android.content.pm.ResolveInfo +import android.os.Build +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getObjectField +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getStaticIntField +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACTIVITY_STARTER_CLASS +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.COMPUTER_ENGINE_CLASS +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.logV + +class ActivityHook(private val service: HMAService) : IFrameworkHook { + companion object { + private const val TAG = "ActivityHook" + private val fakeReturnCode by lazy { + getStaticIntField( + "android.app.ActivityManager", + "START_CLASS_NOT_FOUND", + ) + } + } + + override fun load() { + logI(TAG, "Load hook") + + BulkHooker.instance.apply { + hookBefore( + ACTIVITY_STARTER_CLASS, + "execute", + ) { param -> + val request = getObjectField(param.thisObject, "mRequest") ?: return@hookBefore + val caller = getObjectField(request, "callingPackage") as String? + val intent = getObjectField(request, "intent") as Intent? + val targetApp = intent?.component?.packageName + + if (service.shouldHideActivityLaunch(caller, targetApp)) { + logD( + TAG, + "@executeRequest: insecure query from $caller, target: ${intent?.component}" + ) + param.result = fakeReturnCode + service.increaseALFilterCount(caller) + } + } + + /* + // TODO: Maybe not required anymore? + hookBefore( + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + ACTIVITY_TASK_SUPERVISOR_CLASS + } else { + ACTIVITY_STACK_SUPERVISOR_CLASS + }, + "checkStartAnyActivityPermission", + ) { param -> + var throwable = param.throwable + + while (throwable != null) { + val newTrace = throwable.stackTrace.filter { item -> + !Utils.containsMultiple( + item.className, + "HookBridge", + "LSPHooker", + "LSPosed", + ) + } + + if (newTrace.size != throwable.stackTrace.size) { + throwable.stackTrace = newTrace.toTypedArray() + + val callingUid = param.args!!.lastOrNull { it is Int } as Int? + + logD(TAG, "@checkStartAnyActivityPermission: ${throwable.stackTrace.size - newTrace.size} remnants cleared for $callingUid!") + + service.increaseALFilterCount(callingUid) + } + + throwable = throwable.cause + } + } + */ + + if (!Utils.isSamsung()) { + hookBefore( + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + COMPUTER_ENGINE_CLASS + } else { + PACKAGE_MANAGER_SERVICE_CLASS + }, + "applyPostResolutionFilter", + ) { param -> + @Suppress("UNCHECKED_CAST") // I know what I do + val list = param.args?.get(1) as List? + if (list.isNullOrEmpty()) return@hookBefore + + val callingUid = param.args.first { it is Int } as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.isHookEnabled(it) } + if (caller != null) { + logV(TAG, "@${param.methodName}: $caller requested a resolve info") + + val filteredList = list.filter { resolveInfo -> + val targetApp = Utils.getPackageNameFromResolveInfo(resolveInfo) + + logV(TAG, "@${param.methodName}: Checking $targetApp for $caller") + + (!service.shouldHideActivityLaunch(caller, targetApp)).apply { + if (!this) { + logD(TAG, "@${param.methodName}: Filtered $targetApp from $caller") + } + } + } + + if (filteredList.size != list.size) { + param.args[1] = filteredList.toList() + + service.increasePMFilterCount(caller) + } + } + } + } + } + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt new file mode 100644 index 000000000..a2a9ec9f2 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -0,0 +1,204 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.os.Build +import android.os.SystemProperties +import androidx.annotation.RequiresApi +import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getBooleanField +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getIntField +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getObjectField +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.setBooleanField +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PROCESS_LIST_CLASS +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.STORAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logE +import org.frknkrc44.hma_oss.zygote.logI + +@RequiresApi(Build.VERSION_CODES.R) +class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { + + companion object { + private const val TAG = "AppDataIsolationHook" + private const val APPDATA_ISOLATION_ENABLED = "mAppDataIsolationEnabled" + private const val VOLD_APPDATA_ISOLATION_ENABLED = "mVoldAppDataIsolationEnabled" + private const val FUSE_PROP = "persist.sys.fuse" + } + + private var voldHookSkipped = false + + override fun load() { + if (!(service.config.altAppDataIsolation || service.config.altVoldAppDataIsolation)) return + logI(TAG, "Load hook") + + BulkHooker.instance.apply { + hookBefore( + PROCESS_LIST_CLASS, + "startProcess", + ) { param -> + if (service.config.altAppDataIsolation) { + val isEnabled = getBooleanField( + param.thisObject, + APPDATA_ISOLATION_ENABLED, + ) + + if (!isEnabled) { + setBooleanField( + param.thisObject, + APPDATA_ISOLATION_ENABLED, + true + ) + + logI(TAG, "ProcessList - App data isolation is forced") + } + } + + if (service.config.altVoldAppDataIsolation && !voldHookSkipped) { + val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) + + if (!fuseEnabled) { + voldHookSkipped = true + logE(TAG, "ProcessList - FUSE storage is not enabled, skip vold hook") + } else { + val isolationEnabled = getBooleanField( + param.thisObject, + VOLD_APPDATA_ISOLATION_ENABLED + ) + + if (!isolationEnabled) { + setBooleanField( + param.thisObject, + VOLD_APPDATA_ISOLATION_ENABLED, + true + ) + + logI(TAG, "ProcessList - Vold app data isolation is forced") + } + } + } + } + + hookAfter( + PROCESS_LIST_CLASS, + "needsStorageDataIsolation", + ) { param -> + if (service.config.altVoldAppDataIsolation) { + val app = param.args!!.find { it?.javaClass?.simpleName == "ProcessRecord" }!! + val uid = getIntField(app, "uid") + val processName = runCatching { + getObjectField(app, "processName") + }.getOrDefault("") + val mountNode = runCatching { + getIntField(app, "mMountMode") + }.getOrDefault(0) + val isolated = runCatching { + getBooleanField(app, "isolated") + }.getOrDefault(false) + val appZygote = runCatching { + getBooleanField(app, "appZygote") + }.getOrDefault(false) + + val apps = Utils.binderLocalScope { + service.pms.getPackagesForUid(uid) + } ?: return@hookAfter + + logD( + TAG, + "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" + ) + + // Do not isolate this module for safety + if (apps.contains(BuildConfig.APP_PACKAGE_NAME)) { + param.result = false + return@hookAfter + } + + if (apps.any { service.isAppDataIsolationExcluded(it) }) { + param.result = false + } + + if (service.config.skipSystemAppDataIsolation) { + val isSystemApp = service.systemApps.any { apps.contains(it) } + logD( + TAG, + "@needsStorageDataIsolation $uid and ${apps.contentToString()} - isSystemApp: $isSystemApp" + ) + + if (isSystemApp) { + param.result = false + return@hookAfter + } + } + } + } + + hookBefore( + STORAGE_MANAGER_SERVICE_CLASS, + "onVolumeStateChangedLocked", + ) { param -> + if (service.config.altVoldAppDataIsolation) { + val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) + + if (!fuseEnabled) { + logE(TAG, "StorageManagerService - FUSE storage is not enabled, disable hooks") + unload() + return@hookBefore + } + + val isolationEnabled = getBooleanField( + param.thisObject, + VOLD_APPDATA_ISOLATION_ENABLED + ) + + if (!isolationEnabled) { + setBooleanField( + param.thisObject, + VOLD_APPDATA_ISOLATION_ENABLED, + true + ) + + logI(TAG, "StorageManagerService - Vold app data isolation is forced") + } + } + } + + hookBefore( + STORAGE_MANAGER_SERVICE_CLASS, + "remountAppStorageDirs", + ) { param -> + if (service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + val pidPkgMap = param.args!![1] as java.util.Map<*, *> + val userId = param.args[2] as Int + + val keysToRemove = mutableSetOf() + + for (entry in pidPkgMap.entrySet()) { + val pid = entry.key + val packageName = entry.value as String + + val apps = Utils.binderLocalScope { + val uid = Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) + service.pms.getPackagesForUid(uid) + } ?: continue + + for (app in apps) { + if (app in service.systemApps || app == BuildConfig.APP_PACKAGE_NAME) { + logD( + TAG, + "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" + ) + keysToRemove += pid + break + } + } + } + + keysToRemove.forEach { pidPkgMap.remove(it) } + } + } + } + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt new file mode 100644 index 000000000..b10622ab6 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -0,0 +1,167 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.content.AttributionSource +import android.database.Cursor +import android.database.MatrixCursor +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.provider.Settings +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.CONTENT_PROVIDER_TRANSPORT_CLASS +import org.frknkrc44.hma_oss.zygote.logD + +class ContentProviderHook(private val service: HMAService): IFrameworkHook { + companion object { + private const val TAG = "ContentProviderHook" + private val NV_PAIR = arrayOf("name", "value") + } + + @Suppress("UNCHECKED_CAST") + override fun load() { + BulkHooker.instance.apply { + hookAfter( + CONTENT_PROVIDER_TRANSPORT_CLASS, + "query", + ) { param -> + val callingApps = getCallingPackages(param) + + val caller = callingApps.firstOrNull { service.isHookEnabled(it) } + if (caller == null) return@hookAfter + + val uriIdx = param.args?.indexOfFirst { it is Uri } ?: return@hookAfter + val uri = param.args[uriIdx] as Uri + val projection = param.args[uriIdx + 1] as Array? + val args = param.args[uriIdx + 2] as Bundle? + + if (uri.authority != "settings") return@hookAfter + + val segments = uri.pathSegments + if (segments.isEmpty()) return@hookAfter + + logD(TAG, "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args") + + val database = segments[0] + + if (segments.size >= 2) { + val name = segments[1] + + logD(TAG, "@spoofSettings QUERY received caller: $caller, database: $database, name: $name") + + val replacement = service.getSpoofedSetting(caller, name, database) + if (replacement != null) { + logD(TAG, "@spoofSettings QUERY $name in $database replaced for $caller") + param.result = MatrixCursor(arrayOf("name", "value"), 1).apply { + addRow(arrayOf(replacement.name, replacement.value)) + } + + service.increaseSettingsFilterCount(caller) + } + } else { + logD(TAG, "@spoofSettings LIST_QUERY received caller: $caller, database: $database") + + val result = param.result as Cursor? ?: return@hookAfter + + val columns = mutableMapOf>().apply { + for (i in 0 ..< result.columnCount) { + put(result.getColumnName(i), mutableListOf()) + } + } + + logD(TAG, "@spoofSetting LIST_QUERY columns: ${columns.keys}") + + val keyColumn = columns["name"] + val valueColumn = columns["value"] + + if (keyColumn == null || valueColumn == null) { + logD(TAG, "@spoofSettings LIST_QUERY invalid query: $caller ($keyColumn, $valueColumn)") + return@hookAfter + } + + while (result.moveToNext()) { + val name = result.getString(columns.keys.indexOf("name")) + keyColumn.add(name) + + val replacement = service.getSpoofedSetting(caller, name, database) + val value = if (replacement != null) { + logD(TAG, "@spoofSettings QUERY $name in $database replaced for $caller") + + service.increaseSettingsFilterCount(caller) + + replacement.value + } else { + result.getString(columns.keys.indexOf("value")) + } + + valueColumn.add(value) + + if (columns.keys.size > 2) { + for (otherCol in columns.keys.filter { it !in NV_PAIR }) { + val other = result.getString(columns.keys.indexOf(otherCol)) + + columns[otherCol]!!.add(other) + } + } + } + + param.result = MatrixCursor(columns.keys.toTypedArray(), columns.size).apply { + val size = columns.values.first().size + for (i in 0 ..< size) { + val innerList = mutableListOf() + + columns.values.forEach { colVal -> + innerList.add(colVal[i]) + } + + addRow(innerList) + } + } + } + } + + hookBefore( + CONTENT_PROVIDER_TRANSPORT_CLASS, + "call", + ) { param -> + val callingApps = getCallingPackages(param) + val caller = callingApps.firstOrNull { service.isHookEnabled(it) } + if (caller == null) return@hookBefore + + val nameIdx = param.args?.indexOfLast { it is String } ?: return@hookBefore + val name = param.args[nameIdx] as String? + val method = param.args[nameIdx - 1] as String? + + logD(TAG, "@spoofSettings CALL received caller: ${callingApps.contentToString()}, method: $method, name: $name") + + when (method) { + "GET_global", "GET_secure", "GET_system" -> { + val database = method.substring(method.indexOf('_') + 1) + val replacement = service.getSpoofedSetting(caller, name, database) + if (replacement != null) { + logD(TAG, "@spoofSettings CALL $name in $database replaced for $caller") + param.result = Bundle().apply { + putString(Settings.NameValueTable.VALUE, replacement.value) + putInt("_generation_index", -1) + } + + service.increaseSettingsFilterCount(caller) + } + } + } + } + } + } + + private fun getCallingPackages(param: BulkHooker.HookParam) = try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val attrSource = param.args!!.first { it is AttributionSource } as AttributionSource + arrayOf(attrSource.packageName) + } else { + arrayOf(param.args!!.first { it is String } as String) + } + } catch (_: Throwable) { + Utils4Zygote.getCallingApps(service) + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt new file mode 100644 index 000000000..26907c51a --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt @@ -0,0 +1,10 @@ +package org.frknkrc44.hma_oss.zygote.hook + +interface IFrameworkHook { + + fun load() + fun unload() { + // TODO: Find a way to unload + } + fun onConfigChanged() {} +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt new file mode 100644 index 000000000..8893ed253 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -0,0 +1,177 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.content.ComponentName +import android.os.Build +import android.provider.Settings +import android.view.inputmethod.InputMethodInfo +import android.view.inputmethod.InputMethodSubtype +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Utils +import icu.nullptr.hidemyapplist.common.settings_presets.InputMethodPreset +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.IMM_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logE +import java.util.Collections + +class ImmHook(private val service: HMAService) : IFrameworkHook { + companion object { + private const val TAG = "ImmHook" + } + + // TODO: Find a method to get settings activity + fun getFakeInputMethodInfo(packageName: String): InputMethodInfo { + val defaultInputMethod = service.getSpoofedSetting( + packageName, + Settings.Secure.DEFAULT_INPUT_METHOD, + Constants.SETTINGS_SECURE, + ) + + if (defaultInputMethod?.value != null) { + try { + val component = ComponentName.unflattenFromString(defaultInputMethod.value!!)!! + logD(TAG, "Package component: \"$component\"") + + val pkgManager = Utils4Zygote.getPackageManager() + val kbdPackage = Utils.binderLocalScope { + pkgManager.getApplicationInfo(component.packageName, 0) + } + + return InputMethodInfo( + component.packageName, + component.className, + kbdPackage.loadLabel(pkgManager), + null, + ) + } catch (e: Throwable) { + logE(TAG, e.message ?: "", e) + } + } + + return InputMethodInfo( + "com.google.android.inputmethod.latin", + "com.android.inputmethod.latin.LatinIME", + "Gboard", + null, + ) + } + + override fun load() { + BulkHooker.instance.apply { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + hookBefore( + IMM_SERVICE_CLASS, + "getCurrentInputMethodInfoAsUser", + dumpArgs = false, + ) { param -> + val callingApps = Utils4Zygote.getCallingApps(service) + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + logD(TAG, "@${param.methodName} spoofed input method for $caller") + + param.result = getFakeInputMethodInfo(caller) + service.increaseSettingsFilterCount(caller) + } + } + } + + hookBefore( + IMM_SERVICE_CLASS, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) + "getInputMethodListInternal" + else + "getInputMethodList", + dumpArgs = Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA, + ) { param -> + listHook(param) + } + + hookBefore( + IMM_SERVICE_CLASS, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) + "getEnabledInputMethodListInternal" + else + "getEnabledInputMethodList", + dumpArgs = Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA, + ) { param -> + listHook(param) + } + + hookBefore( + IMM_SERVICE_CLASS, + "getCurrentInputMethodSubtype", + dumpArgs = false, + ) { param -> + subtypeHook(param) + } + + hookBefore( + IMM_SERVICE_CLASS, + "getLastInputMethodSubtype", + dumpArgs = false, + ) { param -> + subtypeHook(param) + } + + hookBefore( + IMM_SERVICE_CLASS, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) + "getEnabledInputMethodSubtypeListInternal" + else + "getEnabledInputMethodSubtypeList", + dumpArgs = false, + ) { param -> + subtypeListHook(param) + } + } + } + + private fun listHook(param: BulkHooker.HookParam) { + val callingApps = if (param.methodName.endsWith("Internal")) { + val callingUid = param.args?.findLast { it is Int } as Int + Utils4Zygote.getCallingApps(service, callingUid) + } else { + Utils4Zygote.getCallingApps(service) + } + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + logD(TAG, "@${param.methodName} spoofed input method for $caller") + + param.result = listOf(getFakeInputMethodInfo(caller)) + service.increaseSettingsFilterCount(caller) + } + } + + private fun subtypeHook(param: BulkHooker.HookParam) { + val callingApps = Utils4Zygote.getCallingApps(service) + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + logD(TAG, "@${param.methodName} spoofed input method subtype for ${callingApps.contentToString()}") + + // TODO: Find a method to get exact value for spoofed input method + param.result = null + service.increaseSettingsFilterCount(caller) + } + } + + private fun subtypeListHook(param: BulkHooker.HookParam) { + val callingApps = Utils4Zygote.getCallingApps(service) + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + logD(TAG, "@${param.methodName} spoofed input method subtype for ${callingApps.contentToString()}") + + // TODO: Find a method to get exact list for spoofed input method + param.result = Collections.emptyList() + service.increaseSettingsFilterCount(caller) + } + } + + private fun callerIsSpoofed(caller: String) = + service.getEnabledSettingsPresets(caller).contains(InputMethodPreset.NAME) +} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt similarity index 65% rename from xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PlatformCompatHook.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index c4e27851b..d249a9b9d 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -1,18 +1,16 @@ -package icu.nullptr.hidemyapplist.xposed.hook +package org.frknkrc44.hma_oss.zygote.hook import android.content.pm.ApplicationInfo import android.os.Build import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook import icu.nullptr.hidemyapplist.common.PropertyUtils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PLATFORM_COMPAT_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PLATFORM_COMPAT_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logE +import org.frknkrc44.hma_oss.zygote.logI @RequiresApi(Build.VERSION_CODES.R) class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { @@ -25,22 +23,22 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { PropertyUtils.isAppDataIsolationEnabled || service.config.altAppDataIsolation } - private var hook: XC_MethodHook.Unhook? = null - override fun load() { if (!service.config.forceMountData) return logI(TAG, "Load hook") logI(TAG, "App data isolation enabled: $sAppDataIsolationEnabled") - hook = findMethod(PLATFORM_COMPAT_CLASS) { - name == "isChangeEnabled" - }.hookBefore { param -> + + BulkHooker.instance.hookBefore( + PLATFORM_COMPAT_CLASS, + "isChangeEnabled", + ) { param -> runCatching { if (!sAppDataIsolationEnabled) return@hookBefore - val changeId = param.args[0] as Long + val changeId = param.args!![1] as Long if (changeId != 143937733L) return@hookBefore - val appInfo = param.args[1] as ApplicationInfo + val appInfo = param.args[2] as ApplicationInfo val app = appInfo.packageName if (app == BuildConfig.APP_PACKAGE_NAME || app in service.systemApps) return@hookBefore if (service.isHookEnabled(app)) { @@ -54,16 +52,13 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { } } - override fun unload() { - hook?.unhook() - hook = null - } - override fun onConfigChanged() { + /* if (service.config.forceMountData) { if (hook == null) load() } else { if (hook != null) unload() } + */ } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt new file mode 100644 index 000000000..fd1bb41fd --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -0,0 +1,106 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.logV + +class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { + + override val TAG = "PmsHookTarget29" + + // not required until SDK 30 + override val fakeSystemPackageInstallSourceInfo = null + override val fakeUserPackageInstallSourceInfo = null + + @Suppress("UNCHECKED_CAST") + override fun load() { + logI(TAG, "Load hook") + + BulkHooker.instance.apply { + hookBefore( + service.pms::class.java.name, + "filterAppAccessLPr", + paramCount = 5, + ) { param -> + val callingUid = param.args!![2] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val packageSettings = param.args[1] ?: return@hookBefore + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(packageSettings) + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = true + service.increasePMFilterCount(callingUid) + logD(TAG, "@filterAppAccessLPr caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils.binderLocalScope { + service.pms.getPackagesForUid(callingUid) + } ?: return@hookBefore + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + param.result = true + service.putShouldHideUidCache(callingUid, caller, targetApp!!) + service.increasePMFilterCount(caller) + val last = lastFilteredApp.getAndSet(caller) + if (last != caller) logI(TAG, "@filterAppAccessLPr query from $caller") + logD(TAG, "@filterAppAccessLPr caller: $callingUid $caller, target: $targetApp") + } + } + + hookBefore( + PACKAGE_MANAGER_SERVICE_CLASS, + "getPackageInfoInternal", + ) { param -> + val targetApp = param.args!![1] as String? ?: return@hookBefore + val callingUid = param.args[4] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + PACKAGE_MANAGER_SERVICE_CLASS, + "getApplicationInfoInternal", + ) { param -> + val targetApp = param.args!![1] as String? ?: return@hookBefore + val callingUid = param.args[3] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + } + + super.load() + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt new file mode 100644 index 000000000..3b945189d --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -0,0 +1,152 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.os.Binder +import android.os.Build +import androidx.annotation.RequiresApi +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME +import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_CLASS +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.logV + +@RequiresApi(Build.VERSION_CODES.R) +class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { + + override val TAG = "PmsHookTarget30" + + override val fakeSystemPackageInstallSourceInfo: Any by lazy { + findConstructor( + "android.content.pm.InstallSourceInfo", + 4, + )!!.newInstance( + null, + null, + null, + null, + ) + } + + override val fakeUserPackageInstallSourceInfo: Any by lazy { + findConstructor( + "android.content.pm.InstallSourceInfo", + 4, + )!!.newInstance( + VENDING_PACKAGE_NAME, + psPackageInfo?.signingInfo, + VENDING_PACKAGE_NAME, + VENDING_PACKAGE_NAME, + ) + } + + override fun load() { + logI(TAG, "Load hook") + + BulkHooker.instance.apply { + hookBefore( + PACKAGE_MANAGER_SERVICE_CLASS, + "getPackageSetting", + ) { param -> + val targetApp = param.args!![1] as String + val callingUid = Binder.getCallingUid() + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@getPackageSetting - PkgMgr cache: insecure query from $callingUid to $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@getPackageSetting - PkgMgr: insecure query from $caller to $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + APPS_FILTER_CLASS, + "shouldFilterApplication", + ) { param -> + val callingUid = param.args!![1] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[3]!!) + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = true + service.increasePMFilterCount(callingUid) + logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils.binderLocalScope { + service.pms.getPackagesForUid(callingUid) + } ?: return@hookBefore + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + param.result = true + service.putShouldHideUidCache(callingUid, caller, targetApp!!) + service.increasePMFilterCount(caller) + val last = lastFilteredApp.getAndSet(caller) + if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") + logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") + } + } + + hookBefore( + PACKAGE_MANAGER_SERVICE_CLASS, + "getPackageInfoInternal", + ) { param -> + val targetApp = param.args?.get(1) as String? ?: return@hookBefore + val callingUid = param.args[4] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + PACKAGE_MANAGER_SERVICE_CLASS, + "getApplicationInfoInternal", + ) { param -> + val targetApp = param.args?.get(1) as String? ?: return@hookBefore + val callingUid = param.args[3] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + } + + super.load() + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt new file mode 100644 index 000000000..4db19dee2 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -0,0 +1,178 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.os.Binder +import android.os.Build +import androidx.annotation.RequiresApi +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME +import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_CLASS +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PMS_COMPUTER_TRACKER_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.logV + +@RequiresApi(Build.VERSION_CODES.S) +class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { + + override val TAG = "PmsHookTarget31" + + override val fakeSystemPackageInstallSourceInfo: Any by lazy { + findConstructor( + "android.content.pm.InstallSourceInfo", + 4, + )!!.newInstance( + null, + null, + null, + null, + ) + } + + override val fakeUserPackageInstallSourceInfo: Any by lazy { + findConstructor( + "android.content.pm.InstallSourceInfo", + 4, + )!!.newInstance( + VENDING_PACKAGE_NAME, + psPackageInfo?.signingInfo, + VENDING_PACKAGE_NAME, + VENDING_PACKAGE_NAME, + ) + } + + override fun load() { + logI(TAG, "Load hook") + + BulkHooker.instance.apply { + hookBefore( + PMS_COMPUTER_TRACKER_CLASS, + "getPackageSetting", + ) { param -> + val targetApp = param.args?.get(1) as String + val callingUid = Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@getPackageSetting - Computer cache: insecure query from $callingUid to $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@getPackageSetting - Computer: insecure query from $caller to $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + PMS_COMPUTER_TRACKER_CLASS, + "getPackageSettingInternal", + ) { param -> + val targetApp = param.args!![1] as String + val callingUid = param.args[2] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@getPackageSettingInternal - Computer cache: insecure query from $callingUid to $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@getPackageSettingInternal - Computer: insecure query from $caller to $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + PMS_COMPUTER_TRACKER_CLASS, + "getPackageInfoInternal", + ) { param -> + val targetApp = param.args?.get(1) as String? ?: return@hookBefore + val callingUid = param.args[4] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + PMS_COMPUTER_TRACKER_CLASS, + "getApplicationInfoInternal", + ) { param -> + val targetApp = param.args?.get(1) as String? ?: return@hookBefore + val callingUid = param.args[3] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + APPS_FILTER_CLASS, + "shouldFilterApplication", + ) { param -> + logV(TAG, "@shouldFilterApplication call: ${param.args.contentToString()}") + + val callingUid = param.args!![1] as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[3]!!) + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = true + service.increasePMFilterCount(callingUid) + logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils.binderLocalScope { + service.pms.getPackagesForUid(callingUid) + } ?: return@hookBefore + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + param.result = true + service.putShouldHideUidCache(callingUid, caller, targetApp!!) + service.increasePMFilterCount(caller) + val last = lastFilteredApp.getAndSet(caller) + if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") + logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") + } + } + } + + super.load() + } +} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt similarity index 63% rename from xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget33.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index 3e6716051..7e4c35d17 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -1,21 +1,19 @@ -package icu.nullptr.hidemyapplist.xposed.hook +package org.frknkrc44.hma_oss.zygote.hook import android.content.pm.PackageInstaller import android.os.Build import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_IMPL_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findMethod +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_IMPL_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logI @RequiresApi(Build.VERSION_CODES.TIRAMISU) class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { @@ -23,17 +21,20 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { override val TAG = "PmsHookTarget33" private val getPackagesForUidMethod by lazy { - findMethod("com.android.server.pm.Computer") { - name == "getPackagesForUid" - } + findMethod( + "com.android.server.pm.Computer", + "getPackagesForUid", + isDeclared = false, + systemClassLoader = true, + Int::class.java, + ) } override val fakeSystemPackageInstallSourceInfo: Any by lazy { findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 5 - }.newInstance( + "android.content.pm.InstallSourceInfo", + 5, + )!!.newInstance( null, null, null, @@ -44,10 +45,9 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { override val fakeUserPackageInstallSourceInfo: Any by lazy { findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 5 - }.newInstance( + "android.content.pm.InstallSourceInfo", + 5, + )!!.newInstance( VENDING_PACKAGE_NAME, psPackageInfo?.signingInfo, VENDING_PACKAGE_NAME, @@ -59,13 +59,15 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { logI(TAG, "Load hook") - hooks += findMethod(APPS_FILTER_IMPL_CLASS, findSuper = true) { - name == "shouldFilterApplication" - }.hookBefore { param -> - runCatching { - val callingUid = param.args[1] as Int + + BulkHooker.instance.apply { + hookBefore( + APPS_FILTER_IMPL_CLASS, + "shouldFilterApplication", + ) { param -> + val callingUid = param.args!![2] as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Xposed.getPackageNameFromPackageSettings(param.args[3]) // PackageSettings <- PackageStateInternal + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[4]!!) // PackageSettings <- PackageStateInternal if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) @@ -85,12 +87,9 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") } - }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) - unload() } } super.load() } -} +} \ No newline at end of file diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt similarity index 62% rename from xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget34.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 4fcbb58ca..8cc34b278 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -1,24 +1,21 @@ -package icu.nullptr.hidemyapplist.xposed.hook +package org.frknkrc44.hma_oss.zygote.hook import android.content.pm.PackageInstaller import android.os.Binder import android.os.Build import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_IMPL_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.logD -import icu.nullptr.hidemyapplist.xposed.logE -import icu.nullptr.hidemyapplist.xposed.logI +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findMethod +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_IMPL_CLASS +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logI @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { @@ -26,17 +23,20 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { override val TAG = "PmsHookTarget34" private val getPackagesForUidMethod by lazy { - findMethod("com.android.server.pm.Computer") { - name == "getPackagesForUid" - } + findMethod( + "com.android.server.pm.Computer", + "getPackagesForUid", + isDeclared = false, + systemClassLoader = true, + Int::class.java, + ) } override val fakeSystemPackageInstallSourceInfo: Any by lazy { findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 6 - }.newInstance( + "android.content.pm.InstallSourceInfo", + 6, + )!!.newInstance( null, null, null, @@ -48,10 +48,9 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { override val fakeUserPackageInstallSourceInfo: Any by lazy { findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 6 - }.newInstance( + "android.content.pm.InstallSourceInfo", + 6, + )!!.newInstance( VENDING_PACKAGE_NAME, psPackageInfo?.signingInfo, VENDING_PACKAGE_NAME, @@ -64,20 +63,22 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { logI(TAG, "Load hook") - hooks += findMethod(APPS_FILTER_IMPL_CLASS, findSuper = true) { - name == "shouldFilterApplication" - }.hookBefore { param -> - runCatching { - val callingUid = param.args[1] as Int + + BulkHooker.instance.apply { + hookBefore( + APPS_FILTER_IMPL_CLASS, + "shouldFilterApplication", + ) { param -> + val callingUid = param.args!![2] as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Xposed.getPackageNameFromPackageSettings(param.args[3]) // PackageSettings <- PackageStateInternal + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[4]!!) // PackageSettings <- PackageStateInternal if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") return@hookBefore } - val snapshot = param.args[0] + val snapshot = param.args[1] val callingApps = Utils.binderLocalScope { getPackagesForUidMethod.invoke(snapshot, callingUid) as Array? } ?: return@hookBefore @@ -90,20 +91,17 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") } - }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) - unload() } - } - // AOSP exploit - https://github.com/aosp-mirror/platform_frameworks_base/commit/5bc482bd99ea18fe0b4064d486b29d5ae2d65139 - // Only 14 QPR2+ has this method - findMethodOrNull(PACKAGE_MANAGER_SERVICE_CLASS, findSuper = true) { - name == "getArchivedPackageInternal" - }?.hookBefore { param -> - runCatching { + + // AOSP exploit - https://github.com/aosp-mirror/platform_frameworks_base/commit/5bc482bd99ea18fe0b4064d486b29d5ae2d65139 + // Only 14 QPR2+ has this method + hookBefore( + PACKAGE_MANAGER_SERVICE_CLASS, + "getArchivedPackageInternal", + ) { param -> val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.args[0].toString() + val targetApp = param.args!![1].toString() if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) @@ -122,14 +120,9 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { if (last != caller) logI(TAG, "@getArchivedPackageInternal: query from $caller") logD(TAG, "@getArchivedPackageInternal caller: $callingUid $caller, target: $targetApp") } - }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) - unload() } - }?.let { - hooks.add(it) } super.load() } -} +} \ No newline at end of file diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt new file mode 100644 index 000000000..f9fa0a623 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -0,0 +1,251 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.content.pm.PackageManager +import android.os.Binder +import android.os.Build +import android.os.UserHandle +import android.util.ArrayMap +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME +import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.COMPUTER_ENGINE_CLASS +import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.logV +import java.util.concurrent.atomic.AtomicReference + +abstract class PmsHookTargetBase(protected val service: HMAService) : IFrameworkHook { + @Suppress("PropertyName") + abstract val TAG: String + + protected var lastFilteredApp: AtomicReference = AtomicReference(null) + + protected val psPackageInfo by lazy { + try { + Utils.getPackageInfoCompat( + service.pms, + VENDING_PACKAGE_NAME, + PackageManager.GET_SIGNING_CERTIFICATES.toLong(), + 0 + ) + } catch (_: Throwable) { + null + } + } + + abstract val fakeSystemPackageInstallSourceInfo: Any? + abstract val fakeUserPackageInstallSourceInfo: Any? + + override fun load() { + BulkHooker.instance.apply { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + hookAfter( + COMPUTER_ENGINE_CLASS, + "getPackageStates", + ) { param -> + val callingUid = Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookAfter + + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.isHookEnabled(it) } + if (caller != null) { + logD(TAG, "@getPackageStates: incoming query from $caller") + + val result = param.result as ArrayMap<*, *> + val markedToRemove = mutableListOf() + + for (pair in result.entries) { + val value = pair.value + val packageName = Utils4Zygote.callMethod(value, "getPackageName") as String + if (service.shouldHide(caller, packageName)) { + markedToRemove.add(pair.key) + } + } + + if (markedToRemove.isNotEmpty()) { + val copyResult = ArrayMap(result) + copyResult.removeAll(markedToRemove) + logD(TAG, "@getPackageStates: removed ${markedToRemove.size} entries from $caller") + param.result = copyResult + service.increasePMFilterCount(caller) + } + } + } + + hookBefore( + COMPUTER_ENGINE_CLASS, + "addPackageHoldingPermissions", + ) { param -> + val callingUid = Binder.getCallingUid() + val packageState = param.args!![2] ?: return@hookBefore + val targetApp = Utils4Zygote.callMethod(packageState, "getPackageName") as String? ?: return@hookBefore + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@addPackageHoldingPermissions caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@addPackageHoldingPermissions caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + COMPUTER_ENGINE_CLASS, + "isCallerInstallerOfRecord", + ) { param -> + val pkg = param.args?.get(1) ?: return@hookBefore + val query = Utils4Zygote.callMethod(pkg, "getPackageName") as String + + val callingUid = param.args.last { it is Int } as Int + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingHandle = UserHandle.getUserHandleForUid(callingUid) + + for (caller in callingApps) { + when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = callingUid == psPackageInfo?.applicationInfo?.uid + Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = false + else -> continue + } + + service.increaseInstallerFilterCount(caller) + break + } + } + + hookBefore( + COMPUTER_ENGINE_CLASS, + "getPackageInfoInternal", + ) { param -> + val targetApp = param.args?.firstOrNull { it is String } as? String ?: return@hookBefore + val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + + hookBefore( + COMPUTER_ENGINE_CLASS, + "getApplicationInfoInternal", + ) { param -> + val targetApp = param.args?.firstOrNull { it is String } as? String ?: return@hookBefore + val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + } + + if (service.pmn != null) { + hookBefore( + service::pmn::class.java.name, + "getInstallerForPackage", + ) { param -> + val query = param.args?.get(1) as? String ?: return@hookBefore + + val callingUid = Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingHandle = UserHandle.getUserHandleForUid(callingUid) + + for (caller in callingApps) { + when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME + Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = "preload" + else -> continue + } + + service.increaseInstallerFilterCount(caller) + break + } + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + hookBefore( + service::pms::class.java.name, + "getInstallSourceInfo", + ) { param -> + val query = param.args?.get(1) as? String ?: return@hookBefore + + val callingUid = Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingHandle = UserHandle.getUserHandleForUid(callingUid) + + for (caller in callingApps) { + when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = fakeUserPackageInstallSourceInfo + Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = fakeSystemPackageInstallSourceInfo + else -> continue + } + + service.increaseInstallerFilterCount(caller) + break + } + } + } + + hookBefore( + service::pms::class.java.name, + "getInstallerPackageName", + ) { param -> + val query = param.args?.get(1) as? String ?: return@hookBefore + + val callingUid = Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingHandle = UserHandle.getUserHandleForUid(callingUid) + + for (caller in callingApps) { + when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME + Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null + else -> continue + } + + service.increaseInstallerFilterCount(caller) + break + } + } + } + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt new file mode 100644 index 000000000..922d6883f --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -0,0 +1,56 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import android.content.Intent +import android.os.Build +import android.os.Bundle +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.logI + +class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { + val TAG = "PmsPackageEventsHook" + + override fun load() { + logI(TAG, "Load hook") + + BulkHooker.instance.apply { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + hookBefore( + "com.android.server.pm.BroadcastHelper", + "sendPackageBroadcastAndNotify", + ) { param -> + service.handlePackageEvent( + param.args!![1] as String?, + param.args[2] as String?, + param.args[3] as Bundle?, + ) + } + + hookBefore( + "com.android.internal.content.PackageMonitor", + "onReceive", + ) { param -> + val intent = param.args?.get(2) as Intent? ?: return@hookBefore + + service.handlePackageEvent( + intent.action, + intent.data?.encodedSchemeSpecificPart, + intent.extras, + ) + } + } else { + hookBefore( + PACKAGE_MANAGER_SERVICE_CLASS, + "sendPackageBroadcast", + ) { param -> + service.handlePackageEvent( + param.args!![1] as String?, + param.args[2] as String?, + param.args[3] as Bundle?, + ) + } + } + } + } +} \ No newline at end of file diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt new file mode 100644 index 000000000..842c7b962 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -0,0 +1,39 @@ +package org.frknkrc44.hma_oss.zygote.hook + +import icu.nullptr.hidemyapplist.common.Constants +import org.frknkrc44.hma_oss.zygote.BulkHooker +import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ZYGOTE_PROCESS_CLASS +import org.frknkrc44.hma_oss.zygote.logD + +class ZygoteHook(private val service: HMAService) : IFrameworkHook { + companion object { + const val TAG = "ZygoteHook" + } + + override fun load() { + BulkHooker.instance.hookBefore( + ZYGOTE_PROCESS_CLASS, + "start", + ) { param -> + logD(TAG, "@startZygoteProcess: Starting ${param.args.contentToString()}") + + // ignore if the GIDs array is null + val gIDsIndex = param.args!!.indexOfFirst { it is IntArray } + if (gIDsIndex < 0) return@hookBefore + + val caller = param.args.lastOrNull { it is String } as String? ?: return@hookBefore + var perms = service.getRestrictedZygotePermissions(caller) ?: return@hookBefore + if (perms.isNotEmpty()) { + val gIDs = param.args[gIDsIndex] as IntArray + + // add more security, reject if not available in GID_PAIRS + perms = perms.filter { Constants.GID_PAIRS.containsValue(it) } + + logD(TAG, "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now") + param.args[gIDsIndex] = gIDs.filter { it !in perms }.toIntArray() + service.increaseOthersFilterCount(caller) + } + } + } +} From 22e6e40e2e64f6ab4b93070759846d9fabe409b1 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 01:00:09 +0300 Subject: [PATCH 002/162] Remove unload --- gradle/libs.versions.toml | 2 +- .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 37 +------------------ .../frknkrc44/hma_oss/zygote/HMAService.kt | 20 ++-------- .../zygote/hook/AppDataIsolationHook.kt | 1 - .../hma_oss/zygote/hook/IFrameworkHook.kt | 3 -- .../hma_oss/zygote/hook/PlatformCompatHook.kt | 1 - 6 files changed, 5 insertions(+), 59 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7b251f920..40c4ea4f2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.0" -androidvmtools = "85bc140b50" +androidvmtools = "753a955da1" zygoteloader = "bf5078e182" [plugins] diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 645697141..390ff86d8 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -154,12 +154,11 @@ class BulkHooker private constructor() { if (BuildConfig.DEBUG) { logI(TAG, "Hooked: $executable") } - val invoker = Hooks.hook( + Hooks.hook( executable, Hooks.EntryPointType.DIRECT, element.impl, Hooks.EntryPointType.DIRECT ) - element.unhooks.add(Unhook(executable, invoker)) element.applyCount++ } } @@ -186,48 +185,14 @@ class BulkHooker private constructor() { } } - fun unhook(element: HookElement) { - for (unhook in element.unhooks) { - unhook.unhook() - } - - element.unhooks.clear() - } - - fun unhookAll() { - // TODO: Not working yet, find a way to implement unhook properly - /* - for (entry in hooks.entries) { - for (element in entry.value) { - unhook(element) - } - } - - hooks.clear() - */ - } - data class HookElement( val impl: HookTransformer, - val unhooks: MutableList = mutableListOf(), val pattern: String, val hookFirst: Boolean, val paramCount: Int = -1, var applyCount: Int = 0, ) - class Unhook(private val backup: Executable, private val invoker: Executable) { - fun unhook() { - // TODO: Not working yet, find a way to implement unhook properly - Hooks.hookSwap( - backup, - Hooks.EntryPointType.DIRECT, - invoker, - Hooks.EntryPointType.DIRECT, - ) - } - } - class ReturnValue(initialValue: Any? = null) { var replace: Boolean = false private set diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 8a0b47314..b28d1ffda 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -440,24 +440,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun stopService(cleanEnv: Boolean) { - // It is an unimplemented method - if (true) return + if (!cleanEnv) return - logI(TAG, "Stop service") - synchronized(loggerLock) { - logcatAvailable = false - } - synchronized(configLock) { - frameworkHooks.forEach(IFrameworkHook::unload) - frameworkHooks.clear() - BulkHooker.instance.unhookAll() - if (cleanEnv) { - logI(TAG, "Clean runtime environment") - File(dataDir).deleteRecursively() - return - } - } - instance = null + logI(TAG, "Clean runtime environment") + File(dataDir).deleteRecursively() } fun addLog(parsedMsg: String) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index a2a9ec9f2..167cac40c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -143,7 +143,6 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { if (!fuseEnabled) { logE(TAG, "StorageManagerService - FUSE storage is not enabled, disable hooks") - unload() return@hookBefore } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt index 26907c51a..4dcd243bb 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt @@ -3,8 +3,5 @@ package org.frknkrc44.hma_oss.zygote.hook interface IFrameworkHook { fun load() - fun unload() { - // TODO: Find a way to unload - } fun onConfigChanged() {} } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index d249a9b9d..29b8d33a7 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -47,7 +47,6 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { } }.onFailure { logE(TAG, "Fatal error occurred, disable hooks", it) - unload() } } } From 23321ab0fa66db19663622e5e0019dea7bd4d5ad Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 01:03:29 +0300 Subject: [PATCH 003/162] Improve AppDataIsolationHook --- .../frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 167cac40c..81d5e9e52 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -138,11 +138,12 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { STORAGE_MANAGER_SERVICE_CLASS, "onVolumeStateChangedLocked", ) { param -> - if (service.config.altVoldAppDataIsolation) { + if (service.config.altVoldAppDataIsolation && !voldHookSkipped) { val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) if (!fuseEnabled) { - logE(TAG, "StorageManagerService - FUSE storage is not enabled, disable hooks") + logE(TAG, "StorageManagerService - FUSE storage is not enabled, skip vold hook") + voldHookSkipped = true return@hookBefore } @@ -167,7 +168,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { STORAGE_MANAGER_SERVICE_CLASS, "remountAppStorageDirs", ) { param -> - if (service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { + if (!voldHookSkipped && service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val pidPkgMap = param.args!![1] as java.util.Map<*, *> val userId = param.args[2] as Int From 384c65e2242b67e2a9009ef9083752078c57db11 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 06:58:51 +0300 Subject: [PATCH 004/162] Use class check for hookedMethod --- .../org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 35f5d11da..52810865b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -21,13 +21,13 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { ACCESSIBILITY_SERVICE_CLASS, "getInstalledAccessibilityServiceList", dumpArgs = false, - ) { param -> hookedMethod(param, true) } + ) { param -> hookedMethod(param) } hookBefore( ACCESSIBILITY_SERVICE_CLASS, "getEnabledAccessibilityServiceList", dumpArgs = false, - ) { param -> hookedMethod(param, false) } + ) { param -> hookedMethod(param) } hookBefore( ACCESSIBILITY_SERVICE_CLASS, @@ -49,7 +49,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { private fun callerIsSpoofed(caller: String) = service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) - private fun hookedMethod(param: BulkHooker.HookParam, returnParcel: Boolean) { + private fun hookedMethod(param: BulkHooker.HookParam) { try { val callingApps = Utils4Zygote.getCallingApps(service) if (callingApps.isEmpty()) return @@ -60,6 +60,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { logD(TAG, "@${param.methodName} returned empty list for ${callingApps.contentToString()}") + val returnParcel = param.frame.type().returnType().javaClass == ParceledListSlice::class.java param.result = if (returnParcel) { ParceledListSlice(returnedList) } else { From f32b8c46591e5ddf3f3cef2b0b005b243831a04d Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 07:56:51 +0300 Subject: [PATCH 005/162] Improve the argument handling --- zygote/build.gradle.kts | 1 + zygote/proguard-rules.pro | 5 +- .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 71 +++++-------------- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 53 +++++++++----- .../hma_oss/zygote/hook/AccessibilityHook.kt | 3 - .../hma_oss/zygote/hook/ActivityHook.kt | 4 +- .../zygote/hook/AppDataIsolationHook.kt | 6 +- .../zygote/hook/ContentProviderHook.kt | 8 +-- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 16 ++--- .../hma_oss/zygote/hook/PlatformCompatHook.kt | 4 +- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 12 ++-- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 14 ++-- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 18 ++--- .../hma_oss/zygote/hook/PmsHookTarget33.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 8 +-- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 14 ++-- .../zygote/hook/PmsPackageEventsHook.kt | 14 ++-- .../hma_oss/zygote/hook/ZygoteHook.kt | 4 +- 18 files changed, 118 insertions(+), 143 deletions(-) diff --git a/zygote/build.gradle.kts b/zygote/build.gradle.kts index 70f10ccc5..467ed1210 100644 --- a/zygote/build.gradle.kts +++ b/zygote/build.gradle.kts @@ -13,6 +13,7 @@ android { defaultConfig { applicationId = namespace + multiDexEnabled = false } } diff --git a/zygote/proguard-rules.pro b/zygote/proguard-rules.pro index 614ce8411..be6b5a79d 100644 --- a/zygote/proguard-rules.pro +++ b/zygote/proguard-rules.pro @@ -20,9 +20,10 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --keep class org.frknkrc44.hma_oss.zygote.ZygoteEntry { main(); } +-keep class org.frknkrc44.hma_oss.zygote.ZygoteEntry { premain(); main(); } +-keep class org.frknkrc44.hma_oss.zygote.** +-keep class org.frknkrc44.hma_oss.zygote.hook.** -dontwarn android.content.pm.IPackageManager -dontwarn android.content.pm.ParceledListSlice -dontwarn android.os.SystemProperties -dontwarn com.v7878.r8.annotations.KeepCodeAttribute --keep class org.frknkrc44.hma_oss.zygote.** \ No newline at end of file diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 390ff86d8..09b82bfcf 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -14,7 +14,6 @@ import java.lang.reflect.Executable import java.util.regex.Pattern import java.util.stream.Stream - class BulkHooker private constructor() { companion object { val instance: BulkHooker by lazy { BulkHooker() } @@ -23,10 +22,6 @@ class BulkHooker private constructor() { private val hooks: MutableMap> = HashMap>() - fun findHookElement(clazz: String, methodName: String) = hooks[clazz]?.first { - it.pattern == String.format("%s\\(.*\\).*", Pattern.quote(methodName)) - } - private fun addPattern(clazz: String, pattern: String, hookFirst: Boolean, paramCount: Int, impl: HookTransformer) { hooks.computeIfAbsent(clazz) { _ -> mutableListOf() } .add(HookElement( @@ -50,28 +45,22 @@ class BulkHooker private constructor() { internal fun hookBefore( clazz: String, methodName: String, - dumpArgs: Boolean = true, autoApply: Boolean = true, hookFirst: Boolean = true, paramCount: Int = -1, hook: (param: HookParam) -> Unit, ) { addAll(clazz, methodName, hookFirst, paramCount) { original, frame -> - val args = if (dumpArgs) Utils4Zygote.dumpArgs(frame) else null val value = ReturnValue() runCatching { - hook(HookParam(clazz, original, frame, methodName, args, value)) + hook(HookParam(clazz, original, frame, methodName, value)) }.onFailure { logE(TAG, it.message ?: "Unknown error on hook", it) } if (!value.replace) { - if (!dumpArgs) { - Transformers.invokeExact(original, frame) - } else { - value.value = original.invokeWithArguments(*args!!) - } + Transformers.invokeExact(original, frame) } if (value.replace && frame.type().returnType() != Void::class.java) { @@ -87,7 +76,6 @@ class BulkHooker private constructor() { internal fun hookAfter( clazz: String, methodName: String, - dumpArgs: Boolean = true, autoApply: Boolean = true, hookFirst: Boolean = true, paramCount: Int = -1, @@ -102,14 +90,13 @@ class BulkHooker private constructor() { throwable = it } - val args = if (dumpArgs) Utils4Zygote.dumpArgs(frame) else null val value = ReturnValue(if (throwable == null) { frame.accessor().getValue(RETURN_VALUE_IDX) } else null) value.throwable = throwable runCatching { - hook(HookParam(clazz, original, frame, methodName, args, value)) + hook(HookParam(clazz, original, frame, methodName, value)) }.onFailure { logE(TAG, it.message ?: "Unknown error on hook", it) } @@ -211,14 +198,6 @@ class BulkHooker private constructor() { val original: MethodHandle, val frame: EmulatedStackFrame, val methodName: String, - - /** - * - `args[0] == thisObject` - * - `args[1:] == function args` - * - * Note that this variable is null when `dumpArgs == false` - */ - val args: Array?, val returnValue: ReturnValue, ) { var result: Any? @@ -226,40 +205,24 @@ class BulkHooker private constructor() { set(newValue) { returnValue.value = newValue } /** - * Returns the first argument, can throw an exception when `dumpArgs == false` + * Returns the first argument */ - val thisObject get() = args?.first()!! - - var throwable: Throwable? - get() = returnValue.throwable - set(newValue) { returnValue.throwable = newValue } + val thisObject by lazy { Utils4Zygote.getArgument(frame, 0) } - // -- BEGIN OF GENERATED FUNCTIONS -- - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false + fun getArgument(index: Int) = Utils4Zygote.getArgument(frame, index) - other as HookParam + fun setArgument(index: Int, value: Any) = Utils4Zygote.setArgument(frame, index, value) - if (clazz != other.clazz) return false - if (original != other.original) return false - if (frame != other.frame) return false - if (methodName != other.methodName) return false - if (!args.contentEquals(other.args)) return false - if (returnValue != other.returnValue) return false - - return true - } + /** + * - `args[0] == thisObject` + * - `args[1:] == function args` + * + * Note that this variable is null when `dumpArgs == false` + */ + val args by lazy { Utils4Zygote.dumpArgs(frame) } - override fun hashCode(): Int { - var result1 = clazz.hashCode() - result1 = 31 * result1 + original.hashCode() - result1 = 31 * result1 + frame.hashCode() - result1 = 31 * result1 + methodName.hashCode() - result1 = 31 * result1 + (args?.contentHashCode() ?: 0) - result1 = 31 * result1 + returnValue.hashCode() - return result1 - } - // -- END OF GENERATED FUNCTIONS -- + var throwable: Throwable? + get() = returnValue.throwable + set(newValue) { returnValue.throwable = newValue } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index c0941c5e0..61f142ed4 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -21,29 +21,48 @@ import java.util.regex.Pattern object Utils4Zygote { fun dumpArgs(frame: EmulatedStackFrame): Array { return mutableListOf().let { - for (i in 0 ..< frame.type().parameterCount()) { - val accessor = frame.accessor() - - it.add( - when (accessor.getArgumentShorty(i)) { - 'L' -> accessor.getReference(i) - 'Z' -> accessor.getBoolean(i) - 'B' -> accessor.getByte(i) - 'C' -> accessor.getChar(i) - 'S' -> accessor.getShort(i) - 'I' -> accessor.getInt(i) - 'J' -> accessor.getLong(i) - 'F' -> accessor.getFloat(i) - 'D' -> accessor.getDouble(i) - else -> throw Exception("Should not reach here") - } - ) + for (index in 0 ..< frame.type().parameterCount()) { + it.add(getArgument(frame, index)) } it.toTypedArray() } } + fun getArgument(frame: EmulatedStackFrame, index: Int): Any { + val accessor = frame.accessor() + + return when (accessor.getArgumentShorty(index)) { + 'L' -> accessor.getReference(index) + 'Z' -> accessor.getBoolean(index) + 'B' -> accessor.getByte(index) + 'C' -> accessor.getChar(index) + 'S' -> accessor.getShort(index) + 'I' -> accessor.getInt(index) + 'J' -> accessor.getLong(index) + 'F' -> accessor.getFloat(index) + 'D' -> accessor.getDouble(index) + else -> throw Exception("Should not reach here") + } + } + + fun setArgument(frame: EmulatedStackFrame, index: Int, value: Any) { + val accessor = frame.accessor() + + when (accessor.getArgumentShorty(index)) { + 'L' -> accessor.setReference(index, value) + 'Z' -> accessor.setBoolean(index, value as Boolean) + 'B' -> accessor.setByte(index, value as Byte) + 'C' -> accessor.setChar(index, value as Char) + 'S' -> accessor.setShort(index, value as Short) + 'I' -> accessor.setInt(index, value as Int) + 'J' -> accessor.setLong(index, value as Long) + 'F' -> accessor.setFloat(index, value as Float) + 'D' -> accessor.setDouble(index, value as Double) + else -> throw Exception("Should not reach here") + } + } + fun filter(pattern: String): Predicate { val compiledPattern = Pattern.compile(pattern) return Predicate { executable: Executable? -> diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 52810865b..d1890cffe 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -20,19 +20,16 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { hookBefore( ACCESSIBILITY_SERVICE_CLASS, "getInstalledAccessibilityServiceList", - dumpArgs = false, ) { param -> hookedMethod(param) } hookBefore( ACCESSIBILITY_SERVICE_CLASS, "getEnabledAccessibilityServiceList", - dumpArgs = false, ) { param -> hookedMethod(param) } hookBefore( ACCESSIBILITY_SERVICE_CLASS, "addClient", - dumpArgs = false, ) { param -> val callingApps = Utils4Zygote.getCallingApps(service) if (callingApps.isEmpty()) return@hookBefore diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index 703e08c0a..f57a11b3c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -98,7 +98,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { "applyPostResolutionFilter", ) { param -> @Suppress("UNCHECKED_CAST") // I know what I do - val list = param.args?.get(1) as List? + val list = param.args[1] as List? if (list.isNullOrEmpty()) return@hookBefore val callingUid = param.args.first { it is Int } as Int @@ -122,7 +122,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { } if (filteredList.size != list.size) { - param.args[1] = filteredList.toList() + param.setArgument(1, filteredList.toList()) service.increasePMFilterCount(caller) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 81d5e9e52..3a8cfbd80 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -85,7 +85,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { "needsStorageDataIsolation", ) { param -> if (service.config.altVoldAppDataIsolation) { - val app = param.args!!.find { it?.javaClass?.simpleName == "ProcessRecord" }!! + val app = param.args.find { it?.javaClass?.simpleName == "ProcessRecord" }!! val uid = getIntField(app, "uid") val processName = runCatching { getObjectField(app, "processName") @@ -170,8 +170,8 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { ) { param -> if (!voldHookSkipped && service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - val pidPkgMap = param.args!![1] as java.util.Map<*, *> - val userId = param.args[2] as Int + val pidPkgMap = param.getArgument(1) as java.util.Map<*, *> + val userId = param.getArgument(2) as Int val keysToRemove = mutableSetOf() diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index b10622ab6..1d724a7c1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -31,7 +31,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller == null) return@hookAfter - val uriIdx = param.args?.indexOfFirst { it is Uri } ?: return@hookAfter + val uriIdx = param.args.indexOfFirst { it is Uri } val uri = param.args[uriIdx] as Uri val projection = param.args[uriIdx + 1] as Array? val args = param.args[uriIdx + 2] as Bundle? @@ -129,7 +129,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller == null) return@hookBefore - val nameIdx = param.args?.indexOfLast { it is String } ?: return@hookBefore + val nameIdx = param.args.indexOfLast { it is String } val name = param.args[nameIdx] as String? val method = param.args[nameIdx - 1] as String? @@ -156,10 +156,10 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { private fun getCallingPackages(param: BulkHooker.HookParam) = try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val attrSource = param.args!!.first { it is AttributionSource } as AttributionSource + val attrSource = param.args.first { it is AttributionSource } as AttributionSource arrayOf(attrSource.packageName) } else { - arrayOf(param.args!!.first { it is String } as String) + arrayOf(param.args.first { it is String } as String) } } catch (_: Throwable) { Utils4Zygote.getCallingApps(service) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 8893ed253..855c170e6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -64,8 +64,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { hookBefore( IMM_SERVICE_CLASS, "getCurrentInputMethodInfoAsUser", - dumpArgs = false, - ) { param -> + ) { param -> val callingApps = Utils4Zygote.getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } @@ -84,7 +83,6 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { "getInputMethodListInternal" else "getInputMethodList", - dumpArgs = Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA, ) { param -> listHook(param) } @@ -95,7 +93,6 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { "getEnabledInputMethodListInternal" else "getEnabledInputMethodList", - dumpArgs = Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA, ) { param -> listHook(param) } @@ -103,16 +100,14 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { hookBefore( IMM_SERVICE_CLASS, "getCurrentInputMethodSubtype", - dumpArgs = false, - ) { param -> + ) { param -> subtypeHook(param) } hookBefore( IMM_SERVICE_CLASS, "getLastInputMethodSubtype", - dumpArgs = false, - ) { param -> + ) { param -> subtypeHook(param) } @@ -122,8 +117,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { "getEnabledInputMethodSubtypeListInternal" else "getEnabledInputMethodSubtypeList", - dumpArgs = false, - ) { param -> + ) { param -> subtypeListHook(param) } } @@ -131,7 +125,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { private fun listHook(param: BulkHooker.HookParam) { val callingApps = if (param.methodName.endsWith("Internal")) { - val callingUid = param.args?.findLast { it is Int } as Int + val callingUid = param.args.findLast { it is Int } as Int Utils4Zygote.getCallingApps(service, callingUid) } else { Utils4Zygote.getCallingApps(service) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index 29b8d33a7..d44c5b964 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -35,10 +35,10 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { runCatching { if (!sAppDataIsolationEnabled) return@hookBefore - val changeId = param.args!![1] as Long + val changeId = param.getArgument(1) as Long if (changeId != 143937733L) return@hookBefore - val appInfo = param.args[2] as ApplicationInfo + val appInfo = param.getArgument(2) as ApplicationInfo val app = appInfo.packageName if (app == BuildConfig.APP_PACKAGE_NAME || app in service.systemApps) return@hookBefore if (service.isHookEnabled(app)) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index fd1bb41fd..5c8575f3e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -28,9 +28,9 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { "filterAppAccessLPr", paramCount = 5, ) { param -> - val callingUid = param.args!![2] as Int + val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val packageSettings = param.args[1] ?: return@hookBefore + val packageSettings = param.getArgument(1) val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(packageSettings) if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true @@ -56,8 +56,8 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.args!![1] as String? ?: return@hookBefore - val callingUid = param.args[4] as Int + val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { @@ -80,8 +80,8 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.args!![1] as String? ?: return@hookBefore - val callingUid = param.args[3] as Int + val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 3b945189d..258ade1e8 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -53,7 +53,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getPackageSetting", ) { param -> - val targetApp = param.args!![1] as String + val targetApp = param.getArgument(1) as String val callingUid = Binder.getCallingUid() if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null @@ -75,9 +75,9 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { APPS_FILTER_CLASS, "shouldFilterApplication", ) { param -> - val callingUid = param.args!![1] as Int + val callingUid = param.getArgument(1) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[3]!!) + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(3)) if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) @@ -102,8 +102,8 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.args?.get(1) as String? ?: return@hookBefore - val callingUid = param.args[4] as Int + val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { @@ -126,8 +126,8 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.args?.get(1) as String? ?: return@hookBefore - val callingUid = param.args[3] as Int + val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index 4db19dee2..2cf0a42dd 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -53,7 +53,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getPackageSetting", ) { param -> - val targetApp = param.args?.get(1) as String + val targetApp = param.getArgument(1) as String val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore if (service.shouldHideFromUid(callingUid, targetApp) == true) { @@ -76,8 +76,8 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getPackageSettingInternal", ) { param -> - val targetApp = param.args!![1] as String - val callingUid = param.args[2] as Int + val targetApp = param.getArgument(1) as String + val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null @@ -99,8 +99,8 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.args?.get(1) as String? ?: return@hookBefore - val callingUid = param.args[4] as Int + val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { @@ -123,8 +123,8 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.args?.get(1) as String? ?: return@hookBefore - val callingUid = param.args[3] as Int + val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { @@ -149,9 +149,9 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { ) { param -> logV(TAG, "@shouldFilterApplication call: ${param.args.contentToString()}") - val callingUid = param.args!![1] as Int + val callingUid = param.getArgument(1) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[3]!!) + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(3)) if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index 7e4c35d17..141e962d3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -65,16 +65,16 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { APPS_FILTER_IMPL_CLASS, "shouldFilterApplication", ) { param -> - val callingUid = param.args!![2] as Int + val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[4]!!) // PackageSettings <- PackageStateInternal + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(4)) // PackageSettings <- PackageStateInternal if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") return@hookBefore } - val snapshot = param.args[0] + val snapshot = param.getArgument(1) val callingApps = Utils.binderLocalScope { getPackagesForUidMethod.invoke(snapshot, callingUid) as Array? } ?: return@hookBefore diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 8cc34b278..41e5b49bc 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -69,16 +69,16 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { APPS_FILTER_IMPL_CLASS, "shouldFilterApplication", ) { param -> - val callingUid = param.args!![2] as Int + val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.args[4]!!) // PackageSettings <- PackageStateInternal + val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(4)) // PackageSettings <- PackageStateInternal if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") return@hookBefore } - val snapshot = param.args[1] + val snapshot = param.getArgument(1) val callingApps = Utils.binderLocalScope { getPackagesForUidMethod.invoke(snapshot, callingUid) as Array? } ?: return@hookBefore @@ -101,7 +101,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { ) { param -> val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.args!![1].toString() + val targetApp = param.getArgument(1).toString() if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index f9fa0a623..449f8a4f6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -79,7 +79,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework "addPackageHoldingPermissions", ) { param -> val callingUid = Binder.getCallingUid() - val packageState = param.args!![2] ?: return@hookBefore + val packageState = param.getArgument(2) val targetApp = Utils4Zygote.callMethod(packageState, "getPackageName") as String? ?: return@hookBefore if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null @@ -101,7 +101,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "isCallerInstallerOfRecord", ) { param -> - val pkg = param.args?.get(1) ?: return@hookBefore + val pkg = param.args[1] ?: return@hookBefore val query = Utils4Zygote.callMethod(pkg, "getPackageName") as String val callingUid = param.args.last { it is Int } as Int @@ -126,7 +126,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.args?.firstOrNull { it is String } as? String ?: return@hookBefore + val targetApp = param.args.firstOrNull { it is String } as? String ?: return@hookBefore val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") @@ -150,7 +150,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.args?.firstOrNull { it is String } as? String ?: return@hookBefore + val targetApp = param.args.firstOrNull { it is String } as? String ?: return@hookBefore val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") @@ -176,7 +176,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service::pmn::class.java.name, "getInstallerForPackage", ) { param -> - val query = param.args?.get(1) as? String ?: return@hookBefore + val query = param.getArgument(1) as? String ?: return@hookBefore val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore @@ -202,7 +202,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service::pms::class.java.name, "getInstallSourceInfo", ) { param -> - val query = param.args?.get(1) as? String ?: return@hookBefore + val query = param.getArgument(1) as? String ?: return@hookBefore val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore @@ -227,7 +227,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service::pms::class.java.name, "getInstallerPackageName", ) { param -> - val query = param.args?.get(1) as? String ?: return@hookBefore + val query = param.getArgument(1) as? String ?: return@hookBefore val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index 922d6883f..9a43526a0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -21,9 +21,9 @@ class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { "sendPackageBroadcastAndNotify", ) { param -> service.handlePackageEvent( - param.args!![1] as String?, - param.args[2] as String?, - param.args[3] as Bundle?, + param.getArgument(1) as String?, + param.getArgument(2) as String?, + param.getArgument(3) as Bundle?, ) } @@ -31,7 +31,7 @@ class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { "com.android.internal.content.PackageMonitor", "onReceive", ) { param -> - val intent = param.args?.get(2) as Intent? ?: return@hookBefore + val intent = param.getArgument(2) as Intent? ?: return@hookBefore service.handlePackageEvent( intent.action, @@ -45,9 +45,9 @@ class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { "sendPackageBroadcast", ) { param -> service.handlePackageEvent( - param.args!![1] as String?, - param.args[2] as String?, - param.args[3] as Bundle?, + param.getArgument(1) as String?, + param.getArgument(2) as String?, + param.getArgument(3) as Bundle?, ) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index 842c7b962..843d89835 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -19,7 +19,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { logD(TAG, "@startZygoteProcess: Starting ${param.args.contentToString()}") // ignore if the GIDs array is null - val gIDsIndex = param.args!!.indexOfFirst { it is IntArray } + val gIDsIndex = param.args.indexOfFirst { it is IntArray } if (gIDsIndex < 0) return@hookBefore val caller = param.args.lastOrNull { it is String } as String? ?: return@hookBefore @@ -31,7 +31,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { perms = perms.filter { Constants.GID_PAIRS.containsValue(it) } logD(TAG, "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now") - param.args[gIDsIndex] = gIDs.filter { it !in perms }.toIntArray() + param.setArgument(gIDsIndex, gIDs.filter { it !in perms }.toIntArray()) service.increaseOthersFilterCount(caller) } } From 6d2852b1d84d86e072233046c1945fa8033a7139 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 08:17:21 +0300 Subject: [PATCH 006/162] Fix some package manager hooks --- zygote/proguard-rules.pro | 4 ++-- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/zygote/proguard-rules.pro b/zygote/proguard-rules.pro index be6b5a79d..f01fbf89c 100644 --- a/zygote/proguard-rules.pro +++ b/zygote/proguard-rules.pro @@ -21,8 +21,8 @@ #-renamesourcefileattribute SourceFile -keep class org.frknkrc44.hma_oss.zygote.ZygoteEntry { premain(); main(); } --keep class org.frknkrc44.hma_oss.zygote.** --keep class org.frknkrc44.hma_oss.zygote.hook.** +-keep class org.frknkrc44.hma_oss.zygote.** { *; } +-keep class org.frknkrc44.hma_oss.zygote.hook.** { *; } -dontwarn android.content.pm.IPackageManager -dontwarn android.content.pm.ParceledListSlice -dontwarn android.os.SystemProperties diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 449f8a4f6..fa0c9b995 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -173,7 +173,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (service.pmn != null) { hookBefore( - service::pmn::class.java.name, + service.pmn.javaClass.name, "getInstallerForPackage", ) { param -> val query = param.getArgument(1) as? String ?: return@hookBefore @@ -199,7 +199,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { hookBefore( - service::pms::class.java.name, + service.pms.javaClass.name, "getInstallSourceInfo", ) { param -> val query = param.getArgument(1) as? String ?: return@hookBefore @@ -224,7 +224,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework } hookBefore( - service::pms::class.java.name, + service.pms.javaClass.name, "getInstallerPackageName", ) { param -> val query = param.getArgument(1) as? String ?: return@hookBefore From 5768c32f4c1ebdd3c7d1edd85ad9d885f219b46f Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 08:29:10 +0300 Subject: [PATCH 007/162] Enable multidex back, remove not required R8 rules --- zygote/build.gradle.kts | 1 - zygote/proguard-rules.pro | 2 -- 2 files changed, 3 deletions(-) diff --git a/zygote/build.gradle.kts b/zygote/build.gradle.kts index 467ed1210..70f10ccc5 100644 --- a/zygote/build.gradle.kts +++ b/zygote/build.gradle.kts @@ -13,7 +13,6 @@ android { defaultConfig { applicationId = namespace - multiDexEnabled = false } } diff --git a/zygote/proguard-rules.pro b/zygote/proguard-rules.pro index f01fbf89c..8ac893e42 100644 --- a/zygote/proguard-rules.pro +++ b/zygote/proguard-rules.pro @@ -21,8 +21,6 @@ #-renamesourcefileattribute SourceFile -keep class org.frknkrc44.hma_oss.zygote.ZygoteEntry { premain(); main(); } --keep class org.frknkrc44.hma_oss.zygote.** { *; } --keep class org.frknkrc44.hma_oss.zygote.hook.** { *; } -dontwarn android.content.pm.IPackageManager -dontwarn android.content.pm.ParceledListSlice -dontwarn android.os.SystemProperties From 2f292c8ed9d00fd1b7ed1c8760a5011206694658 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 08:49:02 +0300 Subject: [PATCH 008/162] Return back to getDeclaredMethod --- .../org/frknkrc44/hma_oss/zygote/SystemServerHook.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt index 2e1b4e7de..d335c00de 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt @@ -3,6 +3,7 @@ package org.frknkrc44.hma_oss.zygote import android.annotation.SuppressLint import android.content.pm.IPackageManager import com.v7878.r8.annotations.DoNotShrink +import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.Hooks @@ -48,17 +49,14 @@ object SystemServerHook { } } - @SuppressLint("PrivateApi") @DoNotShrink @Throws(Throwable::class) @JvmStatic fun init() { - val method = Utils4Zygote.findMethod( - RUNTIME_INIT, "findStaticMain", true, false, + val method = getDeclaredMethod( + Class.forName(RUNTIME_INIT), "findStaticMain", String::class.java, Array::class.java, ClassLoader::class.java - ).apply { - Hooks.deoptimize(this@apply) - } + ) Hooks.hook(method, Hooks.EntryPointType.CURRENT, { original, frame -> try { From 0f2104ee11607871c6c26cf913230ab6d090cb70 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 09:05:53 +0300 Subject: [PATCH 009/162] Fix accessibility hook --- .../java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index d1890cffe..02c8cb781 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -57,7 +57,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { logD(TAG, "@${param.methodName} returned empty list for ${callingApps.contentToString()}") - val returnParcel = param.frame.type().returnType().javaClass == ParceledListSlice::class.java + val returnParcel = param.frame.type().returnType().simpleName.contains("Parcel") param.result = if (returnParcel) { ParceledListSlice(returnedList) } else { From cc2372fba19a1a11d74bf618dcf39158bc28ac8b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 09:38:24 +0300 Subject: [PATCH 010/162] Use "callMethod" for package settings --- .../java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index 61f142ed4..386899a6d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -81,13 +81,8 @@ object Utils4Zygote { return service } - fun getPackageNameFromPackageSettings(packageSettings: Any): String? { - return runCatching { - packageSettings::class.java.getField( - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) "mName" else "name" - ).apply { isAccessible = true }.get(packageSettings) as? String - }.getOrNull() - } + fun getPackageNameFromPackageSettings(packageSettings: Any) = + callMethod(packageSettings, "getPackageName") as String? fun getPackageManager() = ActivityThread.currentActivityThread().application.packageManager!! From df7d9bcc6f0b8d9106e0f3cad9fdca73daf2f77c Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 09:58:06 +0300 Subject: [PATCH 011/162] Add method to find fields correctly --- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index 386899a6d..5ae2303a8 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -12,6 +12,7 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils import java.lang.reflect.Constructor import java.lang.reflect.Executable +import java.lang.reflect.Field import java.lang.reflect.Method import java.lang.reflect.Modifier import java.util.function.Predicate @@ -81,8 +82,18 @@ object Utils4Zygote { return service } - fun getPackageNameFromPackageSettings(packageSettings: Any) = - callMethod(packageSettings, "getPackageName") as String? + fun getPackageNameFromPackageSettings(packageSettings: Any): String? { + return try { + callMethod(packageSettings, "getPackageName") as String? + } catch (_: Throwable) { + runCatching { + findField( + packageSettings::class.java, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) "mName" else "name" + )?.apply { isAccessible = true }?.get(packageSettings) as? String + }.getOrNull() + } + } fun getPackageManager() = ActivityThread.currentActivityThread().application.packageManager!! @@ -138,6 +149,18 @@ object Utils4Zygote { } } + fun findField(clazz: Class<*>, name: String): Field? { + var currentClazz: Class<*> = clazz + var field: Field? = null + + while (field == null && currentClazz.javaClass.simpleName != "Object") { + field = runCatching { currentClazz.getField(name) }.getOrNull() + currentClazz = clazz.superclass.javaClass + } + + return field + } + private fun getClassName(clazz: Class<*>): String { val component = clazz.componentType if (component != null) { From f3282ffc60c084d0775068d5dee030d6f1fd0b17 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 10:48:44 +0300 Subject: [PATCH 012/162] Add app signature verification and reinstall support --- gradle/libs.versions.toml | 1 + zygote/build.gradle.kts | 44 +++++++++++++++++++ .../frknkrc44/hma_oss/zygote/HMAService.kt | 18 ++++++++ .../frknkrc44/hma_oss/zygote/UserService.kt | 25 ++++++++--- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 14 ++++++ 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40c4ea4f2..866b0307c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,6 +28,7 @@ androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fr androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" } androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version = "1.2.1" } androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version = "1.2.0" } +com-android-tools-build-apksig = { module = "com.android.tools.build:apksig", version.ref = "agp" } com-github-bumptech-glide = { module = "com.github.bumptech.glide:glide", version = "5.0.5" } dev-androidbroadcast-vbpd = { module = "dev.androidbroadcast.vbpd:vbpd", version.ref = "vbpd" } dev-androidbroadcast-vbpd-reflection = { module = "dev.androidbroadcast.vbpd:vbpd-reflection", version.ref = "vbpd" } diff --git a/zygote/build.gradle.kts b/zygote/build.gradle.kts index 70f10ccc5..10b6a7ae5 100644 --- a/zygote/build.gradle.kts +++ b/zygote/build.gradle.kts @@ -1,4 +1,8 @@ +import com.android.ide.common.signing.KeystoreHelper import com.v7878.zygisk.gradle.ZygoteLoader +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import java.io.PrintStream +import java.util.Locale plugins { alias(libs.plugins.agp.app) @@ -16,6 +20,45 @@ android { } } +afterEvaluate { + android.applicationVariants.forEach { variant -> + val variantCapped = variant.name.replaceFirstChar { it.titlecase(Locale.ROOT) } + val variantLowered = variant.name.lowercase(Locale.ROOT) + + val outSrcDir = layout.buildDirectory.dir("generated/source/signInfo/${variantLowered}") + val outSrc = outSrcDir.get().file("org/frknkrc44/hma_oss/zygote/Magic.java") + val signInfoTask = tasks.register("generate${variantCapped}SignInfo") { + outputs.file(outSrc) + doLast { + val sign = android.buildTypes[variantLowered].signingConfig + outSrc.asFile.parentFile.mkdirs() + val certificateInfo = KeystoreHelper.getCertificateInfo( + sign?.storeType, + sign?.storeFile, + sign?.storePassword, + sign?.keyPassword, + sign?.keyAlias + ) + PrintStream(outSrc.asFile).apply { + println("package org.frknkrc44.hma_oss.zygote;") + println("public final class Magic {") + print("public static final byte[] magicNumbers = {") + val bytes = certificateInfo.certificate.encoded + print(bytes.joinToString(",") { it.toString() }) + println("};") + println("}") + } + } + } + variant.registerJavaGeneratingTask(signInfoTask, outSrcDir.get().asFile) + + val kotlinCompileTask = tasks.findByName("compile${variantCapped}Kotlin") as KotlinCompile + kotlinCompileTask.dependsOn(signInfoTask) + val srcSet = objects.sourceDirectorySet("magic", "magic").srcDir(outSrcDir) + kotlinCompileTask.source(srcSet) + } +} + zygisk { // inject to system_server packages(ZygoteLoader.PACKAGE_SYSTEM_SERVER) @@ -34,6 +77,7 @@ dependencies { implementation(projects.common) implementation(libs.androidx.annotation.jvm) + implementation(libs.com.android.tools.build.apksig) implementation(libs.io.github.vova7878.androidvmtools) implementation(libs.io.github.vova7878.r8annotations) implementation(libs.dev.rikka.hidden.compat) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index b28d1ffda..04e1a5c82 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -16,6 +16,7 @@ import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.PresetCacheHolder import icu.nullptr.hidemyapplist.common.RiskyPackageUtils.appHasGMSConnection import icu.nullptr.hidemyapplist.common.SettingsPresets +import icu.nullptr.hidemyapplist.common.Utils import icu.nullptr.hidemyapplist.common.Utils.binderLocalScope import icu.nullptr.hidemyapplist.common.Utils.generateRandomString import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat @@ -26,6 +27,7 @@ import icu.nullptr.hidemyapplist.common.Utils.removeIf import icu.nullptr.hidemyapplist.common.app_presets.DetectorAppsPreset import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.verifyAppSignature import org.frknkrc44.hma_oss.zygote.hook.AccessibilityHook import org.frknkrc44.hma_oss.zygote.hook.ActivityHook import org.frknkrc44.hma_oss.zygote.hook.AppDataIsolationHook @@ -70,6 +72,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { private val frameworkHooks = mutableSetOf() val executor: ExecutorService = Executors.newSingleThreadExecutor() private val uidHideCache = mutableListOf>>() + internal var appUid = 0 var config = JsonConfig().apply { detailLog = true } private set @@ -531,6 +534,17 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { when (eventType) { Intent.ACTION_PACKAGE_ADDED -> { if (handlePackageAdded(pms, packageName, presetCache)) { + if (packageName == BuildConfig.APP_PACKAGE_NAME) { + val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) + if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { + logI(TAG, "The app signature is verified successfully") + appUid = pkgInfo!!.applicationInfo!!.uid + } else { + logE(TAG, "The app itself is modified, skipping") + appUid = -1 + } + } + writePresetCache() } } @@ -541,6 +555,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } if (handlePackageRemoved(packageName, presetCache)) { + if (packageName == BuildConfig.APP_PACKAGE_NAME) { + appUid = -1 + } + writePresetCache() } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt index 0f27c6464..8abd3e001 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt @@ -6,8 +6,10 @@ import android.os.Build import android.os.Bundle import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils +import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getStaticIntField +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.verifyAppSignature import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.adapter.UidObserverAdapter @@ -15,7 +17,7 @@ object UserService { private const val TAG = "HMA-UserService" - private var appUid = 0 + private val uidObserver = object : UidObserverAdapter() { override fun onUidActive(uid: Int) { @@ -24,7 +26,10 @@ object UserService { return } - if (uid != appUid) return + if (HMAService.instance!!.appUid < 0 || uid != HMAService.instance?.appUid) { + return + } + try { val provider = ActivityManagerApis.getContentProviderExternal(Constants.PROVIDER_AUTHORITY, 0, null, null) assert (provider != null) { @@ -56,17 +61,23 @@ object UserService { val service = HMAService(pms, pmn) try { - appUid = Utils.getPackageUidCompat(service.pms, BuildConfig.APP_PACKAGE_NAME, 0, 0) - assert(appUid >= 0) { + val pkgInfo = getPackageInfoCompat(pms, BuildConfig.APP_PACKAGE_NAME, 0L, 0) + if (pkgInfo != null) { + if (verifyAppSignature(pkgInfo.applicationInfo?.sourceDir)) { + logI(TAG, "The app signature is verified successfully") + service.appUid = pkgInfo.applicationInfo!!.uid + } else { + throw AssertionError("The app itself is modified, skipping") + } + } + assert(service.appUid >= 0) { "App UID cannot be -1 or lower" } + logD(TAG, "Client uid: ${service.appUid}") } catch (e: Throwable) { logE(TAG, "Fatal: Cannot get package details\nCompile this app from source with your changes", e) - return } - logD(TAG, "Client uid: $appUid") - Utils4Zygote.waitForService("activity") ActivityManagerApis.registerUidObserver( uidObserver, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index 5ae2303a8..62e17f631 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -5,11 +5,13 @@ import android.os.Binder import android.os.Build import android.os.IBinder import android.os.ServiceManager +import com.android.apksig.ApkVerifier import com.v7878.unsafe.Reflection.getDeclaredField import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils +import java.io.File import java.lang.reflect.Constructor import java.lang.reflect.Executable import java.lang.reflect.Field @@ -161,6 +163,18 @@ object Utils4Zygote { return field } + fun verifyAppSignature(path: String?): Boolean { + if (path == null) return false + + val verifier = ApkVerifier.Builder(File(path)) + .setMinCheckedPlatformVersion(24) + .build() + val result = verifier.verify() + if (!result.isVerified) return false + val mainCert = result.signerCertificates[0] + return mainCert.encoded.contentEquals(Magic.magicNumbers) + } + private fun getClassName(clazz: Class<*>): String { val component = clazz.componentType if (component != null) { From 961bf54ac9f84b2d44fa08e36ac53197a108a251 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 11:02:22 +0300 Subject: [PATCH 013/162] Improve the signature verification and reinstall support --- .../frknkrc44/hma_oss/zygote/HMAService.kt | 28 ++++++++++--------- .../frknkrc44/hma_oss/zygote/UserService.kt | 4 +-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 04e1a5c82..57f51f015 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -533,18 +533,18 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { AppPresets.instance.apply { when (eventType) { Intent.ACTION_PACKAGE_ADDED -> { - if (handlePackageAdded(pms, packageName, presetCache)) { - if (packageName == BuildConfig.APP_PACKAGE_NAME) { - val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) - if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { - logI(TAG, "The app signature is verified successfully") - appUid = pkgInfo!!.applicationInfo!!.uid - } else { - logE(TAG, "The app itself is modified, skipping") - appUid = -1 - } + if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid < 0) { + val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) + if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { + logI(TAG, "The manager app signature is verified successfully") + appUid = pkgInfo!!.applicationInfo!!.uid + } else { + logE(TAG, "The manager app itself is modified, skipping") + appUid = -1 } + } + if (handlePackageAdded(pms, packageName, presetCache)) { writePresetCache() } } @@ -554,10 +554,12 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { return } + if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid >= 0) { + logI(TAG, "The manager app is uninstalled") + appUid = -1 + } + if (handlePackageRemoved(packageName, presetCache)) { - if (packageName == BuildConfig.APP_PACKAGE_NAME) { - appUid = -1 - } writePresetCache() } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt index 8abd3e001..0722364db 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt @@ -64,10 +64,10 @@ object UserService { val pkgInfo = getPackageInfoCompat(pms, BuildConfig.APP_PACKAGE_NAME, 0L, 0) if (pkgInfo != null) { if (verifyAppSignature(pkgInfo.applicationInfo?.sourceDir)) { - logI(TAG, "The app signature is verified successfully") + logI(TAG, "The manager app signature is verified successfully") service.appUid = pkgInfo.applicationInfo!!.uid } else { - throw AssertionError("The app itself is modified, skipping") + throw AssertionError("The manager app is modified, skipping") } } assert(service.appUid >= 0) { From aecddb1a1ac8c94722978e58448188948ee9fa5c Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 11:09:10 +0300 Subject: [PATCH 014/162] Add restoring config from service after reinstall support --- .../icu/nullptr/hidemyapplist/service/ConfigManager.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index d86323b38..b80f4de37 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -42,8 +42,13 @@ object ConfigManager { fun init() { val configFileIsNew = !configFile.exists() if (configFileIsNew) { - config = JsonConfig() - configFile.writeText(config.toString()) + runCatching { + val rawConfig = ServiceClient.readConfig()!! + config = JsonConfig.parse(rawConfig) + }.onFailure { + config = JsonConfig() + configFile.writeText(config.toString()) + } } runCatching { if (!configFileIsNew) config = JsonConfig.parse(configFile.readText()) From 9f476ad31d60f15371f5a2c5fd99df19e9ec6c79 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 11:59:31 +0300 Subject: [PATCH 015/162] Switch to invokeExactPlain --- .../src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 09b82bfcf..6877375f1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -60,7 +60,7 @@ class BulkHooker private constructor() { } if (!value.replace) { - Transformers.invokeExact(original, frame) + Transformers.invokeExactPlain(original, frame) } if (value.replace && frame.type().returnType() != Void::class.java) { @@ -85,7 +85,7 @@ class BulkHooker private constructor() { var throwable: Throwable? = null runCatching { - Transformers.invokeExact(original, frame) + Transformers.invokeExactPlain(original, frame) }.onFailure { throwable = it } From 173d344949259a68c6cc858f1a9065332b72b8cf Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 12:20:22 +0300 Subject: [PATCH 016/162] Return back to invokeExact, use CURRENT as target type --- .../main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 6877375f1..85bdaca82 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -60,7 +60,7 @@ class BulkHooker private constructor() { } if (!value.replace) { - Transformers.invokeExactPlain(original, frame) + Transformers.invokeExact(original, frame) } if (value.replace && frame.type().returnType() != Void::class.java) { @@ -85,7 +85,7 @@ class BulkHooker private constructor() { var throwable: Throwable? = null runCatching { - Transformers.invokeExactPlain(original, frame) + Transformers.invokeExact(original, frame) }.onFailure { throwable = it } @@ -142,7 +142,7 @@ class BulkHooker private constructor() { logI(TAG, "Hooked: $executable") } Hooks.hook( - executable, Hooks.EntryPointType.DIRECT, + executable, Hooks.EntryPointType.CURRENT, element.impl, Hooks.EntryPointType.DIRECT ) From 2118ebd76f69fb4d9b2f24f28b5b11b90fb2afd6 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 12:32:23 +0300 Subject: [PATCH 017/162] Remove dumpArgs from the docs --- zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 85bdaca82..3e46ac0a5 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -216,8 +216,6 @@ class BulkHooker private constructor() { /** * - `args[0] == thisObject` * - `args[1:] == function args` - * - * Note that this variable is null when `dumpArgs == false` */ val args by lazy { Utils4Zygote.dumpArgs(frame) } From 2b5aac53f5d3ee94a237c3d5e7d78f7504fc7d73 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 12:38:40 +0300 Subject: [PATCH 018/162] Optimize imports --- app/build.gradle.kts | 1 - .../src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt | 1 - .../src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt | 3 --- 3 files changed, 5 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index dc13a0aef..8fc445330 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,4 +1,3 @@ -import com.android.build.gradle.internal.api.BaseVariantOutputImpl import com.google.gson.JsonParser import org.jose4j.json.internal.json_simple.JSONObject import java.io.DataInputStream diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 57f51f015..c28d94126 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -16,7 +16,6 @@ import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.PresetCacheHolder import icu.nullptr.hidemyapplist.common.RiskyPackageUtils.appHasGMSConnection import icu.nullptr.hidemyapplist.common.SettingsPresets -import icu.nullptr.hidemyapplist.common.Utils import icu.nullptr.hidemyapplist.common.Utils.binderLocalScope import icu.nullptr.hidemyapplist.common.Utils.generateRandomString import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt index 0722364db..8b2a89538 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt @@ -5,7 +5,6 @@ import android.content.pm.IPackageManager import android.os.Build import android.os.Bundle import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getStaticIntField @@ -17,8 +16,6 @@ object UserService { private const val TAG = "HMA-UserService" - - private val uidObserver = object : UidObserverAdapter() { override fun onUidActive(uid: Int) { if (HMAService.instance == null) { From def2eb0fba957474a070a074bcc6ee07acbdd988 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 13:21:03 +0300 Subject: [PATCH 019/162] Optimize hooks --- .../java/org/frknkrc44/hma_oss/zygote/UserService.kt | 12 ++++++++---- .../frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt | 7 ++++--- .../frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt | 8 ++++---- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt index 8b2a89538..108fe4f71 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt @@ -55,26 +55,30 @@ object UserService { fun register(pms: IPackageManager, pmn: Any?) { logI(TAG, "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}") - val service = HMAService(pms, pmn) + + var appUid = -1 try { val pkgInfo = getPackageInfoCompat(pms, BuildConfig.APP_PACKAGE_NAME, 0L, 0) if (pkgInfo != null) { if (verifyAppSignature(pkgInfo.applicationInfo?.sourceDir)) { logI(TAG, "The manager app signature is verified successfully") - service.appUid = pkgInfo.applicationInfo!!.uid + appUid = pkgInfo.applicationInfo!!.uid } else { throw AssertionError("The manager app is modified, skipping") } } - assert(service.appUid >= 0) { + assert(appUid >= 0) { "App UID cannot be -1 or lower" } - logD(TAG, "Client uid: ${service.appUid}") + logD(TAG, "Client uid: $appUid") } catch (e: Throwable) { logE(TAG, "Fatal: Cannot get package details\nCompile this app from source with your changes", e) } + val service = HMAService(pms, pmn) + service.appUid = appUid + Utils4Zygote.waitForService("activity") ActivityManagerApis.registerUidObserver( uidObserver, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 258ade1e8..d5f6ce8da 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -53,8 +53,9 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getPackageSetting", ) { param -> - val targetApp = param.getArgument(1) as String val callingUid = Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = param.getArgument(1) as String if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) @@ -102,9 +103,9 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as String? ?: return@hookBefore val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = param.getArgument(1) as String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null @@ -126,9 +127,9 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as String? ?: return@hookBefore val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = param.getArgument(1) as String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index 2cf0a42dd..45cf19d4a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -53,9 +53,9 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getPackageSetting", ) { param -> - val targetApp = param.getArgument(1) as String val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = param.getArgument(1) as String if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) @@ -76,9 +76,9 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getPackageSettingInternal", ) { param -> - val targetApp = param.getArgument(1) as String val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = param.getArgument(1) as String if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) @@ -99,9 +99,9 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as String? ?: return@hookBefore val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = param.getArgument(1) as String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null @@ -123,9 +123,9 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as String? ?: return@hookBefore val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore + val targetApp = param.getArgument(1) as String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null From 364137afbc4f22388c329e720d81e3377b32fae8 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 13:42:40 +0300 Subject: [PATCH 020/162] Add proper waitForService --- .../java/org/frknkrc44/hma_oss/zygote/UserService.kt | 6 +++--- .../org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt index 108fe4f71..2b3f55118 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt @@ -76,9 +76,6 @@ object UserService { logE(TAG, "Fatal: Cannot get package details\nCompile this app from source with your changes", e) } - val service = HMAService(pms, pmn) - service.appUid = appUid - Utils4Zygote.waitForService("activity") ActivityManagerApis.registerUidObserver( uidObserver, @@ -88,6 +85,9 @@ object UserService { ) logI(TAG, "Registered observer") + + val service = HMAService(pms, pmn) + service.appUid = appUid } private fun getActMgrField(name: String) = getStaticIntField( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index 62e17f631..be4aa4ffe 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -22,6 +22,8 @@ import java.util.regex.Pattern object Utils4Zygote { + const val TAG = "Utils4Zygote" + fun dumpArgs(frame: EmulatedStackFrame): Array { return mutableListOf().let { for (index in 0 ..< frame.type().parameterCount()) { @@ -75,6 +77,16 @@ object Utils4Zygote { @Throws(InterruptedException::class) fun waitForService(name: String?): IBinder? { + try { + return getDeclaredMethod( + ServiceManager::class.java, + "waitForService", + String::class.java, + ).invoke(null, name) as IBinder? + } catch (e: Throwable) { + logE(TAG, "An error occurred on waitForService", e) + } + var service: IBinder? = null do { From 08026bce4cb454139404b193cd70397556c7b7cb Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 15:13:34 +0300 Subject: [PATCH 021/162] Add package name and uid cache --- .../frknkrc44/hma_oss/zygote/HMAService.kt | 16 +++++++- .../hma_oss/zygote/UidPackageNameCache.kt | 38 +++++++++++++++++++ .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 5 +++ .../zygote/hook/AppDataIsolationHook.kt | 29 +++++--------- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 5 +-- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 5 +-- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 7 +--- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 4 +- 8 files changed, 71 insertions(+), 38 deletions(-) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index c28d94126..8e56583fe 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -209,8 +209,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } private fun installHooks() { - getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) { - if (it.flags and ApplicationInfo.FLAG_SYSTEM != 0) it.packageName else null + getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) { appInfo -> + UidPackageNameCache.instance.addCachedAppEntry(appInfo.uid, appInfo.packageName) + + if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) appInfo.packageName else null } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { @@ -532,6 +534,14 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { AppPresets.instance.apply { when (eventType) { Intent.ACTION_PACKAGE_ADDED -> { + UidPackageNameCache.instance.apply { + if (!isPackageNameExists(packageName)) { + val uid = getPackageUidCompat(pms, packageName, + 0L, getCallingUserHandle().hashCode()) + addCachedAppEntry(uid, packageName) + } + } + if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid < 0) { val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { @@ -553,6 +563,8 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { return } + UidPackageNameCache.instance.removeCachedAppEntry(packageName) + if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid >= 0) { logI(TAG, "The manager app is uninstalled") appUid = -1 diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt new file mode 100644 index 000000000..ad603fea9 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt @@ -0,0 +1,38 @@ +package org.frknkrc44.hma_oss.zygote + +class UidPackageNameCache private constructor() { + companion object { + val instance by lazy { UidPackageNameCache() } + } + + private val uidAppsCache = mutableListOf>>() + + fun findCacheEntryByUid(uid: Int) = uidAppsCache.firstOrNull { it.first == uid } + + fun findCacheEntryByPackageName(packageName: String) = uidAppsCache.firstOrNull { packageName in it.second } + + fun isPackageNameExists(packageName: String) = uidAppsCache.any { packageName in it.second } + + fun addCachedAppEntry(uid: Int, packageName: String) { + val entry = findCacheEntryByUid(uid) + if (entry == null) { + uidAppsCache.add( + Pair(uid, mutableSetOf(packageName)) + ) + } else { + entry.second.add(packageName) + } + } + + fun removeCachedUidEntry(uid: Int) = uidAppsCache.removeIf { it.first == uid } + + fun removeCachedAppEntry(packageName: String): Boolean { + val entry = findCacheEntryByPackageName(packageName) ?: return false + + return if (entry.second.size < 2) { + removeCachedUidEntry(entry.first) + } else { + entry.second.removeIf { it == packageName } + } + } +} \ No newline at end of file diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index be4aa4ffe..03e938c0b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -117,6 +117,11 @@ object Utils4Zygote { fun getCallingApps(service: HMAService, callingUid: Int): Array { if (callingUid == Constants.UID_SYSTEM) return arrayOf() + val cache = UidPackageNameCache.instance.findCacheEntryByUid(callingUid) + if (cache != null) { + return cache.second.toTypedArray() + } + return Utils.binderLocalScope { service.pms.getPackagesForUid(callingUid) } ?: arrayOf() diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 3a8cfbd80..b11484012 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -3,10 +3,10 @@ package org.frknkrc44.hma_oss.zygote.hook import android.os.Build import android.os.SystemProperties import androidx.annotation.RequiresApi -import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService +import org.frknkrc44.hma_oss.zygote.Utils4Zygote import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getBooleanField import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getIntField import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getObjectField @@ -100,9 +100,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { getBooleanField(app, "appZygote") }.getOrDefault(false) - val apps = Utils.binderLocalScope { - service.pms.getPackagesForUid(uid) - } ?: return@hookAfter + val apps = Utils4Zygote.getCallingApps(service, uid) logD( TAG, @@ -171,28 +169,19 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { if (!voldHookSkipped && service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") val pidPkgMap = param.getArgument(1) as java.util.Map<*, *> - val userId = param.getArgument(2) as Int - val keysToRemove = mutableSetOf() for (entry in pidPkgMap.entrySet()) { val pid = entry.key val packageName = entry.value as String - val apps = Utils.binderLocalScope { - val uid = Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) - service.pms.getPackagesForUid(uid) - } ?: continue - - for (app in apps) { - if (app in service.systemApps || app == BuildConfig.APP_PACKAGE_NAME) { - logD( - TAG, - "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" - ) - keysToRemove += pid - break - } + if (packageName in service.systemApps || packageName == BuildConfig.APP_PACKAGE_NAME) { + logD( + TAG, + "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" + ) + keysToRemove += pid + break } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index 5c8575f3e..9efcfa9f9 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -1,7 +1,6 @@ package org.frknkrc44.hma_oss.zygote.hook import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService import org.frknkrc44.hma_oss.zygote.Utils4Zygote @@ -38,9 +37,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { logD(TAG, "@filterAppAccessLPr caller cache: $callingUid, target: $targetApp") return@hookBefore } - val callingApps = Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: return@hookBefore + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index d5f6ce8da..2ebddbbfe 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -5,7 +5,6 @@ import android.os.Build import androidx.annotation.RequiresApi import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService import org.frknkrc44.hma_oss.zygote.Utils4Zygote @@ -85,9 +84,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") return@hookBefore } - val callingApps = Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: return@hookBefore + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index 45cf19d4a..18e89e4a3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -5,7 +5,6 @@ import android.os.Build import androidx.annotation.RequiresApi import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService import org.frknkrc44.hma_oss.zygote.Utils4Zygote @@ -158,9 +157,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") return@hookBefore } - val callingApps = Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: return@hookBefore + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true @@ -173,6 +170,6 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { } } - super.load() + // super.load() } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 41e5b49bc..c6376eeb6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -108,9 +108,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { logD(TAG, "@getArchivedPackageInternal caller cache: $callingUid, target: $targetApp") return@hookBefore } - val callingApps = Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: return@hookBefore + val callingApps = Utils4Zygote.getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = null From 2fcc6f0c16c2f8a65af5daff17b1a833234f64b3 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Feb 2026 17:43:06 +0300 Subject: [PATCH 022/162] Revert some changes --- .../main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 3e46ac0a5..704b8468a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -60,7 +60,7 @@ class BulkHooker private constructor() { } if (!value.replace) { - Transformers.invokeExact(original, frame) + Transformers.invokeExactPlain(original, frame) } if (value.replace && frame.type().returnType() != Void::class.java) { @@ -85,7 +85,7 @@ class BulkHooker private constructor() { var throwable: Throwable? = null runCatching { - Transformers.invokeExact(original, frame) + Transformers.invokeExactPlain(original, frame) }.onFailure { throwable = it } @@ -142,7 +142,7 @@ class BulkHooker private constructor() { logI(TAG, "Hooked: $executable") } Hooks.hook( - executable, Hooks.EntryPointType.CURRENT, + executable, Hooks.EntryPointType.DIRECT, element.impl, Hooks.EntryPointType.DIRECT ) From 419cc7a14c3ed226ce5445511dfd657925d5fc4c Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 26 Feb 2026 17:23:00 +0300 Subject: [PATCH 023/162] Fix soft reboot by replacing unwanted return value --- .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index c6376eeb6..4089c3008 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -103,7 +103,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1).toString() if (service.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true + param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@getArchivedPackageInternal caller cache: $callingUid, target: $targetApp") return@hookBefore From 2f361e8e56ce95f48be5c83f16e9256183113e36 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 26 Feb 2026 18:03:48 +0300 Subject: [PATCH 024/162] Optimize removeCachedAppEntry --- .../frknkrc44/hma_oss/zygote/UidPackageNameCache.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt index ad603fea9..1bac7d079 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt @@ -28,11 +28,11 @@ class UidPackageNameCache private constructor() { fun removeCachedAppEntry(packageName: String): Boolean { val entry = findCacheEntryByPackageName(packageName) ?: return false - - return if (entry.second.size < 2) { - removeCachedUidEntry(entry.first) - } else { - entry.second.removeIf { it == packageName } + var result = entry.second.removeIf { it == packageName } + if (entry.second.isEmpty()) { + result = removeCachedUidEntry(entry.first) || result } + + return result } } \ No newline at end of file From 2a22b6a323e4ab8fcc30a9db4739ca4971c2b74d Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 26 Feb 2026 19:02:16 +0300 Subject: [PATCH 025/162] Add timestamp for non-master branch builds, fix file path for app --- app/build.gradle.kts | 2 +- build.gradle.kts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8fc445330..6114e30d3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -122,7 +122,7 @@ android { } base { - archivesName = "${rootProject.name}-${defaultConfig.versionName}" + archivesName = "${rootProject.name}-${defaultConfig.versionName!!.replace("/", "_")}" } packaging { diff --git a/build.gradle.kts b/build.gradle.kts index 4d1f2be3f..078532806 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -43,6 +43,7 @@ fun getUncommittedSuffix(): String { val branch = "git rev-parse --abbrev-ref HEAD".execute().split("/").last() if (branch != "master") { returnedVal += "-$branch" + returnedVal += "(${System.currentTimeMillis() / 1000})" } } catch (_: Throwable) {} From a93f9aee50028244fe8b64ae3ad7718d8d2cdab1 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 27 Feb 2026 16:51:41 +0300 Subject: [PATCH 026/162] Try to fix ImmHook, add action.sh --- settings.gradle.kts | 4 ++-- zygote/src/main/assets/action.sh | 3 +++ .../org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 12 ++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 zygote/src/main/assets/action.sh diff --git a/settings.gradle.kts b/settings.gradle.kts index 7b57ac3e4..cd26b3deb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,6 +28,6 @@ rootProject.name = "HMA-OSS" include( ":app", - ":common" + ":common", + ":zygote", ) -include(":zygote") diff --git a/zygote/src/main/assets/action.sh b/zygote/src/main/assets/action.sh new file mode 100644 index 000000000..b0e8bb5f2 --- /dev/null +++ b/zygote/src/main/assets/action.sh @@ -0,0 +1,3 @@ +#!/system/bin/sh + +am start org.frknkrc44.hma_oss/org.frknkrc44.hma_oss.ui.activity.MainActivity diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 855c170e6..bfbfba108 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -64,7 +64,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { hookBefore( IMM_SERVICE_CLASS, "getCurrentInputMethodInfoAsUser", - ) { param -> + ) { param -> val callingApps = Utils4Zygote.getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } @@ -79,7 +79,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { hookBefore( IMM_SERVICE_CLASS, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) "getInputMethodListInternal" else "getInputMethodList", @@ -89,7 +89,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { hookBefore( IMM_SERVICE_CLASS, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) "getEnabledInputMethodListInternal" else "getEnabledInputMethodList", @@ -100,14 +100,14 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { hookBefore( IMM_SERVICE_CLASS, "getCurrentInputMethodSubtype", - ) { param -> + ) { param -> subtypeHook(param) } hookBefore( IMM_SERVICE_CLASS, "getLastInputMethodSubtype", - ) { param -> + ) { param -> subtypeHook(param) } @@ -117,7 +117,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { "getEnabledInputMethodSubtypeListInternal" else "getEnabledInputMethodSubtypeList", - ) { param -> + ) { param -> subtypeListHook(param) } } From 1081db1260cbbca59ef73517c31199e453ceda50 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 27 Feb 2026 16:54:34 +0300 Subject: [PATCH 027/162] Fix versioning --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 078532806..a336d024f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -43,7 +43,7 @@ fun getUncommittedSuffix(): String { val branch = "git rev-parse --abbrev-ref HEAD".execute().split("/").last() if (branch != "master") { returnedVal += "-$branch" - returnedVal += "(${System.currentTimeMillis() / 1000})" + returnedVal += "-${System.currentTimeMillis() / 1000}" } } catch (_: Throwable) {} From 2544f9ffd3a0940a9cc3059f32dcc233404c02b1 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 27 Feb 2026 17:30:14 +0300 Subject: [PATCH 028/162] Fix 15+ ImmHook support properly --- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index bfbfba108..c252a42f5 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -14,6 +14,7 @@ import org.frknkrc44.hma_oss.zygote.Utils4Zygote import org.frknkrc44.hma_oss.zygote.ZygoteConstants.IMM_SERVICE_CLASS import org.frknkrc44.hma_oss.zygote.logD import org.frknkrc44.hma_oss.zygote.logE +import org.frknkrc44.hma_oss.zygote.logV import java.util.Collections class ImmHook(private val service: HMAService) : IFrameworkHook { @@ -46,7 +47,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { null, ) } catch (e: Throwable) { - logE(TAG, e.message ?: "", e) + logV(TAG, e.message ?: "", e) } } @@ -79,20 +80,14 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { hookBefore( IMM_SERVICE_CLASS, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) - "getInputMethodListInternal" - else - "getInputMethodList", + "getInputMethodList", ) { param -> listHook(param) } hookBefore( IMM_SERVICE_CLASS, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) - "getEnabledInputMethodListInternal" - else - "getEnabledInputMethodList", + "getEnabledInputMethodList", ) { param -> listHook(param) } @@ -124,18 +119,22 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun listHook(param: BulkHooker.HookParam) { - val callingApps = if (param.methodName.endsWith("Internal")) { - val callingUid = param.args.findLast { it is Int } as Int - Utils4Zygote.getCallingApps(service, callingUid) - } else { - Utils4Zygote.getCallingApps(service) - } + val callingApps = Utils4Zygote.getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { logD(TAG, "@${param.methodName} spoofed input method for $caller") - param.result = listOf(getFakeInputMethodInfo(caller)) + listOf(getFakeInputMethodInfo(caller)).let { list -> + val returnType = param.frame.type().returnType() + param.result = if (returnType.simpleName == "InputMethodInfoSafeList") { + returnType.getDeclaredMethod( + "create", + List::class.java, + ).apply { isAccessible = true }.invoke(null, list) + } else { list } + } + service.increaseSettingsFilterCount(caller) } } From 511e50c54c71ac120c1648cacd9b1fa247bfa33a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 2 Mar 2026 11:10:08 +0300 Subject: [PATCH 029/162] Try to improve Android 14 or below support, add OS info to log --- .../hidemyapplist/ui/fragment/LogsFragment.kt | 7 ++- .../nullptr/hidemyapplist/common/OSUtils.kt | 62 +++++++++++++++++++ .../icu/nullptr/hidemyapplist/common/Utils.kt | 12 ---- .../hma_oss/zygote/hook/ActivityHook.kt | 3 +- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 1 - .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 40 +++++++----- 6 files changed, 94 insertions(+), 31 deletions(-) create mode 100644 common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt index df4ddf7bd..d8ada5d94 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt @@ -9,6 +9,7 @@ import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient import icu.nullptr.hidemyapplist.ui.adapter.LogAdapter @@ -40,7 +41,11 @@ class LogsFragment : Fragment(R.layout.fragment_logs) { } contentResolver.openOutputStream(uri).use { output -> if (output == null) showToast(R.string.home_export_failed) - else output.write(logCache!!.toByteArray()) + else { + output.write(OSUtils.collectOSInfo(requireContext()).toByteArray()) + output.write("\n\n".toByteArray()) + output.write(logCache!!.toByteArray()) + } } showToast(R.string.logs_saved) } diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt new file mode 100644 index 000000000..ae5ad4144 --- /dev/null +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt @@ -0,0 +1,62 @@ +package icu.nullptr.hidemyapplist.common + +import android.content.Context +import android.os.Build +import android.os.SystemProperties +import org.frknkrc44.hma_oss.common.BuildConfig +import java.lang.reflect.Field + +object OSUtils { + private val PACKAGES_TO_CHECK = listOf( + "com.google.android.gms", + "com.android.vending", + "com.google.android.inputmethod.latin", + "com.google.android.ext.shared", + ) + + fun collectOSInfo(context: Context) = buildString { + append("HMA-OSS Log") + append("\nApp version: ${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})") + // TODO: Add service version name + append("\nFingerprint: ") + append(Build.FINGERPRINT) + append("\nAndroid SDK: ") + append("${Build.VERSION.SDK_INT} (P ${Build.VERSION.PREVIEW_SDK_INT})") + append("\nKnown codenames: [") + append(SystemProperties.get("ro.build.version.known_codenames")) + append("]\nIs HyperOS: ") + append(SystemProperties.get("ro.mi.os.version.incremental").isNotBlank()) + append("\nIs MIUI: ") + append(isPackageExists(context, "com.miui.system")) + append("\nIs oplus: ") + append(SystemProperties.get("ro.build.version.oplusrom").isNotBlank()) + append("\nIs Samsung: ") + append(isSamsung()) + append("\nIs Pixel: ") + append(isPackageExists(context, "com.google.android.apps.customization.pixel")) + + PACKAGES_TO_CHECK.forEach { + append("Is $it available: ") + append(isPackageExists(context, it)) + } + } + + fun isSamsung(): Boolean { + try { + val semPlatformIntField: Field = + Build.VERSION::class.java.getDeclaredField("SEM_PLATFORM_INT") + semPlatformIntField.isAccessible = true + return semPlatformIntField.getInt(null) >= 0 + } catch (_: Throwable) { + return false + } + } + + fun isPackageExists(context: Context, packageName: String): Boolean { + return try { + context.packageManager.getPackageUid(packageName, 0) > 0 + } catch (_: Throwable) { + false + } + } +} \ No newline at end of file diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index 6aab2b801..07ae5eea2 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -6,7 +6,6 @@ import android.content.pm.PackageInfo import android.content.pm.ResolveInfo import android.os.Binder import android.os.Build -import java.lang.reflect.Field import java.util.Random import java.util.zip.ZipFile @@ -111,17 +110,6 @@ object Utils { } } - fun isSamsung(): Boolean { - try { - val semPlatformIntField: Field = - Build.VERSION::class.java.getDeclaredField("SEM_PLATFORM_INT") - semPlatformIntField.isAccessible = true - return semPlatformIntField.getInt(null) >= 0 - } catch (_: Throwable) { - return false - } - } - inline fun MutableMap.removeIf(predicate: (K, V) -> Boolean) { this.filter { (key, value) -> predicate(key, value) }.forEach { this.remove(it.key) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index f57a11b3c..26545e056 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.content.pm.ResolveInfo import android.os.Build import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService @@ -88,7 +89,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { } */ - if (!Utils.isSamsung()) { + if (!OSUtils.isSamsung()) { hookBefore( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { COMPUTER_ENGINE_CLASS diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index c252a42f5..351c0cc51 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -13,7 +13,6 @@ import org.frknkrc44.hma_oss.zygote.HMAService import org.frknkrc44.hma_oss.zygote.Utils4Zygote import org.frknkrc44.hma_oss.zygote.ZygoteConstants.IMM_SERVICE_CLASS import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logE import org.frknkrc44.hma_oss.zygote.logV import java.util.Collections diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index fa0c9b995..5a77b9645 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -10,7 +10,9 @@ import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.callMethod +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getCallingApps +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.ZygoteConstants.COMPUTER_ENGINE_CLASS import org.frknkrc44.hma_oss.zygote.logD import org.frknkrc44.hma_oss.zygote.logV @@ -48,7 +50,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookAfter - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller != null) { logD(TAG, "@getPackageStates: incoming query from $caller") @@ -57,8 +59,8 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val markedToRemove = mutableListOf() for (pair in result.entries) { - val value = pair.value - val packageName = Utils4Zygote.callMethod(value, "getPackageName") as String + val packageSettings = pair.value + val packageName = getPackageNameFromPackageSettings(packageSettings) if (service.shouldHide(caller, packageName)) { markedToRemove.add(pair.key) } @@ -79,15 +81,15 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework "addPackageHoldingPermissions", ) { param -> val callingUid = Binder.getCallingUid() - val packageState = param.getArgument(2) - val targetApp = Utils4Zygote.callMethod(packageState, "getPackageName") as String? ?: return@hookBefore + val packageSettings = param.getArgument(2) + val targetApp = getPackageNameFromPackageSettings(packageSettings) ?: return@hookBefore if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@addPackageHoldingPermissions caller cache: $callingUid, target: $targetApp") return@hookBefore } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { logD(TAG, "@addPackageHoldingPermissions caller: $callingUid $caller, target: $targetApp") @@ -101,13 +103,19 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "isCallerInstallerOfRecord", ) { param -> - val pkg = param.args[1] ?: return@hookBefore - val query = Utils4Zygote.callMethod(pkg, "getPackageName") as String - val callingUid = param.args.last { it is Int } as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val pkg = param.args[1] ?: return@hookBefore + val query = callMethod( + pkg, + if (pkg.javaClass.simpleName == "PackageImpl") { + "getManifestPackageName" + } else { + "getPackageName" + }) as? String ?: return@hookBefore + + val callingApps = getCallingApps(service, callingUid) val callingHandle = UserHandle.getUserHandleForUid(callingUid) for (caller in callingApps) { @@ -136,7 +144,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") return@hookBefore } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") @@ -160,7 +168,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") return@hookBefore } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") @@ -181,7 +189,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val callingHandle = UserHandle.getUserHandleForUid(callingUid) for (caller in callingApps) { @@ -207,7 +215,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val callingHandle = UserHandle.getUserHandleForUid(callingUid) for (caller in callingApps) { @@ -232,7 +240,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val callingHandle = UserHandle.getUserHandleForUid(callingUid) for (caller in callingApps) { From 4fc650924c0e96a826803cad9cfbcbb5576e04f2 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 2 Mar 2026 12:13:01 +0300 Subject: [PATCH 030/162] Add "service version name" getter --- .../icu/nullptr/hidemyapplist/service/ServiceClient.kt | 8 ++++++++ .../nullptr/hidemyapplist/ui/fragment/LogsFragment.kt | 7 ++++++- .../icu/nullptr/hidemyapplist/common/IHMAService.aidl | 4 ++++ .../java/icu/nullptr/hidemyapplist/common/OSUtils.kt | 10 ++++++---- .../java/org/frknkrc44/hma_oss/zygote/HMAService.kt | 2 ++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt index 749fe6352..9767eba7b 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt @@ -99,4 +99,12 @@ object ServiceClient : IHMAService, IBinder.DeathRecipient { override fun clearFilterStats() { service?.clearFilterStats() } + + /** + * Get the current service `BuildConfig.APP_VERSION_NAME`. + * Returns `null` if there is no service connection or an old version is installed. + */ + override fun getServiceVersionName() = try { + service?.serviceVersionName + } catch (_: Throwable) { null } } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt index d8ada5d94..54900d801 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt @@ -42,7 +42,12 @@ class LogsFragment : Fragment(R.layout.fragment_logs) { contentResolver.openOutputStream(uri).use { output -> if (output == null) showToast(R.string.home_export_failed) else { - output.write(OSUtils.collectOSInfo(requireContext()).toByteArray()) + output.write( + OSUtils.collectOSInfo( + requireContext(), + ServiceClient.serviceVersionName, + ).toByteArray() + ) output.write("\n\n".toByteArray()) output.write(logCache!!.toByteArray()) } diff --git a/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl b/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl index 256713cdc..d7dd94fe9 100644 --- a/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl +++ b/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl @@ -6,6 +6,7 @@ interface IHMAService { void writeConfig(String json) = 1; + // config version int getServiceVersion() = 2; int getFilterCount() = 3; @@ -37,4 +38,7 @@ interface IHMAService { String getDetailedFilterStats() = 16; void clearFilterStats() = 17; + + // service version + String getServiceVersionName() = 18; } diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt index ae5ad4144..db72fe4e8 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/OSUtils.kt @@ -14,10 +14,12 @@ object OSUtils { "com.google.android.ext.shared", ) - fun collectOSInfo(context: Context) = buildString { + fun collectOSInfo(context: Context, serviceVersion: String?) = buildString { append("HMA-OSS Log") - append("\nApp version: ${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})") - // TODO: Add service version name + append("\nApp version: ") + append("${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})") + append("\nService version: ") + append(serviceVersion) append("\nFingerprint: ") append(Build.FINGERPRINT) append("\nAndroid SDK: ") @@ -36,7 +38,7 @@ object OSUtils { append(isPackageExists(context, "com.google.android.apps.customization.pixel")) PACKAGES_TO_CHECK.forEach { - append("Is $it available: ") + append("\nIs $it available: ") append(isPackageExists(context, it)) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 8e56583fe..19bc36284 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -655,4 +655,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { writeFilterCount(true) } + + override fun getServiceVersionName() = BuildConfig.APP_VERSION_NAME } From 0f5618b2c1526ab8e848d8cbf688f67dd9dd7d15 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 5 Mar 2026 07:51:19 +0300 Subject: [PATCH 031/162] Try to optimize hook code --- .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 704b8468a..0cbb992c4 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -53,18 +53,25 @@ class BulkHooker private constructor() { addAll(clazz, methodName, hookFirst, paramCount) { original, frame -> val value = ReturnValue() - runCatching { + try { hook(HookParam(clazz, original, frame, methodName, value)) - }.onFailure { + } catch (it: Throwable) { logE(TAG, it.message ?: "Unknown error on hook", it) } if (!value.replace) { - Transformers.invokeExactPlain(original, frame) + try { + Transformers.invokeExactPlain(original, frame) + } catch (it: Throwable) { + logE(TAG, it.message ?: "Unknown error on original function", it) + value.throwable = it + } } + value.throwable?.let { throw it } + if (value.replace && frame.type().returnType() != Void::class.java) { - frame.accessor().setValue(RETURN_VALUE_IDX, value.value) + frame.accessor().setValue(RETURN_VALUE_IDX, value.result) } } @@ -82,31 +89,28 @@ class BulkHooker private constructor() { hook: (param: HookParam) -> Unit, ) { addAll(clazz, methodName, hookFirst, paramCount) { original, frame -> - var throwable: Throwable? = null + val value = ReturnValue() - runCatching { + try { Transformers.invokeExactPlain(original, frame) - }.onFailure { - throwable = it + } catch (it: Throwable) { + value.throwable = it } - val value = ReturnValue(if (throwable == null) { - frame.accessor().getValue(RETURN_VALUE_IDX) - } else null) - value.throwable = throwable + if (value.throwable == null) { + value.setResultWithoutReplace(frame.accessor().getValue(RETURN_VALUE_IDX)) + } - runCatching { + try { hook(HookParam(clazz, original, frame, methodName, value)) - }.onFailure { + } catch (it: Throwable) { logE(TAG, it.message ?: "Unknown error on hook", it) } - if (throwable != null) { - throw throwable - } + value.throwable?.let { throw it } - if (value.replace && frame.type().returnType() != Void::class.java) { - frame.accessor().setValue(RETURN_VALUE_IDX, value.value) + if (frame.type().returnType() != Void::class.java) { + frame.accessor().setValue(RETURN_VALUE_IDX, value.result) } } @@ -172,24 +176,21 @@ class BulkHooker private constructor() { } } - data class HookElement( - val impl: HookTransformer, - val pattern: String, - val hookFirst: Boolean, - val paramCount: Int = -1, - var applyCount: Int = 0, - ) - class ReturnValue(initialValue: Any? = null) { var replace: Boolean = false private set - var value: Any? = initialValue - set(value) { - field = value + var result: Any? = initialValue + set(newValue) { + field = newValue replace = true } + fun setResultWithoutReplace(newValue: Any?) { + result = newValue + replace = false + } + var throwable: Throwable? = null } @@ -201,8 +202,8 @@ class BulkHooker private constructor() { val returnValue: ReturnValue, ) { var result: Any? - get() = returnValue.value - set(newValue) { returnValue.value = newValue } + get() = returnValue.result + set(newValue) { returnValue.result = newValue } /** * Returns the first argument @@ -223,4 +224,12 @@ class BulkHooker private constructor() { get() = returnValue.throwable set(newValue) { returnValue.throwable = newValue } } + + data class HookElement( + val impl: HookTransformer, + val pattern: String, + val hookFirst: Boolean, + val paramCount: Int = -1, + var applyCount: Int = 0, + ) } From 74237171b6df985acb84cb5a54b92bb4e53b87bc Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 6 Mar 2026 17:33:34 +0300 Subject: [PATCH 032/162] Improve hooking side --- gradle/libs.versions.toml | 2 +- .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 38 ++++++++++++------- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 5 ++- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 866b0307c..088637057 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -#noinspection AndroidGradlePluginVersion +#noinspection GradleDependency,AndroidGradlePluginVersion agp = "8.13.2" kotlin = "2.3.10" material = "1.13.0" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 0cbb992c4..c3d2f66b3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -22,21 +22,21 @@ class BulkHooker private constructor() { private val hooks: MutableMap> = HashMap>() - private fun addPattern(clazz: String, pattern: String, hookFirst: Boolean, paramCount: Int, impl: HookTransformer) { + private fun addPattern(clazz: String, pattern: String, hookOnce: Boolean, paramCount: Int, impl: HookTransformer) { hooks.computeIfAbsent(clazz) { _ -> mutableListOf() } .add(HookElement( impl = impl, pattern = pattern, - hookFirst = hookFirst, + hookOnce = hookOnce, paramCount = paramCount, )) } - private fun addAll(clazz: String, methodName: String, hookFirst: Boolean, paramCount: Int, impl: HookTransformer) { + private fun addAll(clazz: String, methodName: String, hookOnce: Boolean, paramCount: Int, impl: HookTransformer) { addPattern( clazz, String.format("%s\\(.*\\).*", Pattern.quote(methodName)), - hookFirst, + hookOnce, paramCount, impl, ) @@ -46,11 +46,11 @@ class BulkHooker private constructor() { clazz: String, methodName: String, autoApply: Boolean = true, - hookFirst: Boolean = true, + hookOnce: Boolean = true, paramCount: Int = -1, hook: (param: HookParam) -> Unit, ) { - addAll(clazz, methodName, hookFirst, paramCount) { original, frame -> + addAll(clazz, methodName, hookOnce, paramCount) { original, frame -> val value = ReturnValue() try { @@ -84,11 +84,11 @@ class BulkHooker private constructor() { clazz: String, methodName: String, autoApply: Boolean = true, - hookFirst: Boolean = true, + hookOnce: Boolean = true, paramCount: Int = -1, hook: (param: HookParam) -> Unit, ) { - addAll(clazz, methodName, hookFirst, paramCount) { original, frame -> + addAll(clazz, methodName, hookOnce, paramCount) { original, frame -> val value = ReturnValue() try { @@ -137,20 +137,25 @@ class BulkHooker private constructor() { Stream.of(*executables) .filter(Utils4Zygote.filter(element.pattern)) .forEach { executable: Executable -> - if (element.paramCount != -1 && executable.parameterCount != element.paramCount) { - return@forEach - } + if (!element.hookFinished) { + if (element.paramCount != -1 && executable.parameterCount != element.paramCount) { + return@forEach + } - if (!element.hookFirst || element.applyCount < 1) { if (BuildConfig.DEBUG) { logI(TAG, "Hooked: $executable") } + Hooks.hook( - executable, Hooks.EntryPointType.DIRECT, + executable, Hooks.EntryPointType.CURRENT, element.impl, Hooks.EntryPointType.DIRECT ) element.applyCount++ + + if (element.hookOnce) { + element.hookFinished = true + } } } } @@ -173,6 +178,10 @@ class BulkHooker private constructor() { } } } + + entry.value.forEach { + it.hookFinished = true + } } } @@ -228,7 +237,8 @@ class BulkHooker private constructor() { data class HookElement( val impl: HookTransformer, val pattern: String, - val hookFirst: Boolean, + val hookOnce: Boolean, + var hookFinished: Boolean = false, val paramCount: Int = -1, var applyCount: Int = 0, ) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index 03e938c0b..0468138cf 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -24,9 +24,10 @@ import java.util.regex.Pattern object Utils4Zygote { const val TAG = "Utils4Zygote" - fun dumpArgs(frame: EmulatedStackFrame): Array { + fun dumpArgs(frame: EmulatedStackFrame, skipFirst: Boolean = false): Array { return mutableListOf().let { - for (index in 0 ..< frame.type().parameterCount()) { + val begin = if (skipFirst) 1 else 0 + for (index in begin ..< frame.type().parameterCount()) { it.add(getArgument(frame, index)) } From 42c7b9ba6beab8b75070b859a3d12e4d793316a6 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 7 Mar 2026 06:15:21 +0300 Subject: [PATCH 033/162] Optimize the hook applier and other things --- .../hma_oss/ui/fragment/HomeFragment.kt | 2 +- .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 151 +++++++----------- .../hma_oss/zygote/SystemServerHook.kt | 23 +-- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 51 ++---- 4 files changed, 87 insertions(+), 140 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 79aae4990..330387783 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -117,7 +117,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { if (serviceVersion > 0) { moduleStatusIcon.setImageResource(R.drawable.sentiment_calm_24px) - val versionNameSimple = BuildConfig.VERSION_NAME.substringBefore(".r") + val versionNameSimple = ServiceClient.serviceVersionName ?: BuildConfig.VERSION_NAME moduleStatus.text = getString(R.string.home_xposed_activated, versionNameSimple) root.setOnLongClickListener { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index c3d2f66b3..3f45ba513 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -1,6 +1,5 @@ package org.frknkrc44.hma_oss.zygote -import android.util.Log import com.v7878.unsafe.Reflection import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX @@ -10,9 +9,6 @@ import com.v7878.vmtools.Hooks import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.ZygoteEntry.TAG import java.lang.invoke.MethodHandle -import java.lang.reflect.Executable -import java.util.regex.Pattern -import java.util.stream.Stream class BulkHooker private constructor() { companion object { @@ -22,30 +18,24 @@ class BulkHooker private constructor() { private val hooks: MutableMap> = HashMap>() - private fun addPattern(clazz: String, pattern: String, hookOnce: Boolean, paramCount: Int, impl: HookTransformer) { - hooks.computeIfAbsent(clazz) { _ -> mutableListOf() } - .add(HookElement( - impl = impl, - pattern = pattern, - hookOnce = hookOnce, - paramCount = paramCount, - )) - } - private fun addAll(clazz: String, methodName: String, hookOnce: Boolean, paramCount: Int, impl: HookTransformer) { - addPattern( - clazz, - String.format("%s\\(.*\\).*", Pattern.quote(methodName)), - hookOnce, - paramCount, - impl, + val element = HookElement( + impl = impl, + methodName = methodName, + hookOnce = hookOnce, + paramCount = paramCount, ) + + if (applyHook(clazz, element)) { + hooks.computeIfAbsent(clazz) { _ -> mutableListOf() }.add(element) + } else { + logI(TAG, "Invalid hook removed: $clazz -> $methodName($paramCount)") + } } internal fun hookBefore( clazz: String, methodName: String, - autoApply: Boolean = true, hookOnce: Boolean = true, paramCount: Int = -1, hook: (param: HookParam) -> Unit, @@ -70,20 +60,15 @@ class BulkHooker private constructor() { value.throwable?.let { throw it } - if (value.replace && frame.type().returnType() != Void::class.java) { - frame.accessor().setValue(RETURN_VALUE_IDX, value.result) + if (value.replace) { + Utils4Zygote.setReturnValue(frame, value.result) } } - - if (autoApply) { - applyHooks() - } } internal fun hookAfter( clazz: String, methodName: String, - autoApply: Boolean = true, hookOnce: Boolean = true, paramCount: Int = -1, hook: (param: HookParam) -> Unit, @@ -109,80 +94,66 @@ class BulkHooker private constructor() { value.throwable?.let { throw it } - if (frame.type().returnType() != Void::class.java) { - frame.accessor().setValue(RETURN_VALUE_IDX, value.result) - } + Utils4Zygote.setReturnValue(frame, value.result) } + } - if (autoApply) { - applyHooks() + internal fun applyHook( + clazz: String, + element: HookElement, + loader: ClassLoader? = SystemServerHook.classLoader, + ): Boolean { + var curClazz: Class<*>? + try { + curClazz = Class.forName(clazz, true, loader) + } catch (ex: ClassNotFoundException) { + logE(TAG, "Class $clazz not found", ex) + return false } - } - internal fun applyHooks(loader: ClassLoader? = SystemServerHook.classLoader) { - for (entry in hooks.entries) { - var curClazz: Class<*>? - try { - curClazz = Class.forName(entry.key, true, loader) - } catch (ex: ClassNotFoundException) { - Log.e(TAG, java.lang.String.format("Class %s not found", entry.key), ex) - continue + fun applyForClass(clazz: Class<*>?) { + val executables = Reflection.getHiddenExecutables(clazz).filter { executable -> + element.methodName == executable.name && + (element.paramCount in listOf(-1, executable.parameterCount - 1)) + }.sortedWith { v1, v2 -> + v1.parameterCount.compareTo(v2.parameterCount) } - fun apply(clazz: Class<*>?) { - val executables = Reflection.getHiddenExecutables(clazz).sortedWith { v1, v2 -> - v1.parameterCount.compareTo(v2.parameterCount) - }.toTypedArray() - for (element in entry.value) { - Stream.of(*executables) - .filter(Utils4Zygote.filter(element.pattern)) - .forEach { executable: Executable -> - if (!element.hookFinished) { - if (element.paramCount != -1 && executable.parameterCount != element.paramCount) { - return@forEach - } - - if (BuildConfig.DEBUG) { - logI(TAG, "Hooked: $executable") - } - - Hooks.hook( - executable, Hooks.EntryPointType.CURRENT, - element.impl, Hooks.EntryPointType.DIRECT - ) - - element.applyCount++ - - if (element.hookOnce) { - element.hookFinished = true - } - } - } - } - } + for (executable in executables) { + if (!element.hookFinished) { + if (BuildConfig.DEBUG) { + logI(TAG, "Hooked: $executable") + } - while ( - curClazz != null && - entry.value.any { it.applyCount < 1 } && - curClazz.javaClass.simpleName != "Object" - ) { - apply(curClazz) - curClazz = curClazz.superclass - } + Hooks.hook( + executable, Hooks.EntryPointType.DIRECT, + element.impl, Hooks.EntryPointType.DIRECT + ) + + element.applyCount++ - // remove invalid entries - entry.value.removeIf { - (it.applyCount < 1).apply { - if (this@apply) { - logI(TAG, "Invalid hook removed: ${it.pattern}") + if (element.hookOnce) { + element.hookFinished = true + break } } } + } - entry.value.forEach { - it.hookFinished = true - } + while ( + !element.hookFinished && + curClazz != null && + curClazz.javaClass.simpleName != "Object" + ) { + applyForClass(curClazz) + curClazz = curClazz.superclass + } + + if (!element.hookOnce && element.applyCount >= 1) { + element.hookFinished = true } + + return element.hookFinished } class ReturnValue(initialValue: Any? = null) { @@ -236,7 +207,7 @@ class BulkHooker private constructor() { data class HookElement( val impl: HookTransformer, - val pattern: String, + val methodName: String, val hookOnce: Boolean, var hookFinished: Boolean = false, val paramCount: Int = -1, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt index d335c00de..b2391a039 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt @@ -17,6 +17,7 @@ object SystemServerHook { private const val RUNTIME_INIT: String = "com.android.internal.os.RuntimeInit" var classLoader: ClassLoader? = null + var initialized = false @Throws(Throwable::class) fun onSystemServer(loader: ClassLoader?) { @@ -26,16 +27,20 @@ object SystemServerHook { classLoader = loader - thread { - val pms = Utils4Zygote.waitForService("package") as IPackageManager - val pmn = Utils4Zygote.waitForService("package_native") - logD(TAG, "Got pms: $pms, $pmn") + if (!initialized) { + initialized = true - runCatching { - UserService.register(pms, pmn) - logI(TAG, "User service started") - }.onFailure { - logE(TAG, "System service crashed", it) + thread { + val pms = Utils4Zygote.waitForService("package") as IPackageManager + val pmn = Utils4Zygote.waitForService("package_native") + logD(TAG, "Got pms: $pms, $pmn") + + runCatching { + UserService.register(pms, pmn) + logI(TAG, "User service started") + }.onFailure { + logE(TAG, "System service crashed", it) + } } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index 0468138cf..ced7bdb32 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -9,16 +9,13 @@ import com.android.apksig.ApkVerifier import com.v7878.unsafe.Reflection.getDeclaredField import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame +import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils import java.io.File import java.lang.reflect.Constructor -import java.lang.reflect.Executable import java.lang.reflect.Field import java.lang.reflect.Method -import java.lang.reflect.Modifier -import java.util.function.Predicate -import java.util.regex.Pattern object Utils4Zygote { @@ -69,10 +66,9 @@ object Utils4Zygote { } } - fun filter(pattern: String): Predicate { - val compiledPattern = Pattern.compile(pattern) - return Predicate { executable: Executable? -> - compiledPattern.matcher(printExecutable(executable)).matches() + fun setReturnValue(frame: EmulatedStackFrame, value: Any?) { + if (frame.type().returnType() != Void::class.java) { + frame.accessor().setValue(RETURN_VALUE_IDX, value) } } @@ -123,9 +119,15 @@ object Utils4Zygote { return cache.second.toTypedArray() } - return Utils.binderLocalScope { + val apps = Utils.binderLocalScope { service.pms.getPackagesForUid(callingUid) } ?: arrayOf() + + apps.forEach { + UidPackageNameCache.instance.addCachedAppEntry(callingUid, it) + } + + return apps } fun getStaticIntField(className: String, name: String) = getDeclaredField( @@ -192,35 +194,4 @@ object Utils4Zygote { val mainCert = result.signerCertificates[0] return mainCert.encoded.contentEquals(Magic.magicNumbers) } - - private fun getClassName(clazz: Class<*>): String { - val component = clazz.componentType - if (component != null) { - return getClassName(component) + "[]" - } - return clazz.name - } - - private fun getExecName(executable: Executable?): String { - if (executable is Method) { - return executable.name - } - assert(executable is Constructor<*>) - return if (Modifier.isStatic(executable!!.modifiers)) "" else "" - } - - private fun getReturnType(executable: Executable?): String { - if (executable is Method) { - return getClassName(executable.returnType) - } - assert(executable is Constructor<*>) - return getClassName(Void.TYPE) - } - - private fun printExecutable(executable: Executable?): String { - val paramTypes = - executable?.parameterTypes?.joinToString(separator = ", ") { getClassName(it) } - - return "${getExecName(executable)}(${paramTypes})${getReturnType(executable)}" - } } From 383fc88bb3bf75ad8caa14473382e19ed125824b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 8 Mar 2026 18:09:33 +0300 Subject: [PATCH 034/162] Try to fix Android 12- support --- .../hidemyapplist/service/ConfigManager.kt | 2 - gradle/libs.versions.toml | 2 +- .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 52 +++++++++++++++++-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index b80f4de37..a16323c5f 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -5,8 +5,6 @@ import android.util.Log import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.hmaApp -import icu.nullptr.hidemyapplist.service.ConfigManager.PTType.APP -import icu.nullptr.hidemyapplist.service.ConfigManager.PTType.SETTINGS import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper import org.frknkrc44.hma_oss.R diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 088637057..2db98fb0d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.0" -androidvmtools = "753a955da1" +androidvmtools = "81dc2a7" zygoteloader = "bf5078e182" [plugins] diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 3f45ba513..10ff90bf9 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -1,5 +1,7 @@ package org.frknkrc44.hma_oss.zygote +import android.os.Build +import com.v7878.unsafe.ArtMethodUtils import com.v7878.unsafe.Reflection import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX @@ -9,6 +11,8 @@ import com.v7878.vmtools.Hooks import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.ZygoteEntry.TAG import java.lang.invoke.MethodHandle +import java.lang.reflect.Executable +import java.lang.reflect.Method class BulkHooker private constructor() { companion object { @@ -51,7 +55,7 @@ class BulkHooker private constructor() { if (!value.replace) { try { - Transformers.invokeExactPlain(original, frame) + invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { logE(TAG, it.message ?: "Unknown error on original function", it) value.throwable = it @@ -77,7 +81,7 @@ class BulkHooker private constructor() { val value = ReturnValue() try { - Transformers.invokeExactPlain(original, frame) + invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { value.throwable = it } @@ -125,11 +129,18 @@ class BulkHooker private constructor() { logI(TAG, "Hooked: $executable") } - Hooks.hook( + val memoryAddresses = Hooks.hook( executable, Hooks.EntryPointType.DIRECT, element.impl, Hooks.EntryPointType.DIRECT ) + logV(TAG, "Memory address map: $memoryAddresses") + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + element.memoryAddresses = memoryAddresses + element.method = executable + } + element.applyCount++ if (element.hookOnce) { @@ -156,6 +167,39 @@ class BulkHooker private constructor() { return element.hookFinished } + fun invokeExactCompat(clazz: String, methodName: String, original: MethodHandle, frame: EmulatedStackFrame, value: ReturnValue) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + val element = findHookElement(clazz, methodName)!! + + ArtMethodUtils.setExecutableEntryPoint( + element.method!!, + element.memoryAddresses?.second!! + ) + + val thisObject = Utils4Zygote.getArgument(frame, 0) + val args = Utils4Zygote.dumpArgs(frame, true) + + value.result = (element.method as Method).invoke(thisObject, *args) + + ArtMethodUtils.setExecutableEntryPoint( + element.method!!, + element.memoryAddresses?.first!! + ) + } else { + Transformers.invokeExactPlain(original, frame) + } + } + + fun findHookElement(clazz: String, methodName: String): HookElement? { + hooks[clazz]?.forEach { element -> + if (element.methodName == methodName) { + return element + } + } + + return null + } + class ReturnValue(initialValue: Any? = null) { var replace: Boolean = false private set @@ -209,6 +253,8 @@ class BulkHooker private constructor() { val impl: HookTransformer, val methodName: String, val hookOnce: Boolean, + var method: Executable? = null, + var memoryAddresses: android.util.Pair? = null, var hookFinished: Boolean = false, val paramCount: Int = -1, var applyCount: Int = 0, From 700aa1ff29ba0678ad7a3864cd134b30603d53dd Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 8 Mar 2026 20:54:24 +0300 Subject: [PATCH 035/162] Improve methods --- gradle/libs.versions.toml | 2 +- .../src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 2 +- .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt | 4 ++-- .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt | 4 ++-- .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt | 4 ++-- .../org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt | 2 +- .../main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2db98fb0d..33771fda6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.0" -androidvmtools = "81dc2a7" +androidvmtools = "8375ef5" zygoteloader = "bf5078e182" [plugins] diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 10ff90bf9..aa3c57e87 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -86,7 +86,7 @@ class BulkHooker private constructor() { value.throwable = it } - if (value.throwable == null) { + if (value.throwable == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { value.setResultWithoutReplace(frame.accessor().getValue(RETURN_VALUE_IDX)) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index 9efcfa9f9..9fd0cb6d8 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -53,7 +53,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val targetApp = param.getArgument(1) as? String? ?: return@hookBefore val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") @@ -77,7 +77,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val targetApp = param.getArgument(1) as? String? ?: return@hookBefore val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 2ebddbbfe..ec98cbb05 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -102,7 +102,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { ) { param -> val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null @@ -126,7 +126,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { ) { param -> val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index 18e89e4a3..a72bcb043 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -100,7 +100,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { ) { param -> val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null @@ -124,7 +124,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { ) { param -> val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as String? ?: return@hookBefore + val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") if (service.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index 9a43526a0..602c6b26e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -31,7 +31,7 @@ class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { "com.android.internal.content.PackageMonitor", "onReceive", ) { param -> - val intent = param.getArgument(2) as Intent? ?: return@hookBefore + val intent = param.getArgument(2) as? Intent? ?: return@hookBefore service.handlePackageEvent( intent.action, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index 843d89835..9184fa65e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -22,7 +22,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { val gIDsIndex = param.args.indexOfFirst { it is IntArray } if (gIDsIndex < 0) return@hookBefore - val caller = param.args.lastOrNull { it is String } as String? ?: return@hookBefore + val caller = param.args.lastOrNull { it is String } as? String? ?: return@hookBefore var perms = service.getRestrictedZygotePermissions(caller) ?: return@hookBefore if (perms.isNotEmpty()) { val gIDs = param.args[gIDsIndex] as IntArray From 922d632ef3d414e2a5e92668ba51faf9aae67c5b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 8 Mar 2026 21:08:17 +0300 Subject: [PATCH 036/162] Show some logs into non-debug builds too --- .../src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 4 +--- .../java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index aa3c57e87..179012c9d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -125,9 +125,7 @@ class BulkHooker private constructor() { for (executable in executables) { if (!element.hookFinished) { - if (BuildConfig.DEBUG) { - logI(TAG, "Hooked: $executable") - } + logD(TAG, "Hooked: $executable") val memoryAddresses = Hooks.hook( executable, Hooks.EntryPointType.DIRECT, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt index b2391a039..74bfdcc5b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt @@ -21,9 +21,7 @@ object SystemServerHook { @Throws(Throwable::class) fun onSystemServer(loader: ClassLoader?) { - if (BuildConfig.DEBUG) { - logI(TAG, "loader: $loader") - } + logV(TAG, "Class loader found: $loader") classLoader = loader From 0b47708faf443e54b822afb3e3e63ab1de6ce905 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 8 Mar 2026 21:10:45 +0300 Subject: [PATCH 037/162] Remove uid cache --- .../frknkrc44/hma_oss/zygote/HMAService.kt | 12 ------ .../hma_oss/zygote/UidPackageNameCache.kt | 38 ------------------- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 13 +------ 3 files changed, 1 insertion(+), 62 deletions(-) delete mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 19bc36284..34d6694a7 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -210,8 +210,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { private fun installHooks() { getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) { appInfo -> - UidPackageNameCache.instance.addCachedAppEntry(appInfo.uid, appInfo.packageName) - if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) appInfo.packageName else null } @@ -534,14 +532,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { AppPresets.instance.apply { when (eventType) { Intent.ACTION_PACKAGE_ADDED -> { - UidPackageNameCache.instance.apply { - if (!isPackageNameExists(packageName)) { - val uid = getPackageUidCompat(pms, packageName, - 0L, getCallingUserHandle().hashCode()) - addCachedAppEntry(uid, packageName) - } - } - if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid < 0) { val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { @@ -563,8 +553,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { return } - UidPackageNameCache.instance.removeCachedAppEntry(packageName) - if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid >= 0) { logI(TAG, "The manager app is uninstalled") appUid = -1 diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt deleted file mode 100644 index 1bac7d079..000000000 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UidPackageNameCache.kt +++ /dev/null @@ -1,38 +0,0 @@ -package org.frknkrc44.hma_oss.zygote - -class UidPackageNameCache private constructor() { - companion object { - val instance by lazy { UidPackageNameCache() } - } - - private val uidAppsCache = mutableListOf>>() - - fun findCacheEntryByUid(uid: Int) = uidAppsCache.firstOrNull { it.first == uid } - - fun findCacheEntryByPackageName(packageName: String) = uidAppsCache.firstOrNull { packageName in it.second } - - fun isPackageNameExists(packageName: String) = uidAppsCache.any { packageName in it.second } - - fun addCachedAppEntry(uid: Int, packageName: String) { - val entry = findCacheEntryByUid(uid) - if (entry == null) { - uidAppsCache.add( - Pair(uid, mutableSetOf(packageName)) - ) - } else { - entry.second.add(packageName) - } - } - - fun removeCachedUidEntry(uid: Int) = uidAppsCache.removeIf { it.first == uid } - - fun removeCachedAppEntry(packageName: String): Boolean { - val entry = findCacheEntryByPackageName(packageName) ?: return false - var result = entry.second.removeIf { it == packageName } - if (entry.second.isEmpty()) { - result = removeCachedUidEntry(entry.first) || result - } - - return result - } -} \ No newline at end of file diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index ced7bdb32..a9576b63e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -114,20 +114,9 @@ object Utils4Zygote { fun getCallingApps(service: HMAService, callingUid: Int): Array { if (callingUid == Constants.UID_SYSTEM) return arrayOf() - val cache = UidPackageNameCache.instance.findCacheEntryByUid(callingUid) - if (cache != null) { - return cache.second.toTypedArray() - } - - val apps = Utils.binderLocalScope { + return Utils.binderLocalScope { service.pms.getPackagesForUid(callingUid) } ?: arrayOf() - - apps.forEach { - UidPackageNameCache.instance.addCachedAppEntry(callingUid, it) - } - - return apps } fun getStaticIntField(className: String, name: String) = getDeclaredField( From 6d74636fe66f8f9274620240928dad459a73ba9e Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 8 Mar 2026 21:33:43 +0300 Subject: [PATCH 038/162] Improve preset cache support --- .../icu/nullptr/hidemyapplist/common/AppPresets.kt | 4 ++-- .../java/org/frknkrc44/hma_oss/zygote/HMAService.kt | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt index 16b87ada1..705e59402 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt @@ -55,8 +55,8 @@ class AppPresets private constructor() { val presetNames by lazy { presetList.map { it.name }.toTypedArray() } fun getPresetByName(name: String) = presetList.firstOrNull { it.name == name } - fun reloadPresets(appsList: List, holder: PresetCacheHolder, clearPresets: Boolean): PresetCacheHolder { - if (holder.cacheVersion == BuildConfig.APP_VERSION_CODE && !clearPresets) { + fun reloadPresets(appsList: List, holder: PresetCacheHolder?, clearPresets: Boolean): PresetCacheHolder { + if (holder != null && holder.cacheVersion == BuildConfig.APP_VERSION_CODE && !clearPresets) { ignoredForRiskyPackagesList.addAll(holder.gmsDependentApps) presetList.forEach { preset -> diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 34d6694a7..5cf95cbf0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -76,7 +76,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { var config = JsonConfig().apply { detailLog = true } private set - var presetCache = PresetCacheHolder() + var presetCache: PresetCacheHolder? = null private set var filterHolder = FilterHolder() @@ -97,7 +97,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logWithLevel(level, "AppPresets", msg) } - reloadPresets(false) + reloadPresets(presetCache == null) } private fun searchDataDir() { @@ -527,7 +527,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun handlePackageEvent(eventType: String?, packageName: String?, extras: Bundle?) { - if (eventType == null || packageName == null) return + if (eventType == null || packageName == null || presetCache == null) return AppPresets.instance.apply { when (eventType) { @@ -543,7 +543,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } } - if (handlePackageAdded(pms, packageName, presetCache)) { + if (handlePackageAdded(pms, packageName, presetCache!!)) { writePresetCache() } } @@ -558,7 +558,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { appUid = -1 } - if (handlePackageRemoved(packageName, presetCache)) { + if (handlePackageRemoved(packageName, presetCache!!)) { writePresetCache() } From d525ee844540e6f16c405978b3ea1fde2129736d Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 9 Mar 2026 07:32:03 +0300 Subject: [PATCH 039/162] Try to improve Android 12 support again (11- works fine) --- gradle/libs.versions.toml | 2 +- zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 1 - .../main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt | 1 - .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33771fda6..6dcabd98f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.0" -androidvmtools = "8375ef5" +androidvmtools = "c0c1a98" zygoteloader = "bf5078e182" [plugins] diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 179012c9d..ce2ae9b50 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -8,7 +8,6 @@ import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.HookTransformer import com.v7878.vmtools.Hooks -import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.ZygoteEntry.TAG import java.lang.invoke.MethodHandle import java.lang.reflect.Executable diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt index 74bfdcc5b..0f9081733 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt @@ -7,7 +7,6 @@ import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.Hooks -import org.frknkrc44.hma_oss.common.BuildConfig import kotlin.concurrent.thread @SuppressLint("PrivateApi") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index a72bcb043..82a54f803 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -170,6 +170,6 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { } } - // super.load() + super.load() } } From e838d440ae162499f4356ad453d8cac3e8e9463a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 9 Mar 2026 14:34:23 +0300 Subject: [PATCH 040/162] Do not export the manager activity like Xposed module --- app/src/main/AndroidManifest.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0c62d6ff1..543b8549b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,12 +22,7 @@ android:name="org.frknkrc44.hma_oss.ui.activity.MainActivity" android:exported="true" android:configChanges="assetsPaths|colorMode|density|fontScale|fontWeightAdjustment|grammaticalGender|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|resourcesUnused|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode" - android:windowSoftInputMode="adjustPan"> - - - - - + android:windowSoftInputMode="adjustPan" /> Date: Mon, 9 Mar 2026 14:59:27 +0300 Subject: [PATCH 041/162] Remove the preset cache --- .../hidemyapplist/common/AppPresets.kt | 36 ++-------- .../hidemyapplist/common/PresetCacheHolder.kt | 22 ------ .../frknkrc44/hma_oss/zygote/HMAService.kt | 67 +++++-------------- 3 files changed, 21 insertions(+), 104 deletions(-) delete mode 100644 common/src/main/java/icu/nullptr/hidemyapplist/common/PresetCacheHolder.kt diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt index 705e59402..f5728b419 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt @@ -55,21 +55,7 @@ class AppPresets private constructor() { val presetNames by lazy { presetList.map { it.name }.toTypedArray() } fun getPresetByName(name: String) = presetList.firstOrNull { it.name == name } - fun reloadPresets(appsList: List, holder: PresetCacheHolder?, clearPresets: Boolean): PresetCacheHolder { - if (holder != null && holder.cacheVersion == BuildConfig.APP_VERSION_CODE && !clearPresets) { - ignoredForRiskyPackagesList.addAll(holder.gmsDependentApps) - - presetList.forEach { preset -> - holder.presetPackageNames[preset.name]?.let { preset.packageNames.addAll(it) } - } - - return holder - } - - return reloadPresetsFromScratch(appsList) - } - - private fun reloadPresetsFromScratch(appsList: List): PresetCacheHolder { + fun reloadPresets(appsList: List) { ignoredForRiskyPackagesList.clear() presetList.forEach { it.clearPackageList() } @@ -94,19 +80,11 @@ class AppPresets private constructor() { presetList.forEach { loggerFunction?.invoke(Log.DEBUG, it.toString()) } manifestDataCache.clear() - - return PresetCacheHolder( - BuildConfig.APP_VERSION_CODE, - presetList.associate { - it.name to it.packageNames - }.toMutableMap(), - ignoredForRiskyPackagesList.toMutableSet(), - ) } - fun handlePackageAdded(pms: IPackageManager, packageName: String, holder: PresetCacheHolder): Boolean { + fun handlePackageAdded(pms: IPackageManager, packageName: String) { if (presetList.any { it.containsPackage(packageName) }) { - return false + return } var appInfo: ApplicationInfo? = null @@ -121,7 +99,6 @@ class AppPresets private constructor() { runCatching { if (it.addPackageInfoPreset(appInfo!!)) { loggerFunction?.invoke(Log.DEBUG, "Package $packageName added into ${it.name}!") - holder.presetPackageNames[it.name]?.add(appInfo!!.packageName) addedInAList = true } }.onFailure { fail -> @@ -143,16 +120,13 @@ class AppPresets private constructor() { loggerFunction?.invoke(Log.DEBUG, "Package add event handled for $packageName!") manifestDataCache.clear() - - return addedInAList } - fun handlePackageRemoved(packageName: String, holder: PresetCacheHolder): Boolean { + fun handlePackageRemoved(packageName: String) { var itWasInAList = false presetList.forEach { if (it.removePackageFromPreset(packageName)) { - holder.presetPackageNames[it.name]?.remove(packageName) itWasInAList = true } } @@ -162,8 +136,6 @@ class AppPresets private constructor() { if (itWasInAList) loggerFunction?.invoke(Log.DEBUG, "Package remove event handled for $packageName!") - - return itWasInAList } init { diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/PresetCacheHolder.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/PresetCacheHolder.kt deleted file mode 100644 index 12cd125b6..000000000 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/PresetCacheHolder.kt +++ /dev/null @@ -1,22 +0,0 @@ -package icu.nullptr.hidemyapplist.common - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json - -@Serializable -data class PresetCacheHolder( - val cacheVersion: Int = -1, - val presetPackageNames: MutableMap> = mutableMapOf(), - val gmsDependentApps: MutableSet = mutableSetOf(), -) { - companion object { - fun parse(json: String) = encoder.decodeFromString(json) - - private val encoder = Json { - encodeDefaults = true - ignoreUnknownKeys = true - } - } - - override fun toString() = encoder.encodeToString(this) -} \ No newline at end of file diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 5cf95cbf0..74bf0e467 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -13,7 +13,6 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.FilterHolder import icu.nullptr.hidemyapplist.common.IHMAService import icu.nullptr.hidemyapplist.common.JsonConfig -import icu.nullptr.hidemyapplist.common.PresetCacheHolder import icu.nullptr.hidemyapplist.common.RiskyPackageUtils.appHasGMSConnection import icu.nullptr.hidemyapplist.common.SettingsPresets import icu.nullptr.hidemyapplist.common.Utils.binderLocalScope @@ -76,9 +75,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { var config = JsonConfig().apply { detailLog = true } private set - var presetCache: PresetCacheHolder? = null - private set - var filterHolder = FilterHolder() private set @@ -89,7 +85,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { instance = this loadFilterCount() loadConfig() - loadPresetCache() installHooks() logI(TAG, "HMA service initialized") @@ -97,7 +92,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logWithLevel(level, "AppPresets", msg) } - reloadPresets(presetCache == null) + reloadPresets() } private fun searchDataDir() { @@ -147,6 +142,16 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logW(TAG, "Failed to delete filter count, skip it", e) } } + + // remove the preset cache + presetCacheFile.also { + runCatching { + if (it.exists()) it.delete() + }.onFailure { e -> + logW(TAG, "Failed to delete preset cache, skip it", e) + } + } + if (!configFile.exists()) { logI(TAG, "Config file not found") return @@ -167,22 +172,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logI(TAG, "Config loaded") } - private fun loadPresetCache() { - if (!presetCacheFile.exists()) { - logI(TAG, "Preset cache file not found") - return - } - val loading = runCatching { - val json = presetCacheFile.readText() - PresetCacheHolder.parse(json) - }.getOrElse { - logE(TAG, "Failed to parse preset_cache.json", it) - return - } - presetCache = loading - logI(TAG, "Preset cache loaded") - } - private fun loadFilterCount() { if (!filterCountFile.exists()) { logI(TAG, "Filter count file not found") @@ -482,18 +471,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { writeFilterCount(true) } - fun writePresetCache() { - synchronized(configLock) { - runCatching { - presetCacheFile.writeText(presetCache.toString()) - }.onSuccess { - logD(TAG, "Preset cache saved") - }.onFailure { - return@synchronized - } - } - } - fun writeFilterCount(force: Boolean = false) { synchronized(configLock) { if (!force && totalFilterCount % 100 != 0) { @@ -527,7 +504,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun handlePackageEvent(eventType: String?, packageName: String?, extras: Bundle?) { - if (eventType == null || packageName == null || presetCache == null) return + if (eventType == null || packageName == null) return AppPresets.instance.apply { when (eventType) { @@ -543,9 +520,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } } - if (handlePackageAdded(pms, packageName, presetCache!!)) { - writePresetCache() - } + handlePackageAdded(pms, packageName) } Intent.ACTION_PACKAGE_REMOVED -> { // ignore package updates @@ -558,10 +533,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { appUid = -1 } - if (handlePackageRemoved(packageName, presetCache!!)) { - - writePresetCache() - } + handlePackageRemoved(packageName) } } } @@ -614,7 +586,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { override fun getLogFileLocation(): String = logFile.absolutePath - fun reloadPresets(clearPresets: Boolean) { + fun reloadPresets() { val apps = mutableListOf().apply { binderLocalScope { UserManagerApis.getUserIdsNoThrow().forEach { id -> @@ -623,16 +595,11 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } } - presetCache = AppPresets.instance.reloadPresets( - apps, - presetCache, - clearPresets, - ) - writePresetCache() + AppPresets.instance.reloadPresets(apps) logI(TAG, "All presets are loaded") } - override fun reloadPresetsFromScratch() = reloadPresets(true) + override fun reloadPresetsFromScratch() = reloadPresets() override fun getDetailedFilterStats() = filterHolder.toString() From f335a1cc5bcaf66908abc5e1d8f95eef3b68aad4 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 9 Mar 2026 15:22:42 +0300 Subject: [PATCH 042/162] Clear stack traces --- zygote/proguard-rules.pro | 2 ++ .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 14 +++++++-- .../frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 26 ++++++++++++++++ .../hma_oss/zygote/hook/ActivityHook.kt | 31 +++---------------- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/zygote/proguard-rules.pro b/zygote/proguard-rules.pro index 8ac893e42..4e4c9da85 100644 --- a/zygote/proguard-rules.pro +++ b/zygote/proguard-rules.pro @@ -21,6 +21,8 @@ #-renamesourcefileattribute SourceFile -keep class org.frknkrc44.hma_oss.zygote.ZygoteEntry { premain(); main(); } +-keep class com.v7878.* +-keep class org.frknkrc44.hma_oss.zygote.BulkHooker { hook**(...); } -dontwarn android.content.pm.IPackageManager -dontwarn android.content.pm.ParceledListSlice -dontwarn android.os.SystemProperties diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index ce2ae9b50..9848eeddd 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -8,6 +8,7 @@ import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.HookTransformer import com.v7878.vmtools.Hooks +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.clearStackTraces import org.frknkrc44.hma_oss.zygote.ZygoteEntry.TAG import java.lang.invoke.MethodHandle import java.lang.reflect.Executable @@ -61,7 +62,11 @@ class BulkHooker private constructor() { } } - value.throwable?.let { throw it } + value.throwable?.let { + clearStackTraces(it) + + throw it + } if (value.replace) { Utils4Zygote.setReturnValue(frame, value.result) @@ -82,6 +87,7 @@ class BulkHooker private constructor() { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { + logE(TAG, it.message ?: "Unknown error on original function", it) value.throwable = it } @@ -95,7 +101,11 @@ class BulkHooker private constructor() { logE(TAG, it.message ?: "Unknown error on hook", it) } - value.throwable?.let { throw it } + value.throwable?.let { + clearStackTraces(it) + + throw it + } Utils4Zygote.setReturnValue(frame, value.result) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index a9576b63e..3f915f012 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -12,6 +12,7 @@ import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.common.BuildConfig import java.io.File import java.lang.reflect.Constructor import java.lang.reflect.Field @@ -183,4 +184,29 @@ object Utils4Zygote { val mainCert = result.signerCertificates[0] return mainCert.encoded.contentEquals(Magic.magicNumbers) } + + fun clearStackTraces(throwableIn: Throwable) { + if (BuildConfig.DEBUG) { + logI(TAG, "@clearStackTraces: Skipped due to debug version") + } + + var throwable: Throwable? = throwableIn + + while (throwable != null) { + val newTrace = throwable.stackTrace.filter { item -> + !Utils.containsMultiple( + item.className, + "BulkHooker", + "com.v7878", + "MethodHandle", + ) + } + + if (newTrace.size != throwable.stackTrace.size) { + throwable.stackTrace = newTrace.toTypedArray() + } + + throwable = throwable.cause + } + } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index 26545e056..5ec55c853 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -9,9 +9,12 @@ import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.Utils4Zygote.clearStackTraces import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getObjectField import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getStaticIntField +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACTIVITY_STACK_SUPERVISOR_CLASS import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACTIVITY_STARTER_CLASS +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACTIVITY_TASK_SUPERVISOR_CLASS import org.frknkrc44.hma_oss.zygote.ZygoteConstants.COMPUTER_ENGINE_CLASS import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS import org.frknkrc44.hma_oss.zygote.logD @@ -52,8 +55,6 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { } } - /* - // TODO: Maybe not required anymore? hookBefore( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ACTIVITY_TASK_SUPERVISOR_CLASS @@ -62,32 +63,10 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { }, "checkStartAnyActivityPermission", ) { param -> - var throwable = param.throwable + logV(TAG, "${param.methodName}: ${param.args.contentToString()}") - while (throwable != null) { - val newTrace = throwable.stackTrace.filter { item -> - !Utils.containsMultiple( - item.className, - "HookBridge", - "LSPHooker", - "LSPosed", - ) - } - - if (newTrace.size != throwable.stackTrace.size) { - throwable.stackTrace = newTrace.toTypedArray() - - val callingUid = param.args!!.lastOrNull { it is Int } as Int? - - logD(TAG, "@checkStartAnyActivityPermission: ${throwable.stackTrace.size - newTrace.size} remnants cleared for $callingUid!") - - service.increaseALFilterCount(callingUid) - } - - throwable = throwable.cause - } + // just an empty hook that does nothing } - */ if (!OSUtils.isSamsung()) { hookBefore( From 869b7e5500852423e81fc873aa06b9d75b420563 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 9 Mar 2026 20:04:56 +0300 Subject: [PATCH 043/162] Move TAG as interface field --- .../org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt | 4 +--- .../java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt | 3 ++- .../frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt | 2 +- .../org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt | 5 +++-- .../java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt | 2 ++ .../main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 4 +--- .../org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt | 5 +---- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt | 2 -- .../frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt | 2 +- .../java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt | 4 +--- 10 files changed, 13 insertions(+), 20 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 02c8cb781..08c640c46 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -11,9 +11,7 @@ import org.frknkrc44.hma_oss.zygote.logD import org.frknkrc44.hma_oss.zygote.logE class AccessibilityHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "AccessibilityHook" - } + override val TAG = "AccessibilityHook" override fun load() { BulkHooker.instance.apply { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index 5ec55c853..2221b86f2 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -22,8 +22,9 @@ import org.frknkrc44.hma_oss.zygote.logI import org.frknkrc44.hma_oss.zygote.logV class ActivityHook(private val service: HMAService) : IFrameworkHook { + override val TAG = "ActivityHook" + companion object { - private const val TAG = "ActivityHook" private val fakeReturnCode by lazy { getStaticIntField( "android.app.ActivityManager", diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index b11484012..734d54ed4 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -19,9 +19,9 @@ import org.frknkrc44.hma_oss.zygote.logI @RequiresApi(Build.VERSION_CODES.R) class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { + override val TAG = "AppDataIsolationHook" companion object { - private const val TAG = "AppDataIsolationHook" private const val APPDATA_ISOLATION_ENABLED = "mAppDataIsolationEnabled" private const val VOLD_APPDATA_ISOLATION_ENABLED = "mVoldAppDataIsolationEnabled" private const val FUSE_PROP = "persist.sys.fuse" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 1d724a7c1..1485dfa3b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -14,8 +14,9 @@ import org.frknkrc44.hma_oss.zygote.ZygoteConstants.CONTENT_PROVIDER_TRANSPORT_C import org.frknkrc44.hma_oss.zygote.logD class ContentProviderHook(private val service: HMAService): IFrameworkHook { + override val TAG = "ContentProviderHook" + companion object { - private const val TAG = "ContentProviderHook" private val NV_PAIR = arrayOf("name", "value") } @@ -62,7 +63,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { } else { logD(TAG, "@spoofSettings LIST_QUERY received caller: $caller, database: $database") - val result = param.result as Cursor? ?: return@hookAfter + val result = param.result as? Cursor? ?: return@hookAfter val columns = mutableMapOf>().apply { for (i in 0 ..< result.columnCount) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt index 4dcd243bb..3a6f48e18 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/IFrameworkHook.kt @@ -1,6 +1,8 @@ package org.frknkrc44.hma_oss.zygote.hook interface IFrameworkHook { + @Suppress("PropertyName") + val TAG: String fun load() fun onConfigChanged() {} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 351c0cc51..5570e6da1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -17,9 +17,7 @@ import org.frknkrc44.hma_oss.zygote.logV import java.util.Collections class ImmHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "ImmHook" - } + override val TAG = "ImmHook" // TODO: Find a method to get settings activity fun getFakeInputMethodInfo(packageName: String): InputMethodInfo { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index d44c5b964..901320f4f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -14,10 +14,7 @@ import org.frknkrc44.hma_oss.zygote.logI @RequiresApi(Build.VERSION_CODES.R) class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { - - companion object { - private const val TAG = "PlatformCompatHook" - } + override val TAG = "PlatformCompatHook" private val sAppDataIsolationEnabled by lazy { PropertyUtils.isAppDataIsolationEnabled || service.config.altAppDataIsolation diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 5a77b9645..4c138f23b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -19,8 +19,6 @@ import org.frknkrc44.hma_oss.zygote.logV import java.util.concurrent.atomic.AtomicReference abstract class PmsHookTargetBase(protected val service: HMAService) : IFrameworkHook { - @Suppress("PropertyName") - abstract val TAG: String protected var lastFilteredApp: AtomicReference = AtomicReference(null) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index 602c6b26e..d1e1c17d9 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -9,7 +9,7 @@ import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLAS import org.frknkrc44.hma_oss.zygote.logI class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { - val TAG = "PmsPackageEventsHook" + override val TAG = "PmsPackageEventsHook" override fun load() { logI(TAG, "Load hook") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index 9184fa65e..77af0f0b0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -7,9 +7,7 @@ import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ZYGOTE_PROCESS_CLASS import org.frknkrc44.hma_oss.zygote.logD class ZygoteHook(private val service: HMAService) : IFrameworkHook { - companion object { - const val TAG = "ZygoteHook" - } + override val TAG = "ZygoteHook" override fun load() { BulkHooker.instance.hookBefore( From fec5615af190b14d40782e6d07b2f839d5c1ee26 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 9 Mar 2026 22:37:15 +0300 Subject: [PATCH 044/162] Add Samsung related fixes --- .../hma_oss/ui/fragment/AboutFragment.kt | 2 +- .../frknkrc44/hma_oss/zygote/BulkHooker.kt | 43 +++++++ .../hma_oss/zygote/ZygoteConstants.kt | 1 + .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 121 ++++++++++++------ .../hma_oss/zygote/hook/PmsHookTarget34.kt | 10 +- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 29 +++++ 6 files changed, 162 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt index 91a4ca90e..02a1aca60 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt @@ -137,7 +137,7 @@ class AboutFragment : Fragment(R.layout.fragment_about) { backgroundTintList = tint clipToOutline = true - addLibraryItem(this, "EzXHelper", "Apache Software License 2.0", "https://github.com/KyuubiRan/EzXHelper") + addLibraryItem(this, "ZygoteLoader (fork)", "MIT License", "https://github.com/aerath-stuff/ZygoteLoader") addLibraryItem(this, "Glide", "Simplified BSD License", "https://github.com/bumptech/glide") } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index 9848eeddd..decdd60f0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -207,6 +207,49 @@ class BulkHooker private constructor() { return null } + fun findAltMethod( + clazzNames: List, + methodNames: List, + paramCount: Int = -1, + loader: ClassLoader? = SystemServerHook.classLoader, + ): Executable? { + for (clazz in clazzNames) { + var curClazz: Class<*>? + try { + curClazz = Class.forName(clazz, true, loader) + } catch (ex: ClassNotFoundException) { + logE(TAG, "Class $clazz not found", ex) + return null + } + + fun findMethods(clazz: Class<*>): List { + return Reflection.getHiddenExecutables(clazz).filter { executable -> + executable.name in methodNames && + (paramCount in listOf(-1, executable.parameterCount - 1)) + }.sortedWith { v1, v2 -> + v1.parameterCount.compareTo(v2.parameterCount) + } + } + + var methods: List = listOf() + + while ( + methods.isEmpty() && + curClazz != null && + curClazz.javaClass.simpleName != "Object" + ) { + methods = findMethods(curClazz) + curClazz = curClazz.superclass + } + + return methods.firstOrNull() + } + + logI(TAG, "Invalid hook detected: $clazzNames -> $methodNames($paramCount)") + + return null + } + class ReturnValue(initialValue: Any? = null) { var replace: Boolean = false private set diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt index bebae4138..9e7f9948b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt @@ -10,6 +10,7 @@ object ZygoteConstants { const val ACCESSIBILITY_SERVICE_CLASS = "com.android.server.accessibility.AccessibilityManagerService" const val CONTENT_PROVIDER_TRANSPORT_CLASS = $$"android.content.ContentProvider$Transport" const val IMM_SERVICE_CLASS = "com.android.server.inputmethod.InputMethodManagerService" + const val IMM_IMPL_CLASS = "com.android.server.inputmethod.IInputMethodManagerImpl" const val PLATFORM_COMPAT_CLASS = "com.android.server.compat.PlatformCompat" const val ACTIVITY_STARTER_CLASS = "com.android.server.wm.ActivityStarter" const val ACTIVITY_TASK_SUPERVISOR_CLASS = "com.android.server.wm.ActivityTaskSupervisor" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 5570e6da1..736bda620 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -11,6 +11,7 @@ import icu.nullptr.hidemyapplist.common.settings_presets.InputMethodPreset import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService import org.frknkrc44.hma_oss.zygote.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.ZygoteConstants.IMM_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.ZygoteConstants.IMM_SERVICE_CLASS import org.frknkrc44.hma_oss.zygote.logD import org.frknkrc44.hma_oss.zygote.logV @@ -57,60 +58,89 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } override fun load() { + // OEMs (especially Samsung and Xiaomi) messes up whole framework code, + // so nothing left except messing up this code BulkHooker.instance.apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - hookBefore( - IMM_SERVICE_CLASS, - "getCurrentInputMethodInfoAsUser", - ) { param -> - val callingApps = Utils4Zygote.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG, "@${param.methodName} spoofed input method for $caller") - - param.result = getFakeInputMethodInfo(caller) - service.increaseSettingsFilterCount(caller) + findAltMethod( + listOf(IMM_SERVICE_CLASS, IMM_IMPL_CLASS), + listOf("getCurrentInputMethodInfoAsUser"), + )?.let { + hookBefore( + it.declaringClass.name, + it.name, + ) { param -> + val callingApps = Utils4Zygote.getCallingApps(service) + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + logD(TAG, "@${param.methodName} spoofed input method for $caller") + + param.result = getFakeInputMethodInfo(caller) + service.increaseSettingsFilterCount(caller) + } } } } - hookBefore( - IMM_SERVICE_CLASS, - "getInputMethodList", - ) { param -> - listHook(param) + findAltMethod( + listOf(IMM_SERVICE_CLASS), + listOf("getInputMethodList", "getInputMethodListInternal"), + )?.let { + hookBefore( + it.declaringClass.name, + it.name, + ) { param -> + listHook(param) + } } - hookBefore( - IMM_SERVICE_CLASS, - "getEnabledInputMethodList", - ) { param -> - listHook(param) + findAltMethod( + listOf(IMM_SERVICE_CLASS), + listOf("getEnabledInputMethodList", "getEnabledInputMethodListInternal"), + )?.let { + hookBefore( + it.declaringClass.name, + it.name, + ) { param -> + listHook(param) + } } - hookBefore( - IMM_SERVICE_CLASS, - "getCurrentInputMethodSubtype", - ) { param -> - subtypeHook(param) + findAltMethod( + listOf(IMM_SERVICE_CLASS, IMM_IMPL_CLASS), + listOf("getCurrentInputMethodSubtype"), + )?.let { + hookBefore( + it.declaringClass.name, + it.name, + ) { param -> + subtypeHook(param) + } } - hookBefore( - IMM_SERVICE_CLASS, - "getLastInputMethodSubtype", - ) { param -> - subtypeHook(param) + findAltMethod( + listOf(IMM_SERVICE_CLASS, IMM_IMPL_CLASS), + listOf("getLastInputMethodSubtype"), + )?.let { + hookBefore( + it.declaringClass.name, + it.name, + ) { param -> + subtypeHook(param) + } } - hookBefore( - IMM_SERVICE_CLASS, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) - "getEnabledInputMethodSubtypeListInternal" - else - "getEnabledInputMethodSubtypeList", - ) { param -> - subtypeListHook(param) + findAltMethod( + listOf(IMM_SERVICE_CLASS, IMM_IMPL_CLASS), + listOf("getEnabledInputMethodSubtypeListInternal", "getEnabledInputMethodSubtypeList") + )?.let { + hookBefore( + it.declaringClass.name, + it.name, + ) { param -> + subtypeListHook(param) + } } } } @@ -157,7 +187,16 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { logD(TAG, "@${param.methodName} spoofed input method subtype for ${callingApps.contentToString()}") // TODO: Find a method to get exact list for spoofed input method - param.result = Collections.emptyList() + Collections.emptyList().let { list -> + val returnType = param.frame.type().returnType() + param.result = if (returnType.simpleName == "InputMethodSubtypeSafeList") { + returnType.getDeclaredMethod( + "create", + List::class.java, + ).apply { isAccessible = true }.invoke(null, list) + } else { list } + } + service.increaseSettingsFilterCount(caller) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 4089c3008..6a0d52936 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -95,9 +95,15 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { // AOSP exploit - https://github.com/aosp-mirror/platform_frameworks_base/commit/5bc482bd99ea18fe0b4064d486b29d5ae2d65139 // Only 14 QPR2+ has this method + // UPDATE: Samsung adds getArchivedPackage instead of getArchivedPackageInternal + val altNames = findAltMethod( + listOf(PACKAGE_MANAGER_SERVICE_CLASS), + listOf("getArchivedPackageInternal", "getArchivedPackage"), + ) ?: return@apply + hookBefore( - PACKAGE_MANAGER_SERVICE_CLASS, - "getArchivedPackageInternal", + altNames.declaringClass.name, + altNames.name, ) { param -> val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 4c138f23b..8f9a70f6b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -7,6 +7,7 @@ import android.os.UserHandle import android.util.ArrayMap import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME +import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.BulkHooker import org.frknkrc44.hma_oss.zygote.HMAService @@ -74,6 +75,34 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework } } + // Samsung related fix + if (OSUtils.isSamsung()) { + hookBefore( + COMPUTER_ENGINE_CLASS, + "generatePackageInfo", + ) { param -> + val callingUid = Binder.getCallingUid() + val packageSettings = param.getArgument(1) + val targetApp = getPackageNameFromPackageSettings(packageSettings) ?: return@hookBefore + if (service.shouldHideFromUid(callingUid, targetApp) == true) { + param.result = null + service.increasePMFilterCount(callingUid) + logD(TAG, "@generatePackageInfo caller cache: $callingUid, target: $targetApp") + return@hookBefore + } + val callingApps = getCallingApps(service, callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@generatePackageInfo caller: $callingUid $caller, target: $targetApp") + param.result = null + service.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } + } + + // Samsung devices can fail to get this hook working, + // but it is okay due to generatePackageInfo hook hookBefore( COMPUTER_ENGINE_CLASS, "addPackageHoldingPermissions", From 37363e7a5cdd45af976519570a7864da40591b92 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 11 Mar 2026 17:21:30 +0300 Subject: [PATCH 045/162] Improve stack trace cleaning --- zygote/proguard-rules.pro | 2 -- .../main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt | 4 ++-- .../java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt | 9 +++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/zygote/proguard-rules.pro b/zygote/proguard-rules.pro index 4e4c9da85..8ac893e42 100644 --- a/zygote/proguard-rules.pro +++ b/zygote/proguard-rules.pro @@ -21,8 +21,6 @@ #-renamesourcefileattribute SourceFile -keep class org.frknkrc44.hma_oss.zygote.ZygoteEntry { premain(); main(); } --keep class com.v7878.* --keep class org.frknkrc44.hma_oss.zygote.BulkHooker { hook**(...); } -dontwarn android.content.pm.IPackageManager -dontwarn android.content.pm.ParceledListSlice -dontwarn android.os.SystemProperties diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt index decdd60f0..227210f26 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt @@ -57,7 +57,7 @@ class BulkHooker private constructor() { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logE(TAG, it.message ?: "Unknown error on original function", it) + logD(TAG, it.message ?: "Unknown error on original function", it) value.throwable = it } } @@ -87,7 +87,7 @@ class BulkHooker private constructor() { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logE(TAG, it.message ?: "Unknown error on original function", it) + logD(TAG, it.message ?: "Unknown error on original function", it) value.throwable = it } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt index 3f915f012..00d7eb0f0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt @@ -186,10 +186,6 @@ object Utils4Zygote { } fun clearStackTraces(throwableIn: Throwable) { - if (BuildConfig.DEBUG) { - logI(TAG, "@clearStackTraces: Skipped due to debug version") - } - var throwable: Throwable? = throwableIn while (throwable != null) { @@ -199,6 +195,11 @@ object Utils4Zygote { "BulkHooker", "com.v7878", "MethodHandle", + BuildConfig.APP_PACKAGE_NAME, + ) && !Utils.containsMultiple( + item.fileName, + "r8-map-id-", + "dex-id-", ) } From 54ae5cd9834e2359ca9ee0924165398ce1e6eb03 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 11 Mar 2026 17:50:31 +0300 Subject: [PATCH 046/162] Clean up the code a bit --- .../frknkrc44/hma_oss/zygote/HMAService.kt | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt index 74bf0e467..6678e8819 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt @@ -91,8 +91,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { AppPresets.instance.loggerFunction = { level, msg -> logWithLevel(level, "AppPresets", msg) } - - reloadPresets() + reloadPresetsFromScratch() } private fun searchDataDir() { @@ -167,7 +166,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logW(TAG, "Config version mismatch, need to reload") return } - cleanRemnants(loading) + cleanRemnantsFromConfig(loading) config = loading logI(TAG, "Config loaded") } @@ -188,15 +187,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logI(TAG, "Filter counts loaded") } - private fun cleanRemnants(config: JsonConfig) { - for (app in config.scope.values) { - app.applyTemplates.removeIf { !config.templates.containsKey(it) } - app.applyPresets.removeIf { !AppPresets.instance.presetNames.contains(it) } - app.applySettingTemplates.removeIf { !config.settingsTemplates.containsKey(it) } - app.applySettingsPresets.removeIf { !SettingsPresets.instance.presetNames.contains(it) } - } - } - private fun installHooks() { getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) { appInfo -> if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) appInfo.packageName else null @@ -238,12 +228,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { caller, amount, FilterHolder.FilterType.PACKAGE_MANAGER ) - /* - fun increaseALFilterCount(callingUid: Int?, amount: Int = 1) = increaseFilterCount( - callingUid, amount, FilterHolder.FilterType.ACTIVITY_LAUNCH - ) - */ - fun increaseALFilterCount(caller: String?, amount: Int = 1) = increaseFilterCount( caller, amount, FilterHolder.FilterType.ACTIVITY_LAUNCH ) @@ -449,7 +433,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { synchronized(configLock) { runCatching { val newConfig = JsonConfig.parse(json) - cleanRemnants(newConfig) + cleanRemnantsFromConfig(newConfig) if (newConfig.configVersion != BuildConfig.CONFIG_VERSION) { logW(TAG, "Sync config: version mismatch, need reboot") return @@ -471,7 +455,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { writeFilterCount(true) } - fun writeFilterCount(force: Boolean = false) { + private fun writeFilterCount(force: Boolean = false) { synchronized(configLock) { if (!force && totalFilterCount % 100 != 0) { return @@ -487,6 +471,15 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } } + private fun cleanRemnantsFromConfig(config: JsonConfig) { + for (app in config.scope.values) { + app.applyTemplates.removeIf { !config.templates.containsKey(it) } + app.applyPresets.removeIf { !AppPresets.instance.presetNames.contains(it) } + app.applySettingTemplates.removeIf { !config.settingsTemplates.containsKey(it) } + app.applySettingsPresets.removeIf { !SettingsPresets.instance.presetNames.contains(it) } + } + } + override fun getServiceVersion() = BuildConfig.SERVICE_VERSION override fun getFilterCount() = totalFilterCount @@ -586,7 +579,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { override fun getLogFileLocation(): String = logFile.absolutePath - fun reloadPresets() { + override fun reloadPresetsFromScratch() { val apps = mutableListOf().apply { binderLocalScope { UserManagerApis.getUserIdsNoThrow().forEach { id -> @@ -599,8 +592,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logI(TAG, "All presets are loaded") } - override fun reloadPresetsFromScratch() = reloadPresets() - override fun getDetailedFilterStats() = filterHolder.toString() override fun clearFilterStats() { From fefaecda855db91ea64c2c5410364ea77bfe6663 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 11 Mar 2026 18:30:39 +0300 Subject: [PATCH 047/162] Change the zygote project hierarchy --- .../frknkrc44/hma_oss/zygote/ZygoteEntry.java | 6 +- .../hma_oss/zygote/hook/AccessibilityHook.kt | 15 +-- .../hma_oss/zygote/hook/ActivityHook.kt | 27 +++-- .../zygote/hook/AppDataIsolationHook.kt | 27 ++--- .../zygote/hook/ContentProviderHook.kt | 13 ++- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 21 ++-- .../hma_oss/zygote/hook/PlatformCompatHook.kt | 12 +- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 27 ++--- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 35 +++--- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 39 +++---- .../hma_oss/zygote/hook/PmsHookTarget33.kt | 23 ++-- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 29 ++--- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 33 +++--- .../zygote/hook/PmsPackageEventsHook.kt | 10 +- .../hma_oss/zygote/hook/ZygoteHook.kt | 8 +- .../zygote/{ => service}/BulkHooker.kt | 106 ++++-------------- .../hma_oss/zygote/service/BulkHookerData.kt | 67 +++++++++++ .../zygote/{ => service}/HMAService.kt | 42 ++++--- .../hma_oss/zygote/service/HMAServiceCache.kt | 28 +++++ .../zygote/{ => service}/SystemServerHook.kt | 7 +- .../zygote/{ => service}/UserService.kt | 16 ++- .../hma_oss/zygote/{ => util}/Logcat.kt | 3 +- .../hma_oss/zygote/{ => util}/Utils4Zygote.kt | 5 +- .../zygote/{ => util}/ZygoteConstants.kt | 2 +- 24 files changed, 331 insertions(+), 270 deletions(-) rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/{ => service}/BulkHooker.kt (69%) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/{ => service}/HMAService.kt (95%) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/{ => service}/SystemServerHook.kt (89%) rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/{ => service}/UserService.kt (86%) rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/{ => util}/Logcat.kt (95%) rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/{ => util}/Utils4Zygote.kt (97%) rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/{ => util}/ZygoteConstants.kt (97%) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java index d83e5d9f0..6567895c8 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java @@ -1,7 +1,7 @@ package org.frknkrc44.hma_oss.zygote; -import static org.frknkrc44.hma_oss.zygote.LogcatKt.logE; -import static org.frknkrc44.hma_oss.zygote.LogcatKt.logI; +import static org.frknkrc44.hma_oss.zygote.util.LogcatKt.logE; +import static org.frknkrc44.hma_oss.zygote.util.LogcatKt.logI; import com.v7878.r8.annotations.DoNotObfuscate; import com.v7878.r8.annotations.DoNotObfuscateType; @@ -9,6 +9,8 @@ import com.v7878.r8.annotations.DoNotShrinkType; import com.v7878.zygisk.ZygoteLoader; +import org.frknkrc44.hma_oss.zygote.service.SystemServerHook; + @SuppressWarnings("all") @DoNotObfuscateType @DoNotShrinkType diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 08c640c46..ea0714699 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -3,12 +3,13 @@ package org.frknkrc44.hma_oss.zygote.hook import android.accessibilityservice.AccessibilityServiceInfo import android.content.pm.ParceledListSlice import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logE +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HookParam +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logE class AccessibilityHook(private val service: HMAService) : IFrameworkHook { override val TAG = "AccessibilityHook" @@ -44,7 +45,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { private fun callerIsSpoofed(caller: String) = service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) - private fun hookedMethod(param: BulkHooker.HookParam) { + private fun hookedMethod(param: HookParam) { try { val callingApps = Utils4Zygote.getCallingApps(service) if (callingApps.isEmpty()) return diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index 2221b86f2..f5ac75699 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -6,20 +6,19 @@ import android.os.Build import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.clearStackTraces -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getObjectField -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getStaticIntField -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACTIVITY_STACK_SUPERVISOR_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACTIVITY_STARTER_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ACTIVITY_TASK_SUPERVISOR_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.COMPUTER_ENGINE_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logI -import org.frknkrc44.hma_oss.zygote.logV +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_STACK_SUPERVISOR_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_STARTER_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_TASK_SUPERVISOR_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.COMPUTER_ENGINE_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.logV class ActivityHook(private val service: HMAService) : IFrameworkHook { override val TAG = "ActivityHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 734d54ed4..f6ef10e35 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -4,18 +4,19 @@ import android.os.Build import android.os.SystemProperties import androidx.annotation.RequiresApi import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getBooleanField -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getIntField -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getObjectField -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.setBooleanField -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PROCESS_LIST_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.STORAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logE -import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getBooleanField +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getIntField +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.setBooleanField +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PROCESS_LIST_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.STORAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logE +import org.frknkrc44.hma_oss.zygote.util.logI +import java.util.Map @RequiresApi(Build.VERSION_CODES.R) class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { @@ -168,7 +169,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { ) { param -> if (!voldHookSkipped && service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - val pidPkgMap = param.getArgument(1) as java.util.Map<*, *> + val pidPkgMap = param.getArgument(1) as Map<*, *> val keysToRemove = mutableSetOf() for (entry in pidPkgMap.entrySet()) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 1485dfa3b..a591e5930 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -7,11 +7,12 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.provider.Settings -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.CONTENT_PROVIDER_TRANSPORT_CLASS -import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HookParam +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.CONTENT_PROVIDER_TRANSPORT_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD class ContentProviderHook(private val service: HMAService): IFrameworkHook { override val TAG = "ContentProviderHook" @@ -155,7 +156,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { } } - private fun getCallingPackages(param: BulkHooker.HookParam) = try { + private fun getCallingPackages(param: HookParam) = try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val attrSource = param.args.first { it is AttributionSource } as AttributionSource arrayOf(attrSource.packageName) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 736bda620..f914745ce 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -8,13 +8,14 @@ import android.view.inputmethod.InputMethodSubtype import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils import icu.nullptr.hidemyapplist.common.settings_presets.InputMethodPreset -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.IMM_IMPL_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.IMM_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logV +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HookParam +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_IMPL_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logV import java.util.Collections class ImmHook(private val service: HMAService) : IFrameworkHook { @@ -145,7 +146,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } } - private fun listHook(param: BulkHooker.HookParam) { + private fun listHook(param: HookParam) { val callingApps = Utils4Zygote.getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } @@ -166,7 +167,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } } - private fun subtypeHook(param: BulkHooker.HookParam) { + private fun subtypeHook(param: HookParam) { val callingApps = Utils4Zygote.getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } @@ -179,7 +180,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } } - private fun subtypeListHook(param: BulkHooker.HookParam) { + private fun subtypeListHook(param: HookParam) { val callingApps = Utils4Zygote.getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index 901320f4f..2958b7e55 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -5,12 +5,12 @@ import android.os.Build import androidx.annotation.RequiresApi import icu.nullptr.hidemyapplist.common.PropertyUtils import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PLATFORM_COMPAT_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logE -import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PLATFORM_COMPAT_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logE +import org.frknkrc44.hma_oss.zygote.util.logI @RequiresApi(Build.VERSION_CODES.R) class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index 9fd0cb6d8..c8163e1f3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -1,13 +1,14 @@ package org.frknkrc44.hma_oss.zygote.hook import icu.nullptr.hidemyapplist.common.Constants -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logI -import org.frknkrc44.hma_oss.zygote.logV +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { @@ -31,7 +32,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { if (callingUid == Constants.UID_SYSTEM) return@hookBefore val packageSettings = param.getArgument(1) val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(packageSettings) - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@filterAppAccessLPr caller cache: $callingUid, target: $targetApp") @@ -41,7 +42,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) service.increasePMFilterCount(caller) val last = lastFilteredApp.getAndSet(caller) if (last != caller) logI(TAG, "@filterAppAccessLPr query from $caller") @@ -57,7 +58,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { val callingUid = param.getArgument(4) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -68,7 +69,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -81,7 +82,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { val callingUid = param.getArgument(3) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -92,7 +93,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index ec98cbb05..9e7e706ed 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -5,15 +5,16 @@ import android.os.Build import androidx.annotation.RequiresApi import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logI -import org.frknkrc44.hma_oss.zygote.logV +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.R) class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { @@ -55,7 +56,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1) as String - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@getPackageSetting - PkgMgr cache: insecure query from $callingUid to $targetApp") @@ -66,7 +67,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@getPackageSetting - PkgMgr: insecure query from $caller to $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -78,7 +79,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { val callingUid = param.getArgument(1) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(3)) - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") @@ -88,7 +89,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) service.increasePMFilterCount(caller) val last = lastFilteredApp.getAndSet(caller) if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") @@ -104,7 +105,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -115,7 +116,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -128,7 +129,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -139,7 +140,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index 82a54f803..ee3490244 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -5,15 +5,16 @@ import android.os.Build import androidx.annotation.RequiresApi import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PMS_COMPUTER_TRACKER_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logI -import org.frknkrc44.hma_oss.zygote.logV +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PMS_COMPUTER_TRACKER_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.S) class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { @@ -55,7 +56,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1) as String - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@getPackageSetting - Computer cache: insecure query from $callingUid to $targetApp") @@ -66,7 +67,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@getPackageSetting - Computer: insecure query from $caller to $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -78,7 +79,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1) as String - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@getPackageSettingInternal - Computer cache: insecure query from $callingUid to $targetApp") @@ -89,7 +90,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@getPackageSettingInternal - Computer: insecure query from $caller to $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -102,7 +103,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -113,7 +114,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -126,7 +127,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1) as? String? ?: return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -137,7 +138,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -151,7 +152,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { val callingUid = param.getArgument(1) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(3)) - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") @@ -161,7 +162,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) service.increasePMFilterCount(caller) val last = lastFilteredApp.getAndSet(caller) if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index 141e962d3..471b1ec32 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -6,14 +6,15 @@ import androidx.annotation.RequiresApi import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findMethod -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_IMPL_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.TIRAMISU) class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { @@ -68,7 +69,7 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(4)) // PackageSettings <- PackageStateInternal - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") @@ -81,7 +82,7 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) service.increasePMFilterCount(caller) val last = lastFilteredApp.getAndSet(caller) if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") @@ -92,4 +93,4 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { super.load() } -} \ No newline at end of file +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 6a0d52936..6ca82eaea 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -7,15 +7,16 @@ import androidx.annotation.RequiresApi import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.findMethod -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.APPS_FILTER_IMPL_CLASS -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { @@ -72,7 +73,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { val callingUid = param.getArgument(2) as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(4)) // PackageSettings <- PackageStateInternal - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = true service.increasePMFilterCount(callingUid) logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") @@ -85,7 +86,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = true - service.putShouldHideUidCache(callingUid, caller, targetApp!!) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) service.increasePMFilterCount(caller) val last = lastFilteredApp.getAndSet(caller) if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") @@ -108,7 +109,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore val targetApp = param.getArgument(1).toString() - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@getArchivedPackageInternal caller cache: $callingUid, target: $targetApp") @@ -118,7 +119,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) val last = lastFilteredApp.getAndSet(caller) if (last != caller) logI(TAG, "@getArchivedPackageInternal: query from $caller") @@ -129,4 +130,4 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { super.load() } -} \ No newline at end of file +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 8f9a70f6b..9fe5ce99e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -9,14 +9,15 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.callMethod -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getCallingApps -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getPackageNameFromPackageSettings -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.COMPUTER_ENGINE_CLASS -import org.frknkrc44.hma_oss.zygote.logD -import org.frknkrc44.hma_oss.zygote.logV +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callMethod +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.COMPUTER_ENGINE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache import java.util.concurrent.atomic.AtomicReference abstract class PmsHookTargetBase(protected val service: HMAService) : IFrameworkHook { @@ -84,7 +85,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = Binder.getCallingUid() val packageSettings = param.getArgument(1) val targetApp = getPackageNameFromPackageSettings(packageSettings) ?: return@hookBefore - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@generatePackageInfo caller cache: $callingUid, target: $targetApp") @@ -95,7 +96,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (caller != null) { logD(TAG, "@generatePackageInfo caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -110,7 +111,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = Binder.getCallingUid() val packageSettings = param.getArgument(2) val targetApp = getPackageNameFromPackageSettings(packageSettings) ?: return@hookBefore - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@addPackageHoldingPermissions caller cache: $callingUid, target: $targetApp") @@ -121,7 +122,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (caller != null) { logD(TAG, "@addPackageHoldingPermissions caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -165,7 +166,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -176,7 +177,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } @@ -189,7 +190,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (service.shouldHideFromUid(callingUid, targetApp) == true) { + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { param.result = null service.increasePMFilterCount(callingUid) logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") @@ -200,7 +201,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (caller != null) { logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") param.result = null - service.putShouldHideUidCache(callingUid, caller, targetApp) + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index d1e1c17d9..65f254e82 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -3,10 +3,10 @@ package org.frknkrc44.hma_oss.zygote.hook import android.content.Intent import android.os.Build import android.os.Bundle -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.logI +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.util.logI class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { override val TAG = "PmsPackageEventsHook" @@ -53,4 +53,4 @@ class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { } } } -} \ No newline at end of file +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index 77af0f0b0..1c99e95a5 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -1,10 +1,10 @@ package org.frknkrc44.hma_oss.zygote.hook import icu.nullptr.hidemyapplist.common.Constants -import org.frknkrc44.hma_oss.zygote.BulkHooker -import org.frknkrc44.hma_oss.zygote.HMAService -import org.frknkrc44.hma_oss.zygote.ZygoteConstants.ZYGOTE_PROCESS_CLASS -import org.frknkrc44.hma_oss.zygote.logD +import org.frknkrc44.hma_oss.zygote.service.BulkHooker +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ZYGOTE_PROCESS_CLASS +import org.frknkrc44.hma_oss.zygote.util.logD class ZygoteHook(private val service: HMAService) : IFrameworkHook { override val TAG = "ZygoteHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt similarity index 69% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index 227210f26..0c1d84d85 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -1,15 +1,18 @@ -package org.frknkrc44.hma_oss.zygote +package org.frknkrc44.hma_oss.zygote.service import android.os.Build import com.v7878.unsafe.ArtMethodUtils import com.v7878.unsafe.Reflection import com.v7878.unsafe.invoke.EmulatedStackFrame -import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.HookTransformer import com.v7878.vmtools.Hooks -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.clearStackTraces -import org.frknkrc44.hma_oss.zygote.ZygoteEntry.TAG +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.ZygoteEntry +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logE +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.logV import java.lang.invoke.MethodHandle import java.lang.reflect.Executable import java.lang.reflect.Method @@ -19,10 +22,9 @@ class BulkHooker private constructor() { val instance: BulkHooker by lazy { BulkHooker() } } - private val hooks: MutableMap> = - HashMap>() + private val hooks: MutableMap> = HashMap() - private fun addAll(clazz: String, methodName: String, hookOnce: Boolean, paramCount: Int, impl: HookTransformer) { + private fun addHook(clazz: String, methodName: String, hookOnce: Boolean, paramCount: Int, impl: HookTransformer) { val element = HookElement( impl = impl, methodName = methodName, @@ -33,7 +35,7 @@ class BulkHooker private constructor() { if (applyHook(clazz, element)) { hooks.computeIfAbsent(clazz) { _ -> mutableListOf() }.add(element) } else { - logI(TAG, "Invalid hook removed: $clazz -> $methodName($paramCount)") + logI(ZygoteEntry.TAG, "Invalid hook removed: $clazz -> $methodName($paramCount)") } } @@ -44,26 +46,26 @@ class BulkHooker private constructor() { paramCount: Int = -1, hook: (param: HookParam) -> Unit, ) { - addAll(clazz, methodName, hookOnce, paramCount) { original, frame -> + addHook(clazz, methodName, hookOnce, paramCount) { original, frame -> val value = ReturnValue() try { hook(HookParam(clazz, original, frame, methodName, value)) } catch (it: Throwable) { - logE(TAG, it.message ?: "Unknown error on hook", it) + logE(ZygoteEntry.TAG, it.message ?: "Unknown error on hook", it) } if (!value.replace) { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logD(TAG, it.message ?: "Unknown error on original function", it) + logD(ZygoteEntry.TAG, it.message ?: "Unknown error on original function", it) value.throwable = it } } value.throwable?.let { - clearStackTraces(it) + Utils4Zygote.clearStackTraces(it) throw it } @@ -81,28 +83,28 @@ class BulkHooker private constructor() { paramCount: Int = -1, hook: (param: HookParam) -> Unit, ) { - addAll(clazz, methodName, hookOnce, paramCount) { original, frame -> + addHook(clazz, methodName, hookOnce, paramCount) { original, frame -> val value = ReturnValue() try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logD(TAG, it.message ?: "Unknown error on original function", it) + logD(ZygoteEntry.TAG, it.message ?: "Unknown error on original function", it) value.throwable = it } if (value.throwable == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - value.setResultWithoutReplace(frame.accessor().getValue(RETURN_VALUE_IDX)) + value.setResultWithoutReplace(frame.accessor().getValue(EmulatedStackFrame.RETURN_VALUE_IDX)) } try { hook(HookParam(clazz, original, frame, methodName, value)) } catch (it: Throwable) { - logE(TAG, it.message ?: "Unknown error on hook", it) + logE(ZygoteEntry.TAG, it.message ?: "Unknown error on hook", it) } value.throwable?.let { - clearStackTraces(it) + Utils4Zygote.clearStackTraces(it) throw it } @@ -120,7 +122,7 @@ class BulkHooker private constructor() { try { curClazz = Class.forName(clazz, true, loader) } catch (ex: ClassNotFoundException) { - logE(TAG, "Class $clazz not found", ex) + logE(ZygoteEntry.TAG, "Class $clazz not found", ex) return false } @@ -134,14 +136,14 @@ class BulkHooker private constructor() { for (executable in executables) { if (!element.hookFinished) { - logD(TAG, "Hooked: $executable") + logD(ZygoteEntry.TAG, "Hooked: $executable") val memoryAddresses = Hooks.hook( executable, Hooks.EntryPointType.DIRECT, element.impl, Hooks.EntryPointType.DIRECT ) - logV(TAG, "Memory address map: $memoryAddresses") + logV(ZygoteEntry.TAG, "Memory address map: $memoryAddresses") if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { element.memoryAddresses = memoryAddresses @@ -218,7 +220,7 @@ class BulkHooker private constructor() { try { curClazz = Class.forName(clazz, true, loader) } catch (ex: ClassNotFoundException) { - logE(TAG, "Class $clazz not found", ex) + logE(ZygoteEntry.TAG, "Class $clazz not found", ex) return null } @@ -245,68 +247,8 @@ class BulkHooker private constructor() { return methods.firstOrNull() } - logI(TAG, "Invalid hook detected: $clazzNames -> $methodNames($paramCount)") + logI(ZygoteEntry.TAG, "Invalid hook detected: $clazzNames -> $methodNames($paramCount)") return null } - - class ReturnValue(initialValue: Any? = null) { - var replace: Boolean = false - private set - - var result: Any? = initialValue - set(newValue) { - field = newValue - replace = true - } - - fun setResultWithoutReplace(newValue: Any?) { - result = newValue - replace = false - } - - var throwable: Throwable? = null - } - - data class HookParam( - val clazz: String, - val original: MethodHandle, - val frame: EmulatedStackFrame, - val methodName: String, - val returnValue: ReturnValue, - ) { - var result: Any? - get() = returnValue.result - set(newValue) { returnValue.result = newValue } - - /** - * Returns the first argument - */ - val thisObject by lazy { Utils4Zygote.getArgument(frame, 0) } - - fun getArgument(index: Int) = Utils4Zygote.getArgument(frame, index) - - fun setArgument(index: Int, value: Any) = Utils4Zygote.setArgument(frame, index, value) - - /** - * - `args[0] == thisObject` - * - `args[1:] == function args` - */ - val args by lazy { Utils4Zygote.dumpArgs(frame) } - - var throwable: Throwable? - get() = returnValue.throwable - set(newValue) { returnValue.throwable = newValue } - } - - data class HookElement( - val impl: HookTransformer, - val methodName: String, - val hookOnce: Boolean, - var method: Executable? = null, - var memoryAddresses: android.util.Pair? = null, - var hookFinished: Boolean = false, - val paramCount: Int = -1, - var applyCount: Int = 0, - ) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt new file mode 100644 index 000000000..d5f92a75c --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt @@ -0,0 +1,67 @@ +package org.frknkrc44.hma_oss.zygote.service + +import com.v7878.unsafe.invoke.EmulatedStackFrame +import com.v7878.vmtools.HookTransformer +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import java.lang.invoke.MethodHandle +import java.lang.reflect.Executable + +class ReturnValue(initialValue: Any? = null) { + var replace: Boolean = false + private set + + var result: Any? = initialValue + set(newValue) { + field = newValue + replace = true + } + + fun setResultWithoutReplace(newValue: Any?) { + result = newValue + replace = false + } + + var throwable: Throwable? = null +} + +data class HookParam( + val clazz: String, + val original: MethodHandle, + val frame: EmulatedStackFrame, + val methodName: String, + val returnValue: ReturnValue, +) { + var result: Any? + get() = returnValue.result + set(newValue) { returnValue.result = newValue } + + /** + * Returns the first argument + */ + val thisObject by lazy { Utils4Zygote.getArgument(frame, 0) } + + fun getArgument(index: Int) = Utils4Zygote.getArgument(frame, index) + + fun setArgument(index: Int, value: Any) = Utils4Zygote.setArgument(frame, index, value) + + /** + * - `args[0] == thisObject` + * - `args[1:] == function args` + */ + val args by lazy { Utils4Zygote.dumpArgs(frame) } + + var throwable: Throwable? + get() = returnValue.throwable + set(newValue) { returnValue.throwable = newValue } +} + +data class HookElement( + val impl: HookTransformer, + val methodName: String, + val hookOnce: Boolean, + var method: Executable? = null, + var memoryAddresses: android.util.Pair? = null, + var hookFinished: Boolean = false, + val paramCount: Int = -1, + var applyCount: Int = 0, +) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt similarity index 95% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 6678e8819..c8cc8a741 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -1,4 +1,4 @@ -package org.frknkrc44.hma_oss.zygote +package org.frknkrc44.hma_oss.zygote.service import android.content.Intent import android.content.pm.ApplicationInfo @@ -25,7 +25,7 @@ import icu.nullptr.hidemyapplist.common.Utils.removeIf import icu.nullptr.hidemyapplist.common.app_presets.DetectorAppsPreset import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature import org.frknkrc44.hma_oss.zygote.hook.AccessibilityHook import org.frknkrc44.hma_oss.zygote.hook.ActivityHook import org.frknkrc44.hma_oss.zygote.hook.AppDataIsolationHook @@ -40,12 +40,18 @@ import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget33 import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget34 import org.frknkrc44.hma_oss.zygote.hook.PmsPackageEventsHook import org.frknkrc44.hma_oss.zygote.hook.ZygoteHook +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logE +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.logW +import org.frknkrc44.hma_oss.zygote.util.logWithLevel import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.UserManagerApis import java.io.File import java.lang.reflect.Modifier import java.util.concurrent.ExecutorService import java.util.concurrent.Executors +import kotlin.collections.get class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { @@ -69,7 +75,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { val systemApps = mutableSetOf() private val frameworkHooks = mutableSetOf() val executor: ExecutorService = Executors.newSingleThreadExecutor() - private val uidHideCache = mutableListOf>>() internal var appUid = 0 var config = JsonConfig().apply { detailLog = true } @@ -247,8 +252,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { fun increaseFilterCount(uid: Int?, amount: Int = 1, filterType: FilterHolder.FilterType) { if (uid == null || amount < 1) return - val caller = uidHideCache.firstOrNull { it.first == uid }?.second - if (caller == null) return + val caller = HMAServiceCache.instance.findCallerByUid(uid) ?: return return increaseFilterCount(caller, amount, filterType) } @@ -316,21 +320,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { fun isAppInGMSIgnoredPackages(caller: String, query: String) = (caller in Constants.gmsPackages) && appHasGMSConnection(query) - fun shouldHideFromUid(uid: Int, query: String?): Boolean? { - if (query == null) return null - - return uidHideCache.any { it.first == uid && it.third.contains(query) } - } - - fun putShouldHideUidCache(uid: Int, caller: String, query: String) { - val findList = uidHideCache.firstOrNull { it.first == uid } - if (findList != null) { - findList.third.add(query) - } else { - uidHideCache.add(Triple(uid, caller, mutableListOf(query))) - } - } - fun shouldHide(caller: String?, query: String?): Boolean { if (caller == null || query == null) return false if (caller == BuildConfig.APP_PACKAGE_NAME) return false @@ -396,10 +385,17 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { try { val uid = getPackageUidCompat(pms, query, 0L, callingHandle.hashCode()) - logD(TAG, "@shouldHideInstallationSource UID for $caller, ${callingHandle.hashCode()}: $query, $uid") + logD( + TAG, + "@shouldHideInstallationSource UID for $caller, ${callingHandle.hashCode()}: $query, $uid" + ) if (uid < 0) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED // invalid package installation source request } catch (e: Throwable) { - logD(TAG, "@shouldHideInstallationSource UID error for $caller, ${callingHandle.hashCode()}", e) + logD( + TAG, + "@shouldHideInstallationSource UID error for $caller, ${callingHandle.hashCode()}", + e + ) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED } @@ -441,7 +437,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { config = newConfig configFile.writeText(json) frameworkHooks.forEach(IFrameworkHook::onConfigChanged) - uidHideCache.clear() + HMAServiceCache.instance.clearUidCache() // remove filter counts for apps if they are not in config filterHolder.filterCounts.removeIf { key, _ -> !config.scope.containsKey(key) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt new file mode 100644 index 000000000..cc3b5dd96 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt @@ -0,0 +1,28 @@ +package org.frknkrc44.hma_oss.zygote.service + +class HMAServiceCache private constructor() { + companion object { + val instance by lazy { HMAServiceCache() } + } + + private val uidHideCache = mutableListOf>>() + + fun findCallerByUid(uid: Int) = uidHideCache.firstOrNull { it.first == uid }?.second + + fun shouldHideFromUid(uid: Int, query: String?): Boolean? { + if (query == null) return null + + return uidHideCache.any { it.first == uid && it.third.contains(query) } + } + + fun putShouldHideUidCache(uid: Int, caller: String, query: String) { + val findList = uidHideCache.firstOrNull { it.first == uid } + if (findList != null) { + findList.third.add(query) + } else { + uidHideCache.add(Triple(uid, caller, mutableListOf(query))) + } + } + + fun clearUidCache() = uidHideCache.clear() +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt similarity index 89% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 0f9081733..3d1092542 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -1,4 +1,4 @@ -package org.frknkrc44.hma_oss.zygote +package org.frknkrc44.hma_oss.zygote.service import android.annotation.SuppressLint import android.content.pm.IPackageManager @@ -7,6 +7,11 @@ import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.Hooks +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logE +import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.logV import kotlin.concurrent.thread @SuppressLint("PrivateApi") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt similarity index 86% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index 2b3f55118..aedafb12e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -1,4 +1,4 @@ -package org.frknkrc44.hma_oss.zygote +package org.frknkrc44.hma_oss.zygote.service import android.content.AttributionSource import android.content.pm.IPackageManager @@ -7,8 +7,12 @@ import android.os.Bundle import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.getStaticIntField -import org.frknkrc44.hma_oss.zygote.Utils4Zygote.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.logE +import org.frknkrc44.hma_oss.zygote.util.logI import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.adapter.UidObserverAdapter @@ -73,7 +77,11 @@ object UserService { } logD(TAG, "Client uid: $appUid") } catch (e: Throwable) { - logE(TAG, "Fatal: Cannot get package details\nCompile this app from source with your changes", e) + logE( + TAG, + "Fatal: Cannot get package details\nCompile this app from source with your changes", + e + ) } Utils4Zygote.waitForService("activity") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt similarity index 95% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Logcat.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index 1ace7e7d2..b30252390 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -1,7 +1,8 @@ -package org.frknkrc44.hma_oss.zygote +package org.frknkrc44.hma_oss.zygote.util import android.util.Log import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.service.HMAService import java.text.SimpleDateFormat import java.util.Date import java.util.Locale diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt similarity index 97% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index 00d7eb0f0..dfaa12572 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -1,4 +1,4 @@ -package org.frknkrc44.hma_oss.zygote +package org.frknkrc44.hma_oss.zygote.util import android.app.ActivityThread import android.os.Binder @@ -13,6 +13,9 @@ import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.Magic +import org.frknkrc44.hma_oss.zygote.service.SystemServerHook import java.io.File import java.lang.reflect.Constructor import java.lang.reflect.Field diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZygoteConstants.kt similarity index 97% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZygoteConstants.kt index 9e7f9948b..255216171 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteConstants.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZygoteConstants.kt @@ -1,4 +1,4 @@ -package org.frknkrc44.hma_oss.zygote +package org.frknkrc44.hma_oss.zygote.util object ZygoteConstants { const val COMPUTER_ENGINE_CLASS = "com.android.server.pm.ComputerEngine" From 8f51b65bb12c4e7c4f37d3450323610de374797e Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 11 Mar 2026 20:22:24 +0300 Subject: [PATCH 048/162] Convert work mode to dialog, add accessibility apps preset --- .../ui/fragment/AppSettingsV2Fragment.kt | 49 ++++++++++++++----- app/src/main/res/values/strings.xml | 1 + .../xml/app_settings_template_config_v2.xml | 8 +-- .../hidemyapplist/common/AppPresets.kt | 4 +- .../app_presets/AccessibilityAppsPreset.kt | 22 +++++++++ 5 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/AccessibilityAppsPreset.kt diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt index f0abee2f6..3c5efa0f0 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt @@ -13,6 +13,7 @@ import androidx.fragment.app.setFragmentResult import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.navigation.fragment.navArgs +import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceFragmentCompat @@ -132,7 +133,6 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { override fun getBoolean(key: String, defValue: Boolean): Boolean { return when (key) { "enableHide" -> pack.enabled - "useWhiteList" -> pack.config.useWhitelist "excludeSystemApps" -> pack.config.excludeSystemApps "hideInstallationSource" -> pack.config.hideInstallationSource "hideSystemInstallationSource" -> pack.config.hideSystemInstallationSource @@ -146,7 +146,6 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { override fun putBoolean(key: String, value: Boolean) { when (key) { "enableHide" -> pack.enabled = value - "useWhiteList" -> pack.config.useWhitelist = value "excludeSystemApps" -> pack.config.excludeSystemApps = value "hideInstallationSource" -> pack.config.hideInstallationSource = value "hideSystemInstallationSource" -> pack.config.hideSystemInstallationSource = value @@ -156,6 +155,20 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { else -> throw IllegalArgumentException("Invalid key: $key") } } + + override fun getString(key: String, defValue: String?): String { + return when (key) { + "useWhiteList" -> if (pack.config.useWhitelist) "1" else "0" + else -> throw IllegalArgumentException("Invalid key: $key") + } + } + + override fun putString(key: String, value: String?) { + when (key) { + "useWhiteList" -> pack.config.useWhitelist = value == "1" + else -> throw IllegalArgumentException("Invalid key: $key") + } + } } class AppPreferenceFragment : PreferenceFragmentCompat() { @@ -353,16 +366,30 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { preferenceManager.preferenceDataStore = preferenceDataStore setPreferencesFromResource(R.xml.app_settings_template_config_v2, rootKey) - findPreference("useWhiteList")?.setOnPreferenceChangeListener { _, newValue -> - val useWhitelist = newValue as Boolean + findPreference("useWhiteList")?.apply { + val excludeSystemApps = findPreference("excludeSystemApps") - pack.config.applyTemplates.clear() - pack.config.extraAppList.clear() - pack.config.extraOppositeAppList.clear() - updateApplyTemplates() - updateExtraAppList(useWhitelist) - updateExtraOppositeAppList(useWhitelist) - true + entries = arrayOf( + getString(R.string.blacklist), + getString(R.string.whitelist), + ) + entryValues = arrayOf("0", "1") + + excludeSystemApps?.isEnabled = value == "1" + + setOnPreferenceChangeListener { _, newValue -> + val useWhitelist = newValue == "1" + + pack.config.applyTemplates.clear() + pack.config.extraAppList.clear() + pack.config.extraOppositeAppList.clear() + updateApplyTemplates() + updateExtraAppList(useWhitelist) + updateExtraOppositeAppList(useWhitelist) + + excludeSystemApps?.isEnabled = useWhitelist + true + } } findPreference("applyTemplates")?.setOnPreferenceClickListener { val templates = ConfigManager.getTemplateList().mapNotNull { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 999f9ac04..c7a186432 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -130,6 +130,7 @@ Suspicious apps Detector/Checker apps Shizuku/Dhizuku apps + Accessibility apps Accessibility diff --git a/app/src/main/res/xml/app_settings_template_config_v2.xml b/app/src/main/res/xml/app_settings_template_config_v2.xml index 4c0719eac..239d4d95c 100644 --- a/app/src/main/res/xml/app_settings_template_config_v2.xml +++ b/app/src/main/res/xml/app_settings_template_config_v2.xml @@ -4,16 +4,12 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> - () + + override fun canBeAddedIntoPreset(appInfo: ApplicationInfo): Boolean { + return checkSplitPackages(appInfo) { key, zipFile -> + val manifestStr = appPresets.readManifest(key, zipFile) + + return@checkSplitPackages manifestStr.contains(PERM_ACCESSIBILITY) + } + } +} \ No newline at end of file From a23190b21322ebd39726299c3cf6b1c9d6067296 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 11 Mar 2026 20:26:33 +0300 Subject: [PATCH 049/162] Fix some warnings and make AS happy --- .../hma_oss/ui/fragment/AppSettingsV2Fragment.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt index 3c5efa0f0..e044e8d80 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt @@ -48,7 +48,7 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { } private val binding by viewBinding(FragmentSettingsBinding::bind) - private val viewModel by viewModels() { + private val viewModel by viewModels { val args by navArgs() val cfg: JsonConfig.AppConfig? = if (args.bulkConfigMode) { if (args.bulkConfig != null) JsonConfig.AppConfig.parse(args.bulkConfig!!) @@ -308,17 +308,17 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { preferenceManager.preferenceDataStore = preferenceDataStore setPreferencesFromResource(R.xml.app_settings_spoofing_v2, rootKey) - findPreference("hideInstallationSource")?.setOnPreferenceChangeListener { _, newValue -> + findPreference("hideInstallationSource")?.setOnPreferenceChangeListener { _, _ -> Toast.makeText(requireContext(), R.string.app_force_stop_warning, Toast.LENGTH_LONG).show() true } - findPreference("hideSystemInstallationSource")?.setOnPreferenceChangeListener { _, newValue -> + findPreference("hideSystemInstallationSource")?.setOnPreferenceChangeListener { _, _ -> Toast.makeText(requireContext(), R.string.app_force_stop_warning, Toast.LENGTH_LONG).show() true } - findPreference("excludeTargetInstallationSource")?.setOnPreferenceChangeListener { _, newValue -> + findPreference("excludeTargetInstallationSource")?.setOnPreferenceChangeListener { _, _ -> Toast.makeText(requireContext(), R.string.app_force_stop_warning, Toast.LENGTH_LONG).show() true @@ -335,7 +335,7 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { getString(R.string.app_template_using, pack.config.applyTemplates.size) } - private fun updateApplyPresets(useWhitelist: Boolean = pack.config.useWhitelist) { + private fun updateApplyPresets() { findPreference("applyPresets")?.title = getString(R.string.app_preset_using, pack.config.applyPresets.size) } @@ -362,6 +362,7 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { else getString(R.string.app_extra_apps_invisible_count, pack.config.extraOppositeAppList.size) } + @SuppressLint("DiscouragedApi") override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { preferenceManager.preferenceDataStore = preferenceDataStore setPreferencesFromResource(R.xml.app_settings_template_config_v2, rootKey) From 7e31b3b27b13d5557eff269e14f9b42c5b50bfd7 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 11 Mar 2026 20:32:56 +0300 Subject: [PATCH 050/162] Skip scanning the framework package (WIP) --- .../main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt index 6691a0e55..a607afe6b 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt @@ -61,6 +61,10 @@ class AppPresets private constructor() { presetList.forEach { it.clearPackageList() } for (appInfo in appsList) { + when (appInfo.packageName) { + "android" -> continue + } + runCatching { tryToAddIntoGMSConnectionList(appInfo, appInfo.packageName) { loggerFunction?.invoke(Log.DEBUG, it) From 9a05d631b7bc71c83c01e3437bb644965f7a72e0 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 11 Mar 2026 20:40:11 +0300 Subject: [PATCH 051/162] Skip detector apps for accessibility apps, add more detector apps into presets --- .../common/app_presets/AccessibilityAppsPreset.kt | 5 +++++ .../hidemyapplist/common/app_presets/DetectorAppsPreset.kt | 2 ++ 2 files changed, 7 insertions(+) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/AccessibilityAppsPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/AccessibilityAppsPreset.kt index b6324268f..79c697a04 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/AccessibilityAppsPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/AccessibilityAppsPreset.kt @@ -13,6 +13,11 @@ class AccessibilityAppsPreset(private val appPresets: AppPresets) : BasePreset(N override val exactPackageNames = setOf() override fun canBeAddedIntoPreset(appInfo: ApplicationInfo): Boolean { + // skip detector apps + if (appPresets.getPresetByName(DetectorAppsPreset.NAME)?.containsPackage(appInfo.packageName) ?: false) { + return false + } + return checkSplitPackages(appInfo) { key, zipFile -> val manifestStr = appPresets.readManifest(key, zipFile) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt index 0ed976f31..ff233308e 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt @@ -35,6 +35,8 @@ class DetectorAppsPreset : BasePreset(NAME) { "com.joeykrim.rootcheck", "com.studio.duckdetector", "com.chuqniudetector", + "com.chunqiudetector", + "com.longz.detector", // Add more detector apps (thanks @Yurii0307) "com.lingqing.detector", From 79803d1b86b87a13edab204d627db8cbf2db086f Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 15 Mar 2026 18:54:23 +0300 Subject: [PATCH 052/162] Fix filter log sort --- .../java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt index 41ad999b8..628f7e57c 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt @@ -38,7 +38,7 @@ class StatsFragment : Fragment(R.layout.fragment_logs) { fun getTotalCount(key: String) = stats.filterCounts[key]!!.totalCount val countsKeys = stats.filterCounts.keys.sortedWith { key1, key2 -> - if (getTotalCount(key1) > getTotalCount(key2)) -1 else 0 + if (getTotalCount(key1) > getTotalCount(key2)) -1 else 1 } for (key in countsKeys) { From f1a52c92125ba3352f4e6babac597e6b3f0dcb92 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 15 Mar 2026 19:13:31 +0300 Subject: [PATCH 053/162] Add ability to upload debug APK and ZIP for PRs --- .github/workflows/pull_request.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index df6458b64..b9e0c5010 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -59,7 +59,7 @@ jobs: - name: Build debug id: buildDebug run: | - ./gradlew assembleDebug + ./gradlew :app:assembleDebug :zygote:assembleDebug echo "debugName=$(ls app/build/outputs/apk/debug/*.apk | awk -F '(/|.apk)' '{print $6}')" >> $GITHUB_OUTPUT - name: Upload debug @@ -67,4 +67,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: ${{ steps.buildDebug.outputs.debugName }} - path: "app/build/outputs/apk/debug/*.apk" + path: | + app/build/outputs/apk/debug/*.apk + zygote/build/outputs/magisk/debug/*.zip From 3ecaf7070cc79af446ceb63b7f4e43dcb80a3124 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 17 Mar 2026 20:54:07 +0300 Subject: [PATCH 054/162] Check for logd runs and do not print to logd when it is not working --- .../hma_oss/zygote/hook/AccessibilityHook.kt | 4 +- .../hma_oss/zygote/hook/ActivityHook.kt | 6 +- .../zygote/hook/AppDataIsolationHook.kt | 6 +- .../zygote/hook/ContentProviderHook.kt | 2 +- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 4 +- .../hma_oss/zygote/hook/PlatformCompatHook.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget33.kt | 4 +- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 4 +- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 4 +- .../zygote/hook/PmsPackageEventsHook.kt | 2 +- .../hma_oss/zygote/hook/ZygoteHook.kt | 2 +- .../hma_oss/zygote/service/BulkHooker.kt | 8 +- .../hma_oss/zygote/service/HMAService.kt | 10 +-- .../zygote/service/SystemServerHook.kt | 8 +- .../hma_oss/zygote/service/UserService.kt | 6 +- .../frknkrc44/hma_oss/zygote/util/Logcat.kt | 74 +++++++++++-------- 19 files changed, 92 insertions(+), 76 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index ea0714699..cc645c80e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -8,8 +8,8 @@ import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE class AccessibilityHook(private val service: HMAService) : IFrameworkHook { override val TAG = "AccessibilityHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index f5ac75699..55180be89 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -16,9 +16,9 @@ import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_STARTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_TASK_SUPERVISOR_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.COMPUTER_ENGINE_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logI -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV class ActivityHook(private val service: HMAService) : IFrameworkHook { override val TAG = "ActivityHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index f6ef10e35..59b2cb1e1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -13,9 +13,9 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.setBooleanField import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PROCESS_LIST_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.STORAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logE -import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import java.util.Map @RequiresApi(Build.VERSION_CODES.R) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index a591e5930..880d27198 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -12,7 +12,7 @@ import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.CONTENT_PROVIDER_TRANSPORT_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD class ContentProviderHook(private val service: HMAService): IFrameworkHook { override val TAG = "ContentProviderHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index f914745ce..06509cdcc 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -14,8 +14,8 @@ import org.frknkrc44.hma_oss.zygote.service.HookParam import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import java.util.Collections class ImmHook(private val service: HMAService) : IFrameworkHook { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index 2958b7e55..85e4be422 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -8,9 +8,9 @@ import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PLATFORM_COMPAT_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logE -import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI @RequiresApi(Build.VERSION_CODES.R) class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index c8163e1f3..bbc3f6317 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -5,9 +5,9 @@ import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logI -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 9e7e706ed..b0d03aa30 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -11,9 +11,9 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logI -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.R) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index ee3490244..7d72cdf7e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -11,9 +11,9 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PMS_COMPUTER_TRACKER_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logI -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.S) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index 471b1ec32..9e67e91da 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -12,8 +12,8 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.TIRAMISU) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 6ca82eaea..eda2eb97a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -14,8 +14,8 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 9fe5ce99e..cc2b22e07 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -15,8 +15,8 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callMethod import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.COMPUTER_ENGINE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache import java.util.concurrent.atomic.AtomicReference diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index 65f254e82..8fe13a5ad 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -6,7 +6,7 @@ import android.os.Bundle import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { override val TAG = "PmsPackageEventsHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index 1c99e95a5..d0ac036b3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -4,7 +4,7 @@ import icu.nullptr.hidemyapplist.common.Constants import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ZYGOTE_PROCESS_CLASS -import org.frknkrc44.hma_oss.zygote.util.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD class ZygoteHook(private val service: HMAService) : IFrameworkHook { override val TAG = "ZygoteHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index 0c1d84d85..a03582109 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -9,10 +9,10 @@ import com.v7878.vmtools.HookTransformer import com.v7878.vmtools.Hooks import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.ZygoteEntry -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logE -import org.frknkrc44.hma_oss.zygote.util.logI -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import java.lang.invoke.MethodHandle import java.lang.reflect.Executable import java.lang.reflect.Method diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index c8cc8a741..ee084bc2f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -40,11 +40,11 @@ import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget33 import org.frknkrc44.hma_oss.zygote.hook.PmsHookTarget34 import org.frknkrc44.hma_oss.zygote.hook.PmsPackageEventsHook import org.frknkrc44.hma_oss.zygote.hook.ZygoteHook -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logE -import org.frknkrc44.hma_oss.zygote.util.logI -import org.frknkrc44.hma_oss.zygote.util.logW -import org.frknkrc44.hma_oss.zygote.util.logWithLevel +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logW +import org.frknkrc44.hma_oss.zygote.util.Logcat.logWithLevel import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.UserManagerApis import java.io.File diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 3d1092542..5964246c0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -8,10 +8,10 @@ import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.Hooks import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logE -import org.frknkrc44.hma_oss.zygote.util.logI -import org.frknkrc44.hma_oss.zygote.util.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import kotlin.concurrent.thread @SuppressLint("PrivateApi") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index aedafb12e..83a0b700e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -10,9 +10,9 @@ import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature -import org.frknkrc44.hma_oss.zygote.util.logD -import org.frknkrc44.hma_oss.zygote.util.logE -import org.frknkrc44.hma_oss.zygote.util.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.adapter.UidObserverAdapter diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index b30252390..12685ee18 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -1,5 +1,6 @@ package org.frknkrc44.hma_oss.zygote.util +import android.os.SystemProperties import android.util.Log import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.service.HMAService @@ -7,37 +8,52 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -private fun parseLog(level: Int, tag: String, msg: String, cause: Throwable? = null) = buildString { - val levelStr = when (level) { - Log.VERBOSE -> "VERBS" - Log.DEBUG -> "DEBUG" - Log.INFO -> " INFO" - Log.WARN -> " WARN" - Log.ERROR -> "ERROR" - else -> "?WTF?" +@Suppress("SpellCheckingInspection") +object Logcat { + private var logdReady: Boolean? = null + + private fun parseLog(level: Int, tag: String, msg: String, cause: Throwable? = null) = buildString { + val levelStr = when (level) { + Log.VERBOSE -> "VERBS" + Log.DEBUG -> "DEBUG" + Log.INFO -> " INFO" + Log.WARN -> " WARN" + Log.ERROR -> "ERROR" + else -> "?WTF?" + } + val date = SimpleDateFormat("MM-dd HH:mm:ss", Locale.getDefault()).format(Date()) + append("[$levelStr] $date ($tag) $msg") + if (!endsWith('\n')) append('\n') + if (cause != null) append(Log.getStackTraceString(cause)) + if (!endsWith('\n')) append('\n') } - val date = SimpleDateFormat("MM-dd HH:mm:ss", Locale.getDefault()).format(Date()) - append("[$levelStr] $date ($tag) $msg") - if (!endsWith('\n')) append('\n') - if (cause != null) append(Log.getStackTraceString(cause)) - if (!endsWith('\n')) append('\n') -} -fun logWithLevel(level: Int, tag: String, msg: String, cause: Throwable? = null) { - if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return - if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return - if (level == Log.VERBOSE && !BuildConfig.DEBUG) return + fun logWithLevel(level: Int, tag: String, msg: String, cause: Throwable? = null) { + if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return + if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return + if (level == Log.VERBOSE && !BuildConfig.DEBUG) return - val parsedLog = parseLog(level, tag, msg, cause) + val parsedLog = parseLog(level, tag, msg, cause) - HMAService.instance?.executor?.execute { - HMAService.instance?.addLog(parsedLog) - Log.println(Log.INFO, "HMA-OSS", parsedLog) - } ?: Log.println(Log.INFO, "HMA-OSS", parsedLog) -} + HMAService.instance?.executor?.execute { + HMAService.instance?.addLog(parsedLog) + println(parsedLog) + } ?: println(parsedLog) + } + + private fun println(msg: String) { + if (logdReady == null) { + logdReady = SystemProperties.get("init.svc.logd") == "running" + } -fun logV(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.VERBOSE, tag, msg, cause) -fun logD(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.DEBUG, tag, msg, cause) -fun logI(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.INFO, tag, msg, cause) -fun logW(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.WARN, tag, msg, cause) -fun logE(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.ERROR, tag, msg, cause) + if (logdReady != true) return + + Log.i("HMA-OSS", msg) + } + + fun logV(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.VERBOSE, tag, msg, cause) + fun logD(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.DEBUG, tag, msg, cause) + fun logI(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.INFO, tag, msg, cause) + fun logW(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.WARN, tag, msg, cause) + fun logE(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.ERROR, tag, msg, cause) +} From 64d39fd70971ad81f36c925db1a9551e56d6a2cf Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 17 Mar 2026 21:02:48 +0300 Subject: [PATCH 055/162] Shorten logWithLevel --- .../org/frknkrc44/hma_oss/zygote/util/Logcat.kt | 14 ++++++++------ .../frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index 12685ee18..9086004e3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -33,12 +33,14 @@ object Logcat { if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return if (level == Log.VERBOSE && !BuildConfig.DEBUG) return - val parsedLog = parseLog(level, tag, msg, cause) - - HMAService.instance?.executor?.execute { - HMAService.instance?.addLog(parsedLog) - println(parsedLog) - } ?: println(parsedLog) + val parsedMsg = parseLog(level, tag, msg, cause) + + HMAService.instance?.apply { + executor.execute { + addLog(parsedMsg) + println(parsedMsg) + } + } ?: println(parsedMsg) } private fun println(msg: String) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index dfaa12572..beea91022 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -16,6 +16,7 @@ import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.Magic import org.frknkrc44.hma_oss.zygote.service.SystemServerHook +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import java.io.File import java.lang.reflect.Constructor import java.lang.reflect.Field From 5c6b90f199fd112cd4e880715a239cf6e9d13570 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 17 Mar 2026 21:23:38 +0300 Subject: [PATCH 056/162] Export log* functions as JvmStatic --- .../java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java | 4 ++-- .../java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java index 6567895c8..ef8a876cb 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java @@ -1,7 +1,7 @@ package org.frknkrc44.hma_oss.zygote; -import static org.frknkrc44.hma_oss.zygote.util.LogcatKt.logE; -import static org.frknkrc44.hma_oss.zygote.util.LogcatKt.logI; +import static org.frknkrc44.hma_oss.zygote.util.Logcat.logE; +import static org.frknkrc44.hma_oss.zygote.util.Logcat.logI; import com.v7878.r8.annotations.DoNotObfuscate; import com.v7878.r8.annotations.DoNotObfuscateType; diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index 9086004e3..c1bde066e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -53,9 +53,18 @@ object Logcat { Log.i("HMA-OSS", msg) } + @JvmStatic fun logV(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.VERBOSE, tag, msg, cause) + + @JvmStatic fun logD(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.DEBUG, tag, msg, cause) + + @JvmStatic fun logI(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.INFO, tag, msg, cause) + + @JvmStatic fun logW(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.WARN, tag, msg, cause) + + @JvmStatic fun logE(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.ERROR, tag, msg, cause) } From e5bc7a75467978e6252a73267311761967275e0c Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 19 Mar 2026 19:24:59 +0300 Subject: [PATCH 057/162] Implement hook disabler to prevent conflicts --- .../hidemyapplist/service/ConfigManager.kt | 9 +++++ .../hidemyapplist/service/ServiceClient.kt | 2 ++ .../ui/fragment/SettingsFragment.kt | 33 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/settings.xml | 6 ++++ .../hidemyapplist/common/IHMAService.aidl | 2 ++ .../hidemyapplist/common/JsonConfig.kt | 16 ++++++++- gradle/libs.versions.toml | 2 +- .../hma_oss/zygote/service/BulkHooker.kt | 13 +++++++- .../hma_oss/zygote/service/HMAService.kt | 18 ++++++++++ 10 files changed, 100 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index a16323c5f..6418f8fc8 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -141,6 +141,15 @@ object ConfigManager { PackageHelper.invalidateCache() } + var disabledHooks: List + get() = config.disabledHooks + set(elements) { + config.disabledHooks.clear() + config.disabledHooks.addAll(elements) + saveConfig() + showToast(R.string.settings_need_reboot) + } + fun importConfig(json: String) { config = JsonConfig.parse(json) config.configVersion = BuildConfig.CONFIG_VERSION diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt index 9767eba7b..502021a0c 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt @@ -107,4 +107,6 @@ object ServiceClient : IHMAService, IBinder.DeathRecipient { override fun getServiceVersionName() = try { service?.serviceVersionName } catch (_: Throwable) { null } + + override fun getLoadedHooks() = service?.loadedHooks } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt index 8651c455c..240a4c327 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt @@ -11,6 +11,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.preference.ListPreference +import androidx.preference.MultiSelectListPreference import androidx.preference.Preference import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceFragmentCompat @@ -20,6 +21,7 @@ import com.google.android.material.color.DynamicColors import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.PropertyUtils import icu.nullptr.hidemyapplist.hmaApp import icu.nullptr.hidemyapplist.service.ConfigManager @@ -120,6 +122,13 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen } } + override fun getStringSet(key: String?, defValues: Set?): Set { + return when (key) { + "disableHooks" -> ConfigManager.disabledHooks.map { it.toString() }.toSet() + else -> throw IllegalArgumentException("Invalid key: $key") + } + } + override fun putBoolean(key: String, value: Boolean) { when (key) { "followSystemAccent" -> PrefManager.followSystemAccent = value @@ -156,6 +165,13 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen else -> throw IllegalArgumentException("Invalid key: $key") } } + + override fun putStringSet(key: String, values: Set?) { + when (key) { + "disableHooks" -> ConfigManager.disabledHooks = values?.map { JsonConfig.HookItem.parse(it) } ?: listOf() + else -> throw IllegalArgumentException("Invalid key: $key") + } + } } class DataIsolationPreferenceFragment(private val preferenceDataStore: PreferenceDataStore) : PreferenceFragmentCompat() { @@ -391,6 +407,23 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen configureDataIsolation() + findPreference("disableHooks")?.apply { + val allHooks = (ConfigManager.disabledHooks + (ServiceClient.loadedHooks?.map { JsonConfig.HookItem.parse(it) } ?: listOf())).let { + it.sortedWith { item1, item2 -> + fun JsonConfig.HookItem.comparator() = "${className.substringAfterLast('.')}##$methodName" + + item1.comparator().compareTo(item2.comparator()) + } + } + + entries = allHooks.map { + val displayedArgCount = if (it.argumentCount >= 0) { "${it.argumentCount} args" } else { "..." } + + "${it.className.substringAfterLast('.')} -> ${it.methodName}($displayedArgCount)" + }.toTypedArray() + entryValues = allHooks.map { it.toString() }.toTypedArray() + } + findPreference("stopSystemService")?.setOnPreferenceClickListener { if (ServiceClient.serviceVersion != 0) { MaterialAlertDialogBuilder(requireContext()) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c7a186432..c4c7e9769 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -190,6 +190,8 @@ Don\'t enable this option if you see the package list in this app correctly. Launcher icon Error-only log + Disable functions + You can disable some of the functions when they conflict with other modules Language Participate in translation diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index 4492a91e7..78ed57610 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -81,6 +81,12 @@ app:singleLineTitle="false" android:title="@string/settings_disable_activity_launch_protection" android:summary="@string/settings_disable_activity_launch_protection_summary" /> + = mutableMapOf(), val settingsTemplates: MutableMap = mutableMapOf(), + val disabledHooks: MutableList = mutableListOf(), val scope: MutableMap = mutableMapOf() ) { @Serializable @@ -60,10 +61,23 @@ data class JsonConfig( } } + @Serializable + data class HookItem( + val className: String, + val methodName: String, + val argumentCount: Int, + ) { + override fun toString() = encoder.encodeToString(this) + + companion object { + fun parse(json: String) = encoder.decodeFromString(json) + } + } + companion object { fun parse(json: String) = encoder.decodeFromString(json) - private val encoder = Json { + val encoder = Json { encodeDefaults = true ignoreUnknownKeys = true } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6dcabd98f..2631a954d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] #noinspection GradleDependency,AndroidGradlePluginVersion agp = "8.13.2" -kotlin = "2.3.10" +kotlin = "2.3.20" material = "1.13.0" hidden-api = "4.4.0" androidx-navigation = "2.9.7" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index a03582109..37be4c9b5 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -22,9 +22,20 @@ class BulkHooker private constructor() { val instance: BulkHooker by lazy { BulkHooker() } } - private val hooks: MutableMap> = HashMap() + internal val hooks: MutableMap> = HashMap() private fun addHook(clazz: String, methodName: String, hookOnce: Boolean, paramCount: Int, impl: HookTransformer) { + val inDisabledHooks = HMAService.instance?.config?.disabledHooks?.any { + clazz == it.className && + methodName == it.methodName && + paramCount == it.argumentCount + } + + if (inDisabledHooks == true) { + logI(ZygoteEntry.TAG, "Disabled hook: $clazz -> $methodName($paramCount)") + return + } + val element = HookElement( impl = impl, methodName = methodName, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index ee084bc2f..55b4ea08b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -599,4 +599,22 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun getServiceVersionName() = BuildConfig.APP_VERSION_NAME + + override fun getLoadedHooks(): Array { + val hookList = mutableListOf() + + for ((className, hookElements) in BulkHooker.instance.hooks) { + for (element in hookElements) { + hookList.add( + JsonConfig.HookItem( + className, + element.methodName, + element.paramCount, + ).toString() + ) + } + } + + return hookList.toTypedArray() + } } From 8c1d011720e3b3dd9ccd2c17971319e407691992 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Mar 2026 13:56:48 +0300 Subject: [PATCH 058/162] Use newValue for getLocale --- .../icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt | 2 +- .../main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt index 240a4c327..cfcdda609 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt @@ -272,7 +272,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen it.summary = if (!TextUtils.isEmpty(locale.script)) locale.getDisplayScript(userLocale) else locale.getDisplayName(userLocale) } it.setOnPreferenceChangeListener { _, newValue -> - val locale = getLocale() + val locale = getLocale(newValue as String) val config = resources.configuration config.setLocale(locale) hmaApp.resources.updateConfiguration(config, resources.displayMetrics) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt b/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt index 4fe3317eb..088ad4436 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt @@ -8,8 +8,7 @@ class ConfigUtils private constructor() { companion object { fun getSystemLocale(): Locale = Resources.getSystem().configuration.getLocales().get(0) - fun getLocale(): Locale { - val tag = PrefManager.locale + fun getLocale(tag: String = PrefManager.locale): Locale { return if (tag == "SYSTEM") getSystemLocale() else Locale.forLanguageTag(tag) } From 5641003cec57f575b540cb73187b6cd8b4b1b852 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Mar 2026 17:59:14 +0300 Subject: [PATCH 059/162] Update androidvmtools version --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2631a954d..279f697c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.0" -androidvmtools = "c0c1a98" +androidvmtools = "33b8aa9" zygoteloader = "bf5078e182" [plugins] From cf7ab1f3674b482bfe968242bea375672e104642 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Mar 2026 19:05:36 +0300 Subject: [PATCH 060/162] Make the update dialog less annoying, also optimize imports --- app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt | 7 +++++-- .../icu/nullptr/hidemyapplist/service/ConfigManager.kt | 2 +- .../java/icu/nullptr/hidemyapplist/service/PrefManager.kt | 2 +- .../nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt | 2 +- .../main/java/icu/nullptr/hidemyapplist/ui/util/Toast.kt | 2 +- .../java/icu/nullptr/hidemyapplist/util/PackageHelper.kt | 2 +- .../org/frknkrc44/hma_oss/ui/activity/MainActivity.kt | 2 +- .../frknkrc44/hma_oss/ui/fragment/AppPresetFragment.kt | 2 +- .../org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt | 6 +++++- .../frknkrc44/hma_oss/ui/fragment/PresetManageFragment.kt | 2 +- .../java/icu/nullptr/hidemyapplist/common/AppPresets.kt | 1 - .../frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt | 4 ++-- .../org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt | 6 +++--- .../frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt | 6 +++--- .../frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt | 2 +- .../java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 4 ++-- .../frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt | 2 +- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt | 6 +++--- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt | 8 ++++---- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt | 8 ++++---- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt | 6 +++--- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt | 6 +++--- .../frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt | 6 +++--- .../frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt | 2 +- .../java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt | 2 +- .../org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt | 2 +- .../org/frknkrc44/hma_oss/zygote/service/HMAService.kt | 3 +-- .../frknkrc44/hma_oss/zygote/service/SystemServerHook.kt | 2 +- .../org/frknkrc44/hma_oss/zygote/service/UserService.kt | 6 +++--- .../org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt | 2 +- 30 files changed, 59 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt b/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt index e832624e9..8710625e0 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt @@ -16,14 +16,17 @@ import me.zhanghai.android.appiconloader.AppIconLoader import org.frknkrc44.hma_oss.R import kotlin.system.exitProcess -lateinit var hmaApp: MyApp - class MyApp : Application() { + companion object { + lateinit var hmaApp: MyApp + } + val globalScope = CoroutineScope(Dispatchers.Default) val appIconLoader by lazy { val iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size) AppIconLoader(iconSize, false, this) } + var updateDialogSkipped: Boolean = false @Suppress("DEPRECATION") @SuppressLint("SdCardPath") diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 6418f8fc8..0de7d20d3 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -2,9 +2,9 @@ package icu.nullptr.hidemyapplist.service import android.os.Build import android.util.Log +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem -import icu.nullptr.hidemyapplist.hmaApp import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper import org.frknkrc44.hma_oss.R diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt index 684adf29c..d02b4970a 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt @@ -5,8 +5,8 @@ import android.content.Context.MODE_PRIVATE import android.content.pm.PackageManager import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.edit +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.data.AppConstants -import icu.nullptr.hidemyapplist.hmaApp import icu.nullptr.hidemyapplist.ui.util.get import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent import kotlinx.coroutines.flow.MutableSharedFlow diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt index cfcdda609..1cc3031c3 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt @@ -20,10 +20,10 @@ import androidx.preference.SwitchPreferenceCompat import com.google.android.material.color.DynamicColors import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.PropertyUtils -import icu.nullptr.hidemyapplist.hmaApp import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Toast.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Toast.kt index 82e03a510..c2b823792 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Toast.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Toast.kt @@ -2,7 +2,7 @@ package icu.nullptr.hidemyapplist.ui.util import android.widget.Toast import androidx.annotation.StringRes -import icu.nullptr.hidemyapplist.hmaApp +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp fun showToast(@StringRes resId: Int) { Toast.makeText(hmaApp, resId, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt index 61c7278ff..de0e7e3eb 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt @@ -11,8 +11,8 @@ import android.os.UserManager import android.util.Log import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.toDrawable +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.hmaApp import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt index 8604f7a43..bb2ee113b 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt @@ -10,7 +10,7 @@ import androidx.core.graphics.drawable.toDrawable import androidx.navigation.findNavController import com.google.android.material.color.DynamicColors import com.google.android.material.color.DynamicColorsOptions -import icu.nullptr.hidemyapplist.hmaApp +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient import icu.nullptr.hidemyapplist.ui.util.ThemeUtils diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppPresetFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppPresetFragment.kt index 73614cf26..ee1b1f743 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppPresetFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppPresetFragment.kt @@ -4,7 +4,7 @@ import android.os.Bundle import android.view.View import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs -import icu.nullptr.hidemyapplist.hmaApp +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.ui.fragment.AppSelectFragment import icu.nullptr.hidemyapplist.util.PackageHelper diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 330387783..889b272b1 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.data.fetchLatestUpdate import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager @@ -329,7 +330,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } private fun loadUpdateDialog() { - if (PrefManager.disableUpdate || BuildConfig.VERSION_NAME.count { it == '-' } != 1) return + if (hmaApp.updateDialogSkipped || PrefManager.disableUpdate || BuildConfig.VERSION_NAME.count { it == '-' } != 1) return fetchLatestUpdate { updateInfo -> if (updateInfo.versionName != BuildConfig.VERSION_NAME) { withContext(Dispatchers.Main) { @@ -346,6 +347,9 @@ class HomeFragment : Fragment(R.layout.fragment_home) { ) } .setNegativeButton(android.R.string.cancel, null) + .setOnDismissListener { + hmaApp.updateDialogSkipped = true + } .show() } } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/PresetManageFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/PresetManageFragment.kt index ade98187d..450a153a1 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/PresetManageFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/PresetManageFragment.kt @@ -7,7 +7,7 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding -import icu.nullptr.hidemyapplist.hmaApp +import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.ServiceClient import icu.nullptr.hidemyapplist.ui.util.navController diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt index a607afe6b..65b892e53 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/AppPresets.kt @@ -14,7 +14,6 @@ import icu.nullptr.hidemyapplist.common.app_presets.RootAppsPreset import icu.nullptr.hidemyapplist.common.app_presets.SDhizukuAppsPreset import icu.nullptr.hidemyapplist.common.app_presets.SuspiciousAppsPreset import icu.nullptr.hidemyapplist.common.app_presets.XposedModulesPreset -import org.frknkrc44.hma_oss.common.BuildConfig import java.util.zip.ZipFile class AppPresets private constructor() { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index cc645c80e..9edae2ed9 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -6,10 +6,10 @@ import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS class AccessibilityHook(private val service: HMAService) : IFrameworkHook { override val TAG = "AccessibilityHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index 55180be89..fe89814bf 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -8,6 +8,9 @@ import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField @@ -16,9 +19,6 @@ import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_STARTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_TASK_SUPERVISOR_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.COMPUTER_ENGINE_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV class ActivityHook(private val service: HMAService) : IFrameworkHook { override val TAG = "ActivityHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 59b2cb1e1..d1c5d758d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -6,6 +6,9 @@ import androidx.annotation.RequiresApi import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getBooleanField import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getIntField @@ -13,9 +16,6 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.setBooleanField import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PROCESS_LIST_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.STORAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logE -import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import java.util.Map @RequiresApi(Build.VERSION_CODES.R) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 880d27198..107a8bf89 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -10,9 +10,9 @@ import android.provider.Settings import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.CONTENT_PROVIDER_TRANSPORT_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD class ContentProviderHook(private val service: HMAService): IFrameworkHook { override val TAG = "ContentProviderHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 06509cdcc..e363ae3a2 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -11,11 +11,11 @@ import icu.nullptr.hidemyapplist.common.settings_presets.InputMethodPreset import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import java.util.Collections class ImmHook(private val service: HMAService) : IFrameworkHook { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index 85e4be422..e139b3909 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -7,10 +7,10 @@ import icu.nullptr.hidemyapplist.common.PropertyUtils import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PLATFORM_COMPAT_CLASS import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PLATFORM_COMPAT_CLASS @RequiresApi(Build.VERSION_CODES.R) class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index bbc3f6317..e8a8cc62e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -3,12 +3,12 @@ package org.frknkrc44.hma_oss.zygote.hook import icu.nullptr.hidemyapplist.common.Constants import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index b0d03aa30..9de9b0453 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -7,14 +7,14 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.R) class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index 7d72cdf7e..fc34a81a1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -7,14 +7,14 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PMS_COMPUTER_TRACKER_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.S) class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index 9e67e91da..428def99f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -8,13 +8,13 @@ import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.TIRAMISU) class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index eda2eb97a..40eb2daf0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -9,14 +9,14 @@ import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index cc2b22e07..68b05d476 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -11,13 +11,13 @@ import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callMethod import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.COMPUTER_ENGINE_CLASS -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache import java.util.concurrent.atomic.AtomicReference abstract class PmsHookTargetBase(protected val service: HMAService) : IFrameworkHook { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index 8fe13a5ad..86b38b111 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -5,8 +5,8 @@ import android.os.Build import android.os.Bundle import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { override val TAG = "PmsPackageEventsHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index d0ac036b3..acc90a372 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -3,8 +3,8 @@ package org.frknkrc44.hma_oss.zygote.hook import icu.nullptr.hidemyapplist.common.Constants import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ZYGOTE_PROCESS_CLASS import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ZYGOTE_PROCESS_CLASS class ZygoteHook(private val service: HMAService) : IFrameworkHook { override val TAG = "ZygoteHook" diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index 37be4c9b5..b27ddcc96 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -7,12 +7,12 @@ import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.HookTransformer import com.v7878.vmtools.Hooks -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.ZygoteEntry import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import java.lang.invoke.MethodHandle import java.lang.reflect.Executable import java.lang.reflect.Method diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 55b4ea08b..c0851eca4 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -25,7 +25,6 @@ import icu.nullptr.hidemyapplist.common.Utils.removeIf import icu.nullptr.hidemyapplist.common.app_presets.DetectorAppsPreset import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature import org.frknkrc44.hma_oss.zygote.hook.AccessibilityHook import org.frknkrc44.hma_oss.zygote.hook.ActivityHook import org.frknkrc44.hma_oss.zygote.hook.AppDataIsolationHook @@ -45,13 +44,13 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logW import org.frknkrc44.hma_oss.zygote.util.Logcat.logWithLevel +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.UserManagerApis import java.io.File import java.lang.reflect.Modifier import java.util.concurrent.ExecutorService import java.util.concurrent.Executors -import kotlin.collections.get class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 5964246c0..b299a9c43 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -7,11 +7,11 @@ import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.Hooks -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import kotlin.concurrent.thread @SuppressLint("PrivateApi") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index 83a0b700e..2b4c2ecbd 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -7,12 +7,12 @@ import android.os.Bundle import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.adapter.UidObserverAdapter diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index beea91022..7c5f04efa 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -13,8 +13,8 @@ import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.Magic +import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.SystemServerHook import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import java.io.File From 5ffa483a0de1116ee635fcddda5b783c453bd58d Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Mar 2026 21:56:25 +0300 Subject: [PATCH 061/162] Add more meaningful declaration for test build check --- app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt | 3 +++ .../java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt index ff7f21a46..2255f6bac 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt @@ -4,6 +4,7 @@ import android.content.ComponentName import android.content.pm.ActivityInfo import android.content.res.Resources import kotlinx.coroutines.flow.MutableSharedFlow +import org.frknkrc44.hma_oss.BuildConfig import org.frknkrc44.hma_oss.R fun Boolean.enabledString(resources: Resources, lower: Boolean = false): String { @@ -16,3 +17,5 @@ fun Boolean.enabledString(resources: Resources, lower: Boolean = false): String fun ActivityInfo.asComponentName() = ComponentName(packageName, name) fun MutableSharedFlow.get() = replayCache.first() + +val isTestBuild get() = BuildConfig.VERSION_NAME.count { it == '-' } != 1 diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 889b272b1..dcc6933cb 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -25,6 +25,7 @@ import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.getColor import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.themeColor import icu.nullptr.hidemyapplist.ui.util.contentResolver +import icu.nullptr.hidemyapplist.ui.util.isTestBuild import icu.nullptr.hidemyapplist.ui.util.navigate import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags import icu.nullptr.hidemyapplist.ui.util.setupToolbar @@ -330,7 +331,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } private fun loadUpdateDialog() { - if (hmaApp.updateDialogSkipped || PrefManager.disableUpdate || BuildConfig.VERSION_NAME.count { it == '-' } != 1) return + if (hmaApp.updateDialogSkipped || PrefManager.disableUpdate || isTestBuild) return fetchLatestUpdate { updateInfo -> if (updateInfo.versionName != BuildConfig.VERSION_NAME) { withContext(Dispatchers.Main) { From 7f052e42c19250c73aa1d63e53b48e2ed4277fa2 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 24 Mar 2026 22:00:48 +0300 Subject: [PATCH 062/162] Try to improve PR actions --- .github/workflows/pull_request.yml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index b9e0c5010..65d6de674 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -59,14 +59,24 @@ jobs: - name: Build debug id: buildDebug run: | - ./gradlew :app:assembleDebug :zygote:assembleDebug - echo "debugName=$(ls app/build/outputs/apk/debug/*.apk | awk -F '(/|.apk)' '{print $6}')" >> $GITHUB_OUTPUT + ./gradlew assembleDebug + echo "debugAPKName=$(ls app/build/outputs/apk/debug/*.apk | awk -F '(/|.apk)' '{print $6}')" >> $GITHUB_OUTPUT + echo "debugZIPName=$(ls zygote/build/outputs/magisk/debug/*.zip | awk -F '(/|.zip)' '{print $6}')" >> $GITHUB_OUTPUT - - name: Upload debug + - name: Upload debug APK if: success() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: - name: ${{ steps.buildDebug.outputs.debugName }} + archive: false + name: ${{ steps.buildDebug.outputs.debugAPKName }} path: | app/build/outputs/apk/debug/*.apk + + - name: Upload debug ZIP + if: success() + uses: actions/upload-artifact@v7 + with: + archive: false + name: ${{ steps.buildDebug.outputs.debugZIPName }} + path: | zygote/build/outputs/magisk/debug/*.zip From 5b5a6dc501a507c0325efbaa05ce8f31db8b53aa Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 26 Mar 2026 01:06:34 +0300 Subject: [PATCH 063/162] Switch to initial ZygoteLoader C implementation by ThePedroo --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 279f697c0..b883ace6b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.0" androidvmtools = "33b8aa9" -zygoteloader = "bf5078e182" +zygoteloader = "7a7e52c0f2" [plugins] agp-app = { id = "com.android.application", version.ref = "agp" } From cf39b4608937ba29337fd22bd6cab80c61ffd49f Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 26 Mar 2026 18:18:56 +0300 Subject: [PATCH 064/162] Add new packages into presets --- .../hidemyapplist/common/app_presets/DetectorAppsPreset.kt | 1 + .../hidemyapplist/common/app_presets/SuspiciousAppsPreset.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt index ff233308e..55b710a27 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt @@ -37,6 +37,7 @@ class DetectorAppsPreset : BasePreset(NAME) { "com.chuqniudetector", "com.chunqiudetector", "com.longz.detector", + "com.anycheck.app", // Add more detector apps (thanks @Yurii0307) "com.lingqing.detector", diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/SuspiciousAppsPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/SuspiciousAppsPreset.kt index d6006ed24..5759a3145 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/SuspiciousAppsPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/SuspiciousAppsPreset.kt @@ -13,6 +13,7 @@ class SuspiciousAppsPreset : BasePreset(NAME) { "berserker.android.apps.sshdroid", "com.iamaner.oneclickfreeze", "com.shamanland.privatescreenshots", + "org.connectbot", // Remote desktop apps "com.devolutions.remotedesktopmanager", From 115dd5ee136d8274ac9f5295d98461605bd5a5d5 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 27 Mar 2026 11:25:21 +0300 Subject: [PATCH 065/162] Try to fix Android 17 Beta 3+ crash --- .../main/java/icu/nullptr/hidemyapplist/common/Utils.kt | 8 -------- .../org/frknkrc44/hma_oss/zygote/service/HMAService.kt | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index 07ae5eea2..2a6c7bc33 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -30,14 +30,6 @@ object Utils { return result } - fun getInstalledPackagesCompat(pms: IPackageManager, flags: Long, userId: Int): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - pms.getInstalledPackages(flags, userId) - } else { - pms.getInstalledPackages(flags.toInt(), userId) - }.list - } - fun getInstalledApplicationsCompat(pms: IPackageManager, flags: Long, userId: Int): List { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { pms.getInstalledApplications(flags, userId) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index c0851eca4..67cee8368 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -18,7 +18,6 @@ import icu.nullptr.hidemyapplist.common.SettingsPresets import icu.nullptr.hidemyapplist.common.Utils.binderLocalScope import icu.nullptr.hidemyapplist.common.Utils.generateRandomString import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat -import icu.nullptr.hidemyapplist.common.Utils.getInstalledPackagesCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageUidCompat import icu.nullptr.hidemyapplist.common.Utils.removeIf @@ -547,7 +546,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun getPackageNames(userId: Int) = binderLocalScope { - getInstalledPackagesCompat(pms, 0L, userId).map { it.packageName }.toTypedArray() + getInstalledApplicationsCompat(pms, 0L, userId).map { it.packageName }.toTypedArray() } override fun getPackageInfo( From eddb542c137ef3870f80f698762b7f33fb97cdef Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 27 Mar 2026 15:38:07 +0300 Subject: [PATCH 066/162] Revert "Switch to initial ZygoteLoader C implementation by ThePedroo" This reverts commit 5b5a6dc501a507c0325efbaa05ce8f31db8b53aa. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b883ace6b..279f697c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.0" androidvmtools = "33b8aa9" -zygoteloader = "7a7e52c0f2" +zygoteloader = "bf5078e182" [plugins] agp-app = { id = "com.android.application", version.ref = "agp" } From f20c33223d875b08cb4a855997d851dc571d24d0 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 27 Mar 2026 16:12:26 +0300 Subject: [PATCH 067/162] Implement waitForService for onActiveUid delays --- .../hma_oss/ui/fragment/HomeFragment.kt | 111 +++++++++++------- 1 file changed, 70 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index dcc6933cb..30f09de7d 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -40,6 +40,7 @@ import java.io.IOException import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +import kotlin.concurrent.thread /** * A simple [Fragment] subclass. @@ -92,7 +93,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { with(binding.toolbar) { setupToolbar( - toolbar = binding.toolbar, + toolbar = this, title = getString(R.string.app_name), ) // isTitleCentered = true @@ -101,54 +102,32 @@ class HomeFragment : Fragment(R.layout.fragment_home) { setEdge2EdgeFlags(binding.root) } - override fun onStart() { - super.onStart() - - val serviceVersion = ServiceClient.serviceVersion - var color = when { - serviceVersion == 0 -> getColor(R.color.invalid) - else -> themeColor(android.R.attr.colorPrimary) + fun waitForService() { + var serviceVersion = ServiceClient.serviceVersion + if (serviceVersion > 0) { + loadEnabledIndicator() + return } - if (PrefManager.systemWallpaper) color -= 0x55000000 - - with(binding.statusCard) { - root.setCardBackgroundColor(color) - root.outlineAmbientShadowColor = color - root.outlineSpotShadowColor = color + thread { + var count = 0 - if (serviceVersion > 0) { - moduleStatusIcon.setImageResource(R.drawable.sentiment_calm_24px) - val versionNameSimple = ServiceClient.serviceVersionName ?: BuildConfig.VERSION_NAME - moduleStatus.text = - getString(R.string.home_xposed_activated, versionNameSimple) - root.setOnLongClickListener { - ConfigManager.saveConfig() - showToast(android.R.string.ok) - - true - } - } else { - moduleStatusIcon.setImageResource(R.drawable.sentiment_very_dissatisfied_24px) - moduleStatus.setText(R.string.home_xposed_not_activated) + while (ServiceClient.serviceVersion.also { serviceVersion = it } <= 0 && count++ < 100) { + Thread.sleep(100) } - if (serviceVersion != 0) { - if (serviceVersion < org.frknkrc44.hma_oss.common.BuildConfig.SERVICE_VERSION) { - serviceStatus.text = - getString(R.string.home_xposed_service_old) - } else { - serviceStatus.text = - getString(R.string.home_xposed_service_on, serviceVersion) + if (serviceVersion > 0) { + lifecycleScope.launch { + loadEnabledIndicator() } - filterCount.visibility = View.VISIBLE - filterCount.text = - getString(R.string.home_xposed_filter_count, ServiceClient.filterCount) - } else { - serviceStatus.setText(R.string.home_xposed_service_off) - filterCount.visibility = View.GONE } } + } + + override fun onStart() { + super.onStart() + + waitForService() with(binding.howToUse.root.parent as ViewGroup) { val childCount = childCount @@ -330,6 +309,56 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } } + fun loadEnabledIndicator() { + val serviceVersion = ServiceClient.serviceVersion + var color = when { + serviceVersion == 0 -> getColor(R.color.invalid) + else -> themeColor(android.R.attr.colorPrimary) + } + + if (PrefManager.systemWallpaper) { + color -= 0x55000000 + } + + with(binding.statusCard) { + root.setCardBackgroundColor(color) + root.outlineAmbientShadowColor = color + root.outlineSpotShadowColor = color + + if (serviceVersion > 0) { + moduleStatusIcon.setImageResource(R.drawable.sentiment_calm_24px) + val versionNameSimple = ServiceClient.serviceVersionName ?: BuildConfig.VERSION_NAME + moduleStatus.text = + getString(R.string.home_xposed_activated, versionNameSimple) + root.setOnLongClickListener { + ConfigManager.saveConfig() + showToast(android.R.string.ok) + + true + } + } else { + moduleStatusIcon.setImageResource(R.drawable.sentiment_very_dissatisfied_24px) + moduleStatus.setText(R.string.home_xposed_not_activated) + } + + if (serviceVersion != 0) { + if (serviceVersion < org.frknkrc44.hma_oss.common.BuildConfig.SERVICE_VERSION) { + serviceStatus.text = + getString(R.string.home_xposed_service_old) + } else { + serviceStatus.text = + getString(R.string.home_xposed_service_on, serviceVersion) + } + filterCount.visibility = View.VISIBLE + filterCount.text = + getString(R.string.home_xposed_filter_count, ServiceClient.filterCount) + } else { + serviceStatus.setText(R.string.home_xposed_service_off) + filterCount.visibility = View.GONE + } + } + } + private fun loadUpdateDialog() { if (hmaApp.updateDialogSkipped || PrefManager.disableUpdate || isTestBuild) return fetchLatestUpdate { updateInfo -> From 5b4384e4955b69ddbd56d95dd1185b1cdabc72d8 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 28 Mar 2026 13:14:59 +0300 Subject: [PATCH 068/162] Move dp calculation functions --- .../main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt | 3 +++ .../java/icu/nullptr/hidemyapplist/ui/view/ListItemView.kt | 3 ++- .../java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt | 7 ++++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt index 2255f6bac..eeca6ea01 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt @@ -3,6 +3,7 @@ package icu.nullptr.hidemyapplist.ui.util import android.content.ComponentName import android.content.pm.ActivityInfo import android.content.res.Resources +import androidx.fragment.app.Fragment import kotlinx.coroutines.flow.MutableSharedFlow import org.frknkrc44.hma_oss.BuildConfig import org.frknkrc44.hma_oss.R @@ -18,4 +19,6 @@ fun ActivityInfo.asComponentName() = ComponentName(packageName, name) fun MutableSharedFlow.get() = replayCache.first() +fun dp2Px(res: Resources, dp: Int) = res.displayMetrics.density * dp + val isTestBuild get() = BuildConfig.VERSION_NAME.count { it == '-' } != 1 diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/view/ListItemView.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/view/ListItemView.kt index 297b8b6eb..7bbf880a9 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/view/ListItemView.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/view/ListItemView.kt @@ -9,6 +9,7 @@ import androidx.core.view.isVisible import dev.androidbroadcast.vbpd.CreateMethod import dev.androidbroadcast.vbpd.viewBinding import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.themeColor +import icu.nullptr.hidemyapplist.ui.util.dp2Px import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.databinding.ListItemViewBinding @@ -72,7 +73,7 @@ class ListItemView @JvmOverloads constructor( ) setTextColor(textColor) - val padding = (resources.displayMetrics.density * 8f).toInt() + val padding = dp2Px(resources, 8).toInt() setPaddingRelative(paddingStart, padding, paddingEnd, padding) } } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 30f09de7d..21c021d35 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -25,6 +25,7 @@ import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.getColor import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.themeColor import icu.nullptr.hidemyapplist.ui.util.contentResolver +import icu.nullptr.hidemyapplist.ui.util.dp2Px import icu.nullptr.hidemyapplist.ui.util.isTestBuild import icu.nullptr.hidemyapplist.ui.util.navigate import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags @@ -132,9 +133,9 @@ class HomeFragment : Fragment(R.layout.fragment_home) { with(binding.howToUse.root.parent as ViewGroup) { val childCount = childCount - val softCorner: Float = resources.displayMetrics.density * 24 - val squareCorner: Float = resources.displayMetrics.density * 8 - val pad = (resources.displayMetrics.density * 16).toInt() + val softCorner: Float = dp2Px(resources, 24) + val squareCorner: Float = dp2Px(resources, 8) + val pad = dp2Px(resources, 16).toInt() for (i in 0..< childCount) { getChildAt(i).apply { From 73b00f878fbaeee1d2afebede0f7d60eeb24575a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 28 Mar 2026 13:34:22 +0300 Subject: [PATCH 069/162] Improve enabled indicator checks --- .../hma_oss/ui/fragment/HomeFragment.kt | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 21c021d35..83fdc4bfa 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -103,28 +103,6 @@ class HomeFragment : Fragment(R.layout.fragment_home) { setEdge2EdgeFlags(binding.root) } - fun waitForService() { - var serviceVersion = ServiceClient.serviceVersion - if (serviceVersion > 0) { - loadEnabledIndicator() - return - } - - thread { - var count = 0 - - while (ServiceClient.serviceVersion.also { serviceVersion = it } <= 0 && count++ < 100) { - Thread.sleep(100) - } - - if (serviceVersion > 0) { - lifecycleScope.launch { - loadEnabledIndicator() - } - } - } - } - override fun onStart() { super.onStart() @@ -310,8 +288,29 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } } - fun loadEnabledIndicator() { - val serviceVersion = ServiceClient.serviceVersion + fun waitForService() { + var serviceVersion = ServiceClient.serviceVersion + loadEnabledIndicator(serviceVersion) + if (serviceVersion > 0) { + return + } + + thread { + var count = 0 + + while (ServiceClient.serviceVersion.also { serviceVersion = it } <= 0 && count++ < 100) { + Thread.sleep(100) + } + + if (serviceVersion > 0) { + lifecycleScope.launch { + loadEnabledIndicator(serviceVersion) + } + } + } + } + + fun loadEnabledIndicator(serviceVersion: Int) { var color = when { serviceVersion == 0 -> getColor(R.color.invalid) else -> themeColor(android.R.attr.colorPrimary) @@ -337,12 +336,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { true } - } else { - moduleStatusIcon.setImageResource(R.drawable.sentiment_very_dissatisfied_24px) - moduleStatus.setText(R.string.home_xposed_not_activated) - } - if (serviceVersion != 0) { if (serviceVersion < org.frknkrc44.hma_oss.common.BuildConfig.SERVICE_VERSION) { serviceStatus.text = getString(R.string.home_xposed_service_old) @@ -354,6 +348,8 @@ class HomeFragment : Fragment(R.layout.fragment_home) { filterCount.text = getString(R.string.home_xposed_filter_count, ServiceClient.filterCount) } else { + moduleStatusIcon.setImageResource(R.drawable.sentiment_very_dissatisfied_24px) + moduleStatus.setText(R.string.home_xposed_not_activated) serviceStatus.setText(R.string.home_xposed_service_off) filterCount.visibility = View.GONE } From 64033ba2bffebebc9ccf301eeb90f147dec50672 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 28 Mar 2026 14:15:20 +0300 Subject: [PATCH 070/162] Add "Enable/Disable Internet" functionality --- .../hidemyapplist/service/ConfigManager.kt | 16 +++++++++ .../ui/fragment/SettingsFragment.kt | 3 ++ .../hma_oss/ui/fragment/AboutFragment.kt | 16 ++++++--- .../hma_oss/ui/fragment/HomeFragment.kt | 35 +++++++++++++++++-- .../main/res/drawable/plug_connect_24px.xml | 5 +++ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/settings.xml | 8 +++++ .../nullptr/hidemyapplist/common/Constants.kt | 4 +++ .../hidemyapplist/common/JsonConfig.kt | 2 ++ 9 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/drawable/plug_connect_24px.xml diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 0de7d20d3..d56aeb335 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -3,6 +3,7 @@ package icu.nullptr.hidemyapplist.service import android.os.Build import android.util.Log import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp +import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast @@ -150,6 +151,21 @@ object ConfigManager { showToast(R.string.settings_need_reboot) } + var enableInternet: Int + get() = config.enableInternet + set(value) { + config.enableInternet = value + saveConfig() + } + + fun setEnableInternet(value: Boolean) { + enableInternet = if (value) { + Constants.ENABLE_INTERNET_ON + } else { + Constants.ENABLE_INTERNET_OFF + } + } + fun importConfig(json: String) { config = JsonConfig.parse(json) config.configVersion = BuildConfig.CONFIG_VERSION diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt index 1cc3031c3..3fe8f25cb 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt @@ -25,6 +25,7 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.PropertyUtils import icu.nullptr.hidemyapplist.service.ConfigManager +import icu.nullptr.hidemyapplist.service.ConfigManager.setEnableInternet import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient import icu.nullptr.hidemyapplist.ui.util.enabledString @@ -99,6 +100,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen "skipSystemAppDataIsolation" -> ConfigManager.skipSystemAppDataIsolation "disableActivityLaunchProtection" -> ConfigManager.disableActivityLaunchProtection "forceMountData" -> ConfigManager.forceMountData + "enableInternet" -> ConfigManager.enableInternet == Constants.ENABLE_INTERNET_ON "disableUpdate" -> PrefManager.disableUpdate "packageQueryWorkaround" -> ConfigManager.packageQueryWorkaround else -> throw IllegalArgumentException("Invalid key: $key") @@ -137,6 +139,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen "detailLog" -> ConfigManager.detailLog = value "errorOnlyLog" -> ConfigManager.errorOnlyLog = value "forceMountData" -> ConfigManager.forceMountData = value + "enableInternet" -> setEnableInternet(value) "disableUpdate" -> PrefManager.disableUpdate = value "hideIcon" -> PrefManager.hideIcon = value "bypassRiskyPackageWarning" -> PrefManager.bypassRiskyPackageWarning = value diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt index 02a1aca60..e9e1e18e0 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt @@ -15,6 +15,8 @@ import androidx.transition.AutoTransition import androidx.transition.TransitionManager import com.bumptech.glide.Glide import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.ui.util.AccessibilityUtils import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor @@ -171,11 +173,15 @@ class AboutFragment : Fragment(R.layout.fragment_about) { fun addTranslatorItem(layout: LinearLayout, avatarUrl: String, name: String) { val newLayout = FragmentAboutListItemBinding.inflate(layoutInflater) - Glide.with(this) - .load(avatarUrl) - .placeholder(R.drawable.outline_info_24) - .circleCrop() - .into(newLayout.aboutPersonIcon) + if (ConfigManager.enableInternet == Constants.ENABLE_INTERNET_ON) { + Glide.with(this) + .load(avatarUrl) + .placeholder(R.drawable.outline_info_24) + .circleCrop() + .into(newLayout.aboutPersonIcon) + } else { + newLayout.aboutPersonIcon.isVisible = false + } newLayout.text1.text = name newLayout.text2.visibility = View.GONE diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 83fdc4bfa..c68b23ec0 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -16,6 +16,7 @@ import androidx.lifecycle.lifecycleScope import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp +import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.data.fetchLatestUpdate import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager @@ -284,7 +285,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } lifecycleScope.launch { - loadUpdateDialog() + loadDialogs() } } @@ -356,8 +357,36 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } } - private fun loadUpdateDialog() { - if (hmaApp.updateDialogSkipped || PrefManager.disableUpdate || isTestBuild) return + private fun loadDialogs() { + if (ConfigManager.enableInternet == Constants.ENABLE_INTERNET_UNKNOWN) { + loadEnableInternetDialogLocked() + return + } + + if (ConfigManager.enableInternet != Constants.ENABLE_INTERNET_ON || + hmaApp.updateDialogSkipped || PrefManager.disableUpdate || isTestBuild) { + return + } + + loadUpdateDialogLocked() + } + + private fun loadEnableInternetDialogLocked() { + MaterialAlertDialogBuilder(requireContext()) + .setCancelable(false) + .setTitle(R.string.settings_enable_internet) + .setMessage(R.string.settings_enable_internet_summary) + .setPositiveButton(R.string.yes) { _, _ -> + ConfigManager.enableInternet = Constants.ENABLE_INTERNET_ON + loadUpdateDialogLocked() + } + .setNegativeButton(R.string.no) { _, _ -> + ConfigManager.enableInternet = Constants.ENABLE_INTERNET_OFF + } + .show() + } + + private fun loadUpdateDialogLocked() { fetchLatestUpdate { updateInfo -> if (updateInfo.versionName != BuildConfig.VERSION_NAME) { withContext(Dispatchers.Main) { diff --git a/app/src/main/res/drawable/plug_connect_24px.xml b/app/src/main/res/drawable/plug_connect_24px.xml new file mode 100644 index 000000000..b48c0a9c5 --- /dev/null +++ b/app/src/main/res/drawable/plug_connect_24px.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c4c7e9769..64ed50661 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -192,6 +192,8 @@ Error-only log Disable functions You can disable some of the functions when they conflict with other modules + Enable Internet connection + This app will lose all of Internet-related functionality when you disabled this option. Language Participate in translation diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index 78ed57610..241cae0c7 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -141,6 +141,14 @@ + = mutableMapOf(), val settingsTemplates: MutableMap = mutableMapOf(), val disabledHooks: MutableList = mutableListOf(), From 2760a5a2c31700917c58b149f1ef7e7b39ea9687 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 28 Mar 2026 15:49:15 +0300 Subject: [PATCH 071/162] Add more descriptions --- .../nullptr/hidemyapplist/ui/util/Fragment.kt | 40 ++++++++++++++++++- .../hma_oss/ui/fragment/HomeFragment.kt | 5 ++- app/src/main/res/values/strings.xml | 3 ++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt index e1eecf6bf..19d195eb7 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt @@ -2,13 +2,18 @@ package icu.nullptr.hidemyapplist.ui.util import android.content.ContentResolver import android.content.Intent +import android.graphics.Typeface import android.os.Build import android.os.Bundle +import android.os.SystemClock.elapsedRealtime +import android.view.Gravity import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View +import android.view.ViewGroup import android.view.WindowInsets +import android.widget.Chronometer import androidx.annotation.DrawableRes import androidx.annotation.IdRes import androidx.annotation.MenuRes @@ -18,6 +23,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import androidx.navigation.NavOptions import androidx.navigation.fragment.NavHostFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.ui.activity.MainActivity @@ -48,8 +54,40 @@ fun Fragment.setupToolbar( @DrawableRes navigationIcon: Int? = null, navigationOnClick: View.OnClickListener? = null, @MenuRes menuRes: Int? = null, - onMenuOptionSelected: ((MenuItem) -> Unit)? = null + onMenuOptionSelected: ((MenuItem) -> Unit)? = null, + isHomeToolbar: Boolean = false, ) { + if (isHomeToolbar) { + toolbar.setOnLongClickListener { + val dialog = MaterialAlertDialogBuilder(toolbar.context) + .setTitle(R.string.app_name) + .create() + + dialog.setView(Chronometer(toolbar.context).apply { + layoutParams = ViewGroup.LayoutParams(-1, -2) + base = elapsedRealtime() + 3000 + textSize = dp2Px(toolbar.resources, 24) + gravity = Gravity.CENTER + typeface = Typeface.SERIF + onChronometerTickListener = { + if (elapsedRealtime() >= base) { + stop() + dialog.dismiss() + + // is it really final countdown? + isTheFinalCountDown + } + } + isCountDown = true + start() + }) + + dialog.show() + + true + } + } + navigationOnClick?.let { toolbar.setNavigationOnClickListener(it) } navigationIcon?.let { toolbar.setNavigationIcon(navigationIcon) } toolbar.title = title diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index c68b23ec0..121867462 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -97,6 +97,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { setupToolbar( toolbar = this, title = getString(R.string.app_name), + isHomeToolbar = true, ) // isTitleCentered = true } @@ -197,7 +198,9 @@ class HomeFragment : Fragment(R.layout.fragment_home) { .setMessage( getString(R.string.about_how_to_use_description_1) + "\n\n" + - getString(R.string.about_how_to_use_description_2)) + getString(R.string.about_how_to_use_description_2) + + "\n\n" + + getString(R.string.about_how_to_use_description_3)) .setNegativeButton(android.R.string.ok, null) .show() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 64ed50661..c26058227 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -237,6 +237,9 @@ Config modification effective in real time. + + This application acts like a manager of the Zygisk module from now, so you need a separate Zygisk module to make this manager work. + Translator Developer Support and feedback From e0e1d2387c3c5367aa17c51c595d4efe7fc1f220 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 14:03:50 +0300 Subject: [PATCH 072/162] Improve ImmHook (WIP) --- .../frknkrc44/hma_oss/zygote/ZygoteEntry.java | 3 + .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 95 +++++++++++++++++-- .../hma_oss/zygote/service/BulkHooker.kt | 5 +- .../hma_oss/zygote/service/BulkHookerData.kt | 5 - .../hma_oss/zygote/util/Utils4Zygote.kt | 8 ++ 5 files changed, 99 insertions(+), 17 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java index ef8a876cb..fff5d1213 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java @@ -32,6 +32,9 @@ public static void main() throws Throwable { SystemServerHook.init(); } catch (Throwable th) { logE(TAG, "An exception occurred while SystemServerHook init", th); + + // do not print "Done" if there is an issue + return; } logI(TAG, "Done", null); diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index e363ae3a2..7ba880900 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -1,6 +1,7 @@ package org.frknkrc44.hma_oss.zygote.hook import android.content.ComponentName +import android.os.Binder import android.os.Build import android.provider.Settings import android.view.inputmethod.InputMethodInfo @@ -13,7 +14,9 @@ import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logV +import org.frknkrc44.hma_oss.zygote.util.Logcat.logW import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callStaticMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_SERVICE_CLASS import java.util.Collections @@ -58,6 +61,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { ) } + @Suppress("UNCHECKED_CAST") override fun load() { // OEMs (especially Samsung and Xiaomi) messes up whole framework code, // so nothing left except messing up this code @@ -66,10 +70,10 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { findAltMethod( listOf(IMM_SERVICE_CLASS, IMM_IMPL_CLASS), listOf("getCurrentInputMethodInfoAsUser"), - )?.let { + )?.let { method -> hookBefore( - it.declaringClass.name, - it.name, + method.declaringClass.name, + method.name, ) { param -> val callingApps = Utils4Zygote.getCallingApps(service) @@ -77,7 +81,13 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { if (caller != null) { logD(TAG, "@${param.methodName} spoofed input method for $caller") - param.result = getFakeInputMethodInfo(caller) + val fakeIMInfo = getFakeInputMethodInfo(caller) + val userHandle = param.getArgument(1) as Int + if (Utils.getPackageUidCompat(service.pms, fakeIMInfo.packageName, 0L, userHandle) < 0) { + warnNotInstalledKeyboard(param.methodName, fakeIMInfo.packageName) + } + + param.result = fakeIMInfo service.increaseSettingsFilterCount(caller) } } @@ -87,12 +97,42 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { findAltMethod( listOf(IMM_SERVICE_CLASS), listOf("getInputMethodList", "getInputMethodListInternal"), - )?.let { - hookBefore( - it.declaringClass.name, - it.name, + )?.let { method -> + hookAfter( + method.declaringClass.name, + method.name, ) { param -> - listHook(param) + logD(TAG, "@${param.methodName}: hook init") + + val currentResult = param.result ?: return@hookAfter + logD(TAG, "@${param.methodName}: Result: $currentResult Args: ${param.args.contentToString()}") + + val callingUid = if (param.args.count { it is Int } > 2) { + param.args.lastOrNull { it is Int && it > 999 } as? Int ?: return@hookAfter + } else { + Binder.getCallingUid() + } + + logD(TAG, "@${param.methodName}: Caller ID: $callingUid") + + val returnType = param.frame.type().returnType() + if (returnType.simpleName == "InputMethodInfoSafeList") { + val inList = callStaticMethod( + currentResult.javaClass, + "extractFrom", + currentResult + ) as List + + val newImmList = calculateReturnedInputMethodList(callingUid, inList) + + param.result = returnType.getDeclaredMethod( + "create", + List::class.java, + ).apply { isAccessible = true }.invoke(null, newImmList) + } else { + param.result = calculateReturnedInputMethodList( + callingUid, currentResult as List) + } } } @@ -153,7 +193,13 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { if (caller != null) { logD(TAG, "@${param.methodName} spoofed input method for $caller") - listOf(getFakeInputMethodInfo(caller)).let { list -> + val fakeIMInfo = getFakeInputMethodInfo(caller) + val userHandle = Binder.getCallingUserHandle() + if (Utils.getPackageUidCompat(service.pms, fakeIMInfo.packageName, 0L, userHandle.hashCode()) < 0) { + warnNotInstalledKeyboard(param.methodName, fakeIMInfo.packageName) + } + + listOf(fakeIMInfo).let { list -> val returnType = param.frame.type().returnType() param.result = if (returnType.simpleName == "InputMethodInfoSafeList") { returnType.getDeclaredMethod( @@ -202,6 +248,35 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } } + fun calculateReturnedInputMethodList(callingUid: Int, inList: List): List { + logD(TAG, "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}") + + val caller = Utils4Zygote.getCallingApps(service, callingUid) + .firstOrNull { callerIsSpoofed(it) } ?: return inList + + val calculatedList = inList.filter { imInfo -> + !service.shouldHide(caller, imInfo.packageName) + } + + logD(TAG, "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}") + + val fakeIMInfo = getFakeInputMethodInfo(caller) + + if (!calculatedList.any { it.packageName == fakeIMInfo.packageName }) { + warnNotInstalledKeyboard("getInputMethodList*calculator", fakeIMInfo.packageName) + + return (calculatedList + fakeIMInfo).sortedWith { info1, info2 -> + info1.packageName.compareTo(info2.packageName) + } + } + + return calculatedList + } + + private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { + logW(TAG, "@$methodName: Spoofing for a not installed keyboard, please install $packageName to reduce detections or spoof for another keyboard by using settings templates") + } + private fun callerIsSpoofed(caller: String) = service.getEnabledSettingsPresets(caller).contains(InputMethodPreset.NAME) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index b27ddcc96..371035e4f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -4,6 +4,7 @@ import android.os.Build import com.v7878.unsafe.ArtMethodUtils import com.v7878.unsafe.Reflection import com.v7878.unsafe.invoke.EmulatedStackFrame +import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.HookTransformer import com.v7878.vmtools.Hooks @@ -105,7 +106,7 @@ class BulkHooker private constructor() { } if (value.throwable == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - value.setResultWithoutReplace(frame.accessor().getValue(EmulatedStackFrame.RETURN_VALUE_IDX)) + value.result = frame.accessor().getValue(RETURN_VALUE_IDX) } try { @@ -206,7 +207,7 @@ class BulkHooker private constructor() { element.memoryAddresses?.first!! ) } else { - Transformers.invokeExactPlain(original, frame) + Transformers.invokeExactNoChecks(original, frame) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt index d5f92a75c..3ae92caa2 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt @@ -16,11 +16,6 @@ class ReturnValue(initialValue: Any? = null) { replace = true } - fun setResultWithoutReplace(newValue: Any?) { - result = newValue - replace = false - } - var throwable: Throwable? = null } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index 7c5f04efa..40a07645f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -148,6 +148,14 @@ object Utils4Zygote { ).apply { isAccessible = true }.invoke(obj, *args) } + fun callStaticMethod(clazz: Class<*>, name: String, vararg args: Any): Any? { + return getDeclaredMethod( + clazz, + name, + *args.map { it.javaClass }.toTypedArray() + ).apply { isAccessible = true }.invoke(null, *args) + } + fun findConstructor(className: String, paramCount: Int = -1): Constructor<*>? { val clazz = Class.forName(className, true, SystemServerHook.classLoader) From 567ab73f3591145f7863ca6dc386105b84d86c0b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 14:29:30 +0300 Subject: [PATCH 073/162] Improve ImmHook again --- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 7ba880900..2de526b41 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -83,7 +83,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val fakeIMInfo = getFakeInputMethodInfo(caller) val userHandle = param.getArgument(1) as Int - if (Utils.getPackageUidCompat(service.pms, fakeIMInfo.packageName, 0L, userHandle) < 0) { + if (!isIMExists(fakeIMInfo.packageName, userHandle)) { warnNotInstalledKeyboard(param.methodName, fakeIMInfo.packageName) } @@ -194,8 +194,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { logD(TAG, "@${param.methodName} spoofed input method for $caller") val fakeIMInfo = getFakeInputMethodInfo(caller) - val userHandle = Binder.getCallingUserHandle() - if (Utils.getPackageUidCompat(service.pms, fakeIMInfo.packageName, 0L, userHandle.hashCode()) < 0) { + if (!isIMExists(fakeIMInfo.packageName)) { warnNotInstalledKeyboard(param.methodName, fakeIMInfo.packageName) } @@ -262,17 +261,24 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val fakeIMInfo = getFakeInputMethodInfo(caller) - if (!calculatedList.any { it.packageName == fakeIMInfo.packageName }) { + if (!isIMExists(fakeIMInfo.packageName)) { warnNotInstalledKeyboard("getInputMethodList*calculator", fakeIMInfo.packageName) - return (calculatedList + fakeIMInfo).sortedWith { info1, info2 -> - info1.packageName.compareTo(info2.packageName) + if (!calculatedList.any { it.packageName == fakeIMInfo.packageName }) { + return (calculatedList + fakeIMInfo).sortedWith { info1, info2 -> + info1.packageName.compareTo(info2.packageName) + } } } return calculatedList } + private fun isIMExists(packageName: String, inUserId: Int? = null): Boolean { + val userId = inUserId ?: Binder.getCallingUserHandle().hashCode() + return Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) >= 0 + } + private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { logW(TAG, "@$methodName: Spoofing for a not installed keyboard, please install $packageName to reduce detections or spoof for another keyboard by using settings templates") } From eb6f70b154afe36722fd7b37cf06a31147fbcdb9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 14:32:53 +0300 Subject: [PATCH 074/162] Move some logs to debug builds --- .../org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 2de526b41..2bf4f491f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -191,7 +191,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, "@${param.methodName} spoofed input method for $caller") + logD(TAG, "@${param.methodName}: spoofed input method for $caller") val fakeIMInfo = getFakeInputMethodInfo(caller) if (!isIMExists(fakeIMInfo.packageName)) { @@ -217,7 +217,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, "@${param.methodName} spoofed input method subtype for ${callingApps.contentToString()}") + logD(TAG, "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}") // TODO: Find a method to get exact value for spoofed input method param.result = null @@ -230,7 +230,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, "@${param.methodName} spoofed input method subtype for ${callingApps.contentToString()}") + logD(TAG, "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}") // TODO: Find a method to get exact list for spoofed input method Collections.emptyList().let { list -> @@ -248,16 +248,18 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } fun calculateReturnedInputMethodList(callingUid: Int, inList: List): List { - logD(TAG, "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}") + logV(TAG, "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}") val caller = Utils4Zygote.getCallingApps(service, callingUid) .firstOrNull { callerIsSpoofed(it) } ?: return inList + logD(TAG, "@getInputMethodList: spoofed input method for $caller") + val calculatedList = inList.filter { imInfo -> !service.shouldHide(caller, imInfo.packageName) } - logD(TAG, "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}") + logV(TAG, "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}") val fakeIMInfo = getFakeInputMethodInfo(caller) From 07cd02eff29d13c7339112b6a8634bd891e31e16 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 14:36:43 +0300 Subject: [PATCH 075/162] Improve the warning message --- .../src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 2bf4f491f..0abff2f41 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -282,7 +282,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { - logW(TAG, "@$methodName: Spoofing for a not installed keyboard, please install $packageName to reduce detections or spoof for another keyboard by using settings templates") + logW(TAG, "@$methodName: Spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections") } private fun callerIsSpoofed(caller: String) = From e6b13ce303de181a0ffa54fcb556e3eb1405b689 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 15:08:39 +0300 Subject: [PATCH 076/162] Improve dialogs --- .../hma_oss/ui/fragment/HomeFragment.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 121867462..922dcc0cd 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -362,26 +362,21 @@ class HomeFragment : Fragment(R.layout.fragment_home) { private fun loadDialogs() { if (ConfigManager.enableInternet == Constants.ENABLE_INTERNET_UNKNOWN) { - loadEnableInternetDialogLocked() + loadEnableInternetDialog() return } - if (ConfigManager.enableInternet != Constants.ENABLE_INTERNET_ON || - hmaApp.updateDialogSkipped || PrefManager.disableUpdate || isTestBuild) { - return - } - - loadUpdateDialogLocked() + loadUpdateDialog() } - private fun loadEnableInternetDialogLocked() { + private fun loadEnableInternetDialog() { MaterialAlertDialogBuilder(requireContext()) .setCancelable(false) .setTitle(R.string.settings_enable_internet) .setMessage(R.string.settings_enable_internet_summary) .setPositiveButton(R.string.yes) { _, _ -> ConfigManager.enableInternet = Constants.ENABLE_INTERNET_ON - loadUpdateDialogLocked() + loadUpdateDialog() } .setNegativeButton(R.string.no) { _, _ -> ConfigManager.enableInternet = Constants.ENABLE_INTERNET_OFF @@ -389,7 +384,12 @@ class HomeFragment : Fragment(R.layout.fragment_home) { .show() } - private fun loadUpdateDialogLocked() { + private fun loadUpdateDialog() { + if (ConfigManager.enableInternet != Constants.ENABLE_INTERNET_ON || + hmaApp.updateDialogSkipped || PrefManager.disableUpdate || isTestBuild) { + return + } + fetchLatestUpdate { updateInfo -> if (updateInfo.versionName != BuildConfig.VERSION_NAME) { withContext(Dispatchers.Main) { From 05f938337873f7f2fd4feef3ab0d7918d208037c Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 15:12:01 +0300 Subject: [PATCH 077/162] Fix enable internet icon --- app/src/main/res/drawable/plug_connect_24px.xml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/drawable/plug_connect_24px.xml b/app/src/main/res/drawable/plug_connect_24px.xml index b48c0a9c5..83d3fdc5f 100644 --- a/app/src/main/res/drawable/plug_connect_24px.xml +++ b/app/src/main/res/drawable/plug_connect_24px.xml @@ -1,5 +1,10 @@ - - - - + + From a33b2a35c2620e76ef7ee124a49709c64f49f342 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 15:21:00 +0300 Subject: [PATCH 078/162] Try to use binderLocalScope for uid query --- .../main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 0abff2f41..8a22b1253 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -1,6 +1,7 @@ package org.frknkrc44.hma_oss.zygote.hook import android.content.ComponentName +import android.content.pm.PackageManager import android.os.Binder import android.os.Build import android.provider.Settings @@ -278,7 +279,9 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { private fun isIMExists(packageName: String, inUserId: Int? = null): Boolean { val userId = inUserId ?: Binder.getCallingUserHandle().hashCode() - return Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) >= 0 + return Utils.binderLocalScope { + Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) >= 0 + } } private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { From 3079439982b742ad6c1330d82c99a39114d1a7e9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 15:32:41 +0300 Subject: [PATCH 079/162] Improve calculate im list function --- .../main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 8a22b1253..f9714200c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -264,7 +264,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val fakeIMInfo = getFakeInputMethodInfo(caller) - if (!isIMExists(fakeIMInfo.packageName)) { + if (!(isIMExists(fakeIMInfo.packageName) && calculatedList.any { it.packageName == fakeIMInfo.packageName })) { warnNotInstalledKeyboard("getInputMethodList*calculator", fakeIMInfo.packageName) if (!calculatedList.any { it.packageName == fakeIMInfo.packageName }) { @@ -280,7 +280,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { private fun isIMExists(packageName: String, inUserId: Int? = null): Boolean { val userId = inUserId ?: Binder.getCallingUserHandle().hashCode() return Utils.binderLocalScope { - Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) >= 0 + Utils.getPackageUidCompat(service.pms, packageName, PackageManager.MATCH_ALL.toLong(), userId) >= 0 } } From 4d69a4d677965f7f6c52d18317a26b94d6bf3e0e Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 15:45:46 +0300 Subject: [PATCH 080/162] Improve the non-valid keyboard warning --- .../src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index f9714200c..22bbb10e7 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -285,7 +285,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { - logW(TAG, "@$methodName: Spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections") + logW(TAG, "@$methodName: (Probably) spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections") } private fun callerIsSpoofed(caller: String) = From e6a92e363242be385098a4e0268efb1d02e437b9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 15:53:56 +0300 Subject: [PATCH 081/162] Check for firstOrNull instead of any --- .../org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt index cc3b5dd96..9c1bf59e4 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAServiceCache.kt @@ -12,7 +12,7 @@ class HMAServiceCache private constructor() { fun shouldHideFromUid(uid: Int, query: String?): Boolean? { if (query == null) return null - return uidHideCache.any { it.first == uid && it.third.contains(query) } + return uidHideCache.firstOrNull { it.first == uid && it.third.contains(query) } != null } fun putShouldHideUidCache(uid: Int, caller: String, query: String) { From 6f665ff253a574d08deec4c2e8c1361acf35a497 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 17:37:51 +0300 Subject: [PATCH 082/162] Fix wrongly parsed log --- .../src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 22bbb10e7..42a6548cd 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -285,7 +285,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { - logW(TAG, "@$methodName: (Probably) spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections") + logW(TAG, "@$methodName: PROBABLY spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections") } private fun callerIsSpoofed(caller: String) = From 069913f991d9647cc20cf216f3e54eda64ba5baf Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 29 Mar 2026 18:01:48 +0300 Subject: [PATCH 083/162] Improve the warning message again --- .../src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 42a6548cd..907d6723b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -285,7 +285,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { - logW(TAG, "@$methodName: PROBABLY spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections") + logW(TAG, "@$methodName: PROBABLY spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections. Do not care this message if you are sure the keyboard is installed correctly.") } private fun callerIsSpoofed(caller: String) = From 0eef47508afdf21f79bfe77a86804da7ff51eb21 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 1 Apr 2026 21:46:42 +0300 Subject: [PATCH 084/162] Move listHook contents into getEnabledInputMethodList hook --- .../nullptr/hidemyapplist/ui/util/Common.kt | 1 - .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 50 +++++++++---------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt index eeca6ea01..7f6d930e5 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt @@ -3,7 +3,6 @@ package icu.nullptr.hidemyapplist.ui.util import android.content.ComponentName import android.content.pm.ActivityInfo import android.content.res.Resources -import androidx.fragment.app.Fragment import kotlinx.coroutines.flow.MutableSharedFlow import org.frknkrc44.hma_oss.BuildConfig import org.frknkrc44.hma_oss.R diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 907d6723b..4c7fb5c13 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -145,7 +145,29 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { it.declaringClass.name, it.name, ) { param -> - listHook(param) + val callingApps = Utils4Zygote.getCallingApps(service) + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + logD(TAG, "@${param.methodName}: spoofed input method for $caller") + + val fakeIMInfo = getFakeInputMethodInfo(caller) + if (!isIMExists(fakeIMInfo.packageName)) { + warnNotInstalledKeyboard(param.methodName, fakeIMInfo.packageName) + } + + listOf(fakeIMInfo).let { list -> + val returnType = param.frame.type().returnType() + param.result = if (returnType.simpleName == "InputMethodInfoSafeList") { + returnType.getDeclaredMethod( + "create", + List::class.java, + ).apply { isAccessible = true }.invoke(null, list) + } else { list } + } + + service.increaseSettingsFilterCount(caller) + } } } @@ -187,32 +209,6 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } } - private fun listHook(param: HookParam) { - val callingApps = Utils4Zygote.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG, "@${param.methodName}: spoofed input method for $caller") - - val fakeIMInfo = getFakeInputMethodInfo(caller) - if (!isIMExists(fakeIMInfo.packageName)) { - warnNotInstalledKeyboard(param.methodName, fakeIMInfo.packageName) - } - - listOf(fakeIMInfo).let { list -> - val returnType = param.frame.type().returnType() - param.result = if (returnType.simpleName == "InputMethodInfoSafeList") { - returnType.getDeclaredMethod( - "create", - List::class.java, - ).apply { isAccessible = true }.invoke(null, list) - } else { list } - } - - service.increaseSettingsFilterCount(caller) - } - } - private fun subtypeHook(param: HookParam) { val callingApps = Utils4Zygote.getCallingApps(service) From 3096021e04bf6ccbfcc7d9cff0f1bbb718b98340 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 1 Apr 2026 22:22:16 +0300 Subject: [PATCH 085/162] Add some documentation for JsonConfig --- .../hidemyapplist/common/JsonConfig.kt | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt index db90302eb..fbe398221 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt @@ -9,31 +9,116 @@ import org.frknkrc44.hma_oss.common.BuildConfig @Serializable data class JsonConfig( var configVersion: Int = BuildConfig.CONFIG_VERSION, + + /** + * Enable/disable debug (and verbose for debug builds) logging + */ var detailLog: Boolean = false, + + /** + * Enable/disable error-only logging + * + * It will disable all log channels except the error channel + */ var errorOnlyLog: Boolean = false, + + /** + * Maximum log size in KBs. + * + * Increasing it much will cause Binder issues for now + */ var maxLogSize: Int = 512, + + /** + * Enable/disable target SDK 30+ restrictions for all apps + */ var forceMountData: Boolean = true, + + /** + * Enable/disable the activity launch protection + * + * The activity launch protection basically blocks starting + * applications when they are hidden from target app, and reduces detections + */ var disableActivityLaunchProtection: Boolean = false, + + /** + * Enable/disable alternative (propless) appdata isolation + */ var altAppDataIsolation: Boolean = false, + + /** + * Enable/disable alternative (propless) vold appdata isolation + * + * Use it carefully that some of Android editions are still leaking + * vold existence even while not using props + */ var altVoldAppDataIsolation: Boolean = false, + + /** + * Skip vold appdata isolation enforcements for system apps + * + * This will help you to reduce bootloop issues caused by vold appdata isolation + */ var skipSystemAppDataIsolation: Boolean = true, + + /** + * Use alternative path to query packages + * + * This option is useful for querying packages from other profiles, + * or bypassing some of Chinese OEM ROM (MIUI, HyperOS, ...) restrictions + * while trying to get package lists in the manager app + */ var packageQueryWorkaround: Boolean = false, + + /** + * Enable/disable the Internet connection in the manager app + * + * States: + * - ENABLE_INTERNET_UNKNOWN - The user didn't pass the dialog yet + * - ENABLE_INTERNET_ON - The user granted the Internet permission + * - ENABLE_INTERNET_OFF - The user rejected the Internet permission + */ var enableInternet: Int = ENABLE_INTERNET_UNKNOWN, + val templates: MutableMap = mutableMapOf(), val settingsTemplates: MutableMap = mutableMapOf(), + + /** + * A list of disabled hooks, checked while the module is loading + */ val disabledHooks: MutableList = mutableListOf(), + + /** + * A package name and config pair to keep per-app configs + */ val scope: MutableMap = mutableMapOf() ) { @Serializable data class Template( + /** + * Is it a blacklist or whitelist template? + */ val isWhitelist: Boolean, + + /** + * Apps inside of this application template + */ val appList: Set ) { override fun toString() = encoder.encodeToString(this) } @Serializable + /** + * A type of template that holds settings replacements/overrides + * + * Also used for override the settings presets + */ data class SettingsTemplate( + /** + * Setting replacements inside of this settings template + */ val settingsList: Set ) { override fun toString() = encoder.encodeToString(this) @@ -41,19 +126,88 @@ data class JsonConfig( @Serializable data class AppConfig( + /** + * Is it a blacklist or whitelist configuration? + */ var useWhitelist: Boolean = false, + + /** + * Exclude/include system apps for whitelist mode + */ var excludeSystemApps: Boolean = true, + + /** + * Hide all user apps' installation sources + */ var hideInstallationSource: Boolean = false, + + /** + * Hide all system apps' installation sources + */ var hideSystemInstallationSource: Boolean = false, + + /** + * Exclude the target app from installation source replacements + */ var excludeTargetInstallationSource: Boolean = false, + + /** + * Invert the currently active activity protection mode for this application + * + * How this option works: + * - If it was enabled globally, then it will be disabled for this application + * - If it was disabled globally, then it will be enabled for this application + */ var invertActivityLaunchProtection: Boolean = false, + + /** + * Exclude this app from appdata isolation + * + * This option is only useful when you don't need vold appdata isolation + * for the target app or the app assumes the vold isolation as a detection point + */ var excludeVoldIsolation: Boolean = false, + + /** + * A list of removed Zygote permissions while the app was launching + */ var restrictedZygotePermissions: List = listOf(), + + /** + * A list of applied application templates, it has to contain items + * from the global application template list + */ var applyTemplates: MutableSet = mutableSetOf(), + + /** + * A list of applied application presets, it has to contain items + * from the global application preset list + */ var applyPresets: MutableSet = mutableSetOf(), + + /** + * A list of applied settings templates, it has to contain items + * from the global settings template list + */ var applySettingTemplates: MutableSet = mutableSetOf(), + + /** + * A list of applied settings presets, it has to contain items + * from the global settings preset list + */ var applySettingsPresets: MutableSet = mutableSetOf(), + + /** + * Extra hidden/unhidden apps list, depends on `useWhitelist` + */ var extraAppList: MutableSet = mutableSetOf(), + + /** + * Extra hidden/unhidden apps list in opposite way, depends on `useWhitelist` + * + * - A list of extra hidden apps on whitelist mode + * - A list of extra unhidden apps on blacklist mode + */ var extraOppositeAppList: MutableSet = mutableSetOf(), ) { override fun toString() = encoder.encodeToString(this) From 65598e684e91f27c3ece624603d4859ccf032777 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 2 Apr 2026 11:40:43 +0300 Subject: [PATCH 086/162] Try to fix parameter count checker --- .../java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index 371035e4f..c4dd466f5 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -141,7 +141,7 @@ class BulkHooker private constructor() { fun applyForClass(clazz: Class<*>?) { val executables = Reflection.getHiddenExecutables(clazz).filter { executable -> element.methodName == executable.name && - (element.paramCount in listOf(-1, executable.parameterCount - 1)) + (element.paramCount in listOf(-1, executable.parameterCount)) }.sortedWith { v1, v2 -> v1.parameterCount.compareTo(v2.parameterCount) } @@ -239,7 +239,7 @@ class BulkHooker private constructor() { fun findMethods(clazz: Class<*>): List { return Reflection.getHiddenExecutables(clazz).filter { executable -> executable.name in methodNames && - (paramCount in listOf(-1, executable.parameterCount - 1)) + (paramCount in listOf(-1, executable.parameterCount)) }.sortedWith { v1, v2 -> v1.parameterCount.compareTo(v2.parameterCount) } From 03aeb46977c50631749103bbb4e231491b37f7d1 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 2 Apr 2026 11:43:20 +0300 Subject: [PATCH 087/162] Add -1 parameter count as PARAMETER_COUNT_UNKNOWN --- .../frknkrc44/hma_oss/zygote/service/BulkHooker.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index c4dd466f5..c1f2b01f6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -21,6 +21,7 @@ import java.lang.reflect.Method class BulkHooker private constructor() { companion object { val instance: BulkHooker by lazy { BulkHooker() } + const val PARAMETER_COUNT_UNKNOWN = -1 } internal val hooks: MutableMap> = HashMap() @@ -55,7 +56,7 @@ class BulkHooker private constructor() { clazz: String, methodName: String, hookOnce: Boolean = true, - paramCount: Int = -1, + paramCount: Int = PARAMETER_COUNT_UNKNOWN, hook: (param: HookParam) -> Unit, ) { addHook(clazz, methodName, hookOnce, paramCount) { original, frame -> @@ -92,7 +93,7 @@ class BulkHooker private constructor() { clazz: String, methodName: String, hookOnce: Boolean = true, - paramCount: Int = -1, + paramCount: Int = PARAMETER_COUNT_UNKNOWN, hook: (param: HookParam) -> Unit, ) { addHook(clazz, methodName, hookOnce, paramCount) { original, frame -> @@ -141,7 +142,7 @@ class BulkHooker private constructor() { fun applyForClass(clazz: Class<*>?) { val executables = Reflection.getHiddenExecutables(clazz).filter { executable -> element.methodName == executable.name && - (element.paramCount in listOf(-1, executable.parameterCount)) + (element.paramCount in listOf(PARAMETER_COUNT_UNKNOWN, executable.parameterCount)) }.sortedWith { v1, v2 -> v1.parameterCount.compareTo(v2.parameterCount) } @@ -239,13 +240,13 @@ class BulkHooker private constructor() { fun findMethods(clazz: Class<*>): List { return Reflection.getHiddenExecutables(clazz).filter { executable -> executable.name in methodNames && - (paramCount in listOf(-1, executable.parameterCount)) + (paramCount in listOf(PARAMETER_COUNT_UNKNOWN, executable.parameterCount)) }.sortedWith { v1, v2 -> v1.parameterCount.compareTo(v2.parameterCount) } } - var methods: List = listOf() + var methods = listOf() while ( methods.isEmpty() && From e417f5320a264fc3db4e0996cd5bc2339d8543c9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 2 Apr 2026 12:42:34 +0300 Subject: [PATCH 088/162] Unify package hiding function --- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 84 +++-------- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 107 ++++---------- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 133 +++++------------- .../hma_oss/zygote/hook/PmsHookTarget33.kt | 38 ++--- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 65 +++------ .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 128 ++++++++--------- 6 files changed, 180 insertions(+), 375 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index e8a8cc62e..1208bc4fc 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -1,13 +1,10 @@ package org.frknkrc44.hma_oss.zygote.hook -import icu.nullptr.hidemyapplist.common.Constants import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { @@ -28,74 +25,39 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { "filterAppAccessLPr", paramCount = 5, ) { param -> - val callingUid = param.getArgument(2) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val packageSettings = param.getArgument(1) - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(packageSettings) - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@filterAppAccessLPr caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@filterAppAccessLPr query from $caller") - logD(TAG, "@filterAppAccessLPr caller: $callingUid $caller, target: $targetApp") - } + applyPackageHiding( + param.methodName, + { param.getArgument(2) as Int? }, + { getPackageNameFromPackageSettings(param.getArgument(1)) }, + { getCallingApps(service, it) }, + { param.result = true }, + ) } hookBefore( PACKAGE_MANAGER_SERVICE_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as? String? ?: return@hookBefore - val callingUid = param.getArgument(4) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.getArgument(4) as Int? }, + { param.getArgument(1) as String? }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( PACKAGE_MANAGER_SERVICE_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.getArgument(1) as? String? ?: return@hookBefore - val callingUid = param.getArgument(3) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.getArgument(1) as Int? }, + { param.getArgument(3) as String? }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 9de9b0453..754e236e6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -3,16 +3,13 @@ package org.frknkrc44.hma_oss.zygote.hook import android.os.Binder import android.os.Build import androidx.annotation.RequiresApi -import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS @@ -53,96 +50,52 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { PACKAGE_MANAGER_SERVICE_CLASS, "getPackageSetting", ) { param -> - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as String - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@getPackageSetting - PkgMgr cache: insecure query from $callingUid to $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@getPackageSetting - PkgMgr: insecure query from $caller to $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { Binder.getCallingUid() }, + { param.getArgument(1) as String? }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( APPS_FILTER_CLASS, "shouldFilterApplication", ) { param -> - val callingUid = param.getArgument(1) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(3)) - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") - logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") - } + applyPackageHiding( + param.methodName, + { param.getArgument(1) as Int }, + { getPackageNameFromPackageSettings(param.getArgument(3)) }, + { getCallingApps(service, it) }, + { param.result = true }, + ) } hookBefore( PACKAGE_MANAGER_SERVICE_CLASS, "getPackageInfoInternal", ) { param -> - val callingUid = param.getArgument(4) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as? String? ?: return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.getArgument(4) as? Int }, + { param.getArgument(1) as? String }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( PACKAGE_MANAGER_SERVICE_CLASS, "getApplicationInfoInternal", ) { param -> - val callingUid = param.getArgument(3) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as? String? ?: return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.getArgument(3) as? Int }, + { param.getArgument(1) as? String }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index fc34a81a1..b932ea3d7 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -3,16 +3,13 @@ package org.frknkrc44.hma_oss.zygote.hook import android.os.Binder import android.os.Build import androidx.annotation.RequiresApi -import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PMS_COMPUTER_TRACKER_CLASS @@ -53,121 +50,65 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { PMS_COMPUTER_TRACKER_CLASS, "getPackageSetting", ) { param -> - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as String - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@getPackageSetting - Computer cache: insecure query from $callingUid to $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@getPackageSetting - Computer: insecure query from $caller to $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { Binder.getCallingUid() }, + { param.getArgument(1) as String? }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( PMS_COMPUTER_TRACKER_CLASS, "getPackageSettingInternal", ) { param -> - val callingUid = param.getArgument(2) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as String - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@getPackageSettingInternal - Computer cache: insecure query from $callingUid to $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@getPackageSettingInternal - Computer: insecure query from $caller to $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.getArgument(2) as Int? }, + { param.getArgument(1) as String? }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( PMS_COMPUTER_TRACKER_CLASS, "getPackageInfoInternal", ) { param -> - val callingUid = param.getArgument(4) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as? String? ?: return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.getArgument(4) as Int? }, + { param.getArgument(1) as String? }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( PMS_COMPUTER_TRACKER_CLASS, "getApplicationInfoInternal", ) { param -> - val callingUid = param.getArgument(3) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1) as? String? ?: return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.getArgument(3) as Int? }, + { param.getArgument(1) as String? }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( APPS_FILTER_CLASS, "shouldFilterApplication", ) { param -> - logV(TAG, "@shouldFilterApplication call: ${param.args.contentToString()}") - - val callingUid = param.getArgument(1) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(3)) - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") - logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") - } + applyPackageHiding( + param.methodName, + { param.getArgument(1) as Int? }, + { getPackageNameFromPackageSettings(param.getArgument(3)) }, + { getCallingApps(service, it) }, + { param.result = true }, + ) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index 428def99f..f04f12830 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -3,17 +3,14 @@ package org.frknkrc44.hma_oss.zygote.hook import android.content.pm.PackageInstaller import android.os.Build import androidx.annotation.RequiresApi -import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS @RequiresApi(Build.VERSION_CODES.TIRAMISU) @@ -66,28 +63,17 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { APPS_FILTER_IMPL_CLASS, "shouldFilterApplication", ) { param -> - val callingUid = param.getArgument(2) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(4)) // PackageSettings <- PackageStateInternal - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val snapshot = param.getArgument(1) - val callingApps = Utils.binderLocalScope { - getPackagesForUidMethod.invoke(snapshot, callingUid) as Array? - } ?: return@hookBefore - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") - logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") - } + applyPackageHiding( + param.methodName, + { param.getArgument(2) as Int? }, + { getPackageNameFromPackageSettings(param.getArgument(4)) }, + { + Utils.binderLocalScope { + getPackagesForUidMethod.invoke(param.getArgument(1), it) as Array + } + }, + { param.result = true }, + ) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 40eb2daf0..026f36f93 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -4,17 +4,15 @@ import android.content.pm.PackageInstaller import android.os.Binder import android.os.Build import androidx.annotation.RequiresApi -import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS @@ -70,28 +68,17 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { APPS_FILTER_IMPL_CLASS, "shouldFilterApplication", ) { param -> - val callingUid = param.getArgument(2) as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = Utils4Zygote.getPackageNameFromPackageSettings(param.getArgument(4)) // PackageSettings <- PackageStateInternal - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = true - service.increasePMFilterCount(callingUid) - logD(TAG, "@shouldFilterApplication caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val snapshot = param.getArgument(1) - val callingApps = Utils.binderLocalScope { - getPackagesForUidMethod.invoke(snapshot, callingUid) as Array? - } ?: return@hookBefore - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = true - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp!!) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller") - logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp") - } + applyPackageHiding( + param.methodName, + { param.getArgument(2) as Int? }, + { getPackageNameFromPackageSettings(param.getArgument(4)) }, + { + Utils.binderLocalScope { + getPackagesForUidMethod.invoke(param.getArgument(1), it) as Array + } + }, + { param.result = true }, + ) } // AOSP exploit - https://github.com/aosp-mirror/platform_frameworks_base/commit/5bc482bd99ea18fe0b4064d486b29d5ae2d65139 @@ -106,25 +93,13 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { altNames.declaringClass.name, altNames.name, ) { param -> - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val targetApp = param.getArgument(1).toString() - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@getArchivedPackageInternal caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@getArchivedPackageInternal: query from $caller") - logD(TAG, "@getArchivedPackageInternal caller: $callingUid $caller, target: $targetApp") - } + applyPackageHiding( + param.methodName, + { Binder.getCallingUid() }, + { param.getArgument(1).toString() }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 68b05d476..505879e6c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -13,6 +13,7 @@ import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache import org.frknkrc44.hma_oss.zygote.util.Logcat.logD +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callMethod import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps @@ -82,23 +83,13 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "generatePackageInfo", ) { param -> - val callingUid = Binder.getCallingUid() - val packageSettings = param.getArgument(1) - val targetApp = getPackageNameFromPackageSettings(packageSettings) ?: return@hookBefore - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@generatePackageInfo caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@generatePackageInfo caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { Binder.getCallingUid() }, + { getPackageNameFromPackageSettings(param.getArgument(1)) }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } } @@ -108,23 +99,13 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "addPackageHoldingPermissions", ) { param -> - val callingUid = Binder.getCallingUid() - val packageSettings = param.getArgument(2) - val targetApp = getPackageNameFromPackageSettings(packageSettings) ?: return@hookBefore - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@addPackageHoldingPermissions caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@addPackageHoldingPermissions caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { Binder.getCallingUid() }, + { getPackageNameFromPackageSettings(param.getArgument(2)) }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( @@ -162,48 +143,26 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "getPackageInfoInternal", ) { param -> - val targetApp = param.args.firstOrNull { it is String } as? String ?: return@hookBefore - val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.args.firstOrNull { it is Int } as? Int }, + { param.args.firstOrNull { it is String } as? String }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } hookBefore( COMPUTER_ENGINE_CLASS, "getApplicationInfoInternal", ) { param -> - val targetApp = param.args.firstOrNull { it is String } as? String ?: return@hookBefore - val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - logV(TAG, "@${param.methodName} incoming query: $callingUid => $targetApp") - if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { - param.result = null - service.increasePMFilterCount(callingUid) - logD(TAG, "@${param.methodName} caller cache: $callingUid, target: $targetApp") - return@hookBefore - } - val callingApps = getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG, "@${param.methodName} caller: $callingUid $caller, target: $targetApp") - param.result = null - HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } + applyPackageHiding( + param.methodName, + { param.args.firstOrNull { it is Int } as? Int }, + { param.args.firstOrNull { it is String } as? String }, + { getCallingApps(service, it) }, + { param.result = null }, + ) } } @@ -284,4 +243,33 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework } } } + + fun applyPackageHiding( + methodName: String, + findCallingUid: () -> Int?, + findTargetApp: () -> String?, + findCallingApps: (Int) -> Array, + applyReturnValue: () -> Unit, + ) { + val callingUid = findCallingUid() + if (callingUid == null || callingUid == Constants.UID_SYSTEM) return + val targetApp = findTargetApp() ?: return + logV(TAG, "@$methodName incoming query: $callingUid => $targetApp") + if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { + applyReturnValue() + service.increasePMFilterCount(callingUid) + logD(TAG, "@$methodName caller cache: $callingUid, target: $targetApp") + return + } + val callingApps = findCallingApps(callingUid) + val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + if (caller != null) { + logD(TAG, "@$methodName caller: $callingUid $caller, target: $targetApp") + applyReturnValue() + val last = lastFilteredApp.getAndSet(caller) + if (last != caller) logI(TAG, "@${methodName}: query from $caller") + HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) + service.increasePMFilterCount(caller) + } + } } From bb7f1bf4b834df9454fd2656417e769e9f9fc90f Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 2 Apr 2026 13:38:09 +0300 Subject: [PATCH 089/162] Prevent HMA-OSS selected as target app --- .../nullptr/hidemyapplist/ui/adapter/AppManageAdapter.kt | 2 +- .../nullptr/hidemyapplist/ui/adapter/AppScopeAdapter.kt | 3 ++- .../nullptr/hidemyapplist/ui/adapter/AppSelectAdapter.kt | 7 +++---- .../icu/nullptr/hidemyapplist/ui/fragment/ScopeFragment.kt | 6 ++++-- .../hidemyapplist/ui/fragment/TemplateSettingsFragment.kt | 3 ++- .../org/frknkrc44/hma_oss/ui/adapter/AppPresetAdapter.kt | 2 +- .../frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt | 6 ++++-- app/src/main/res/navigation/home_nav_graph.xml | 5 +++++ 8 files changed, 22 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppManageAdapter.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppManageAdapter.kt index a472aefc0..21d157f92 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppManageAdapter.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppManageAdapter.kt @@ -10,7 +10,7 @@ import org.frknkrc44.hma_oss.R class AppManageAdapter( private val onItemClickListener: (String) -> Unit -) : AppSelectAdapter() { +) : AppSelectAdapter(true) { inner class ViewHolder(view: AppItemView) : AppSelectAdapter.ViewHolder(view) { init { diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppScopeAdapter.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppScopeAdapter.kt index 5e1facfeb..c5b5c5335 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppScopeAdapter.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppScopeAdapter.kt @@ -5,8 +5,9 @@ import icu.nullptr.hidemyapplist.ui.view.AppItemView class AppScopeAdapter( private val checked: MutableSet, + hideMyself: Boolean, firstFilter: ((String) -> Boolean)?, -) : AppSelectAdapter(firstFilter) { +) : AppSelectAdapter(hideMyself, firstFilter) { private inline var String.isChecked get() = checked.contains(this) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppSelectAdapter.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppSelectAdapter.kt index ba54f0517..cae708181 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppSelectAdapter.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/adapter/AppSelectAdapter.kt @@ -11,7 +11,8 @@ import kotlinx.coroutines.runBlocking import org.frknkrc44.hma_oss.BuildConfig abstract class AppSelectAdapter( - private val firstFilter: ((String) -> Boolean)? = null + private val hideMyself: Boolean, + private val firstFilter: ((String) -> Boolean)? = null, ) : RecyclerView.Adapter(), Filterable { abstract class ViewHolder(view: AppItemView) : RecyclerView.ViewHolder(view) { @@ -25,9 +26,7 @@ abstract class AppSelectAdapter( val filteredList = PackageHelper.appList.first().filter { if (firstFilter?.invoke(it) == false) return@filter false if (!PrefManager.appFilter_showSystem && PackageHelper.isSystem(it)) return@filter false - if (it == BuildConfig.APPLICATION_ID && - (this@AppSelectAdapter.javaClass == AppManageAdapter::class.java || - (this@AppSelectAdapter.javaClass == AppScopeAdapter::class.java && firstFilter != null))) return@filter false + if (it == BuildConfig.APPLICATION_ID && hideMyself) return@filter false val label = PackageHelper.loadAppLabel(it) label.lowercase().contains(constraintLowered) || it.lowercase().contains(constraintLowered) } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/ScopeFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/ScopeFragment.kt index 57afce9a8..193af5f07 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/ScopeFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/ScopeFragment.kt @@ -21,8 +21,10 @@ class ScopeFragment : AppSelectFragment() { override val adapter by lazy { val args by navArgs() checked = args.checked.toMutableSet() - if (!args.filterOnlyEnabled) AppScopeAdapter(checked, null) - else AppScopeAdapter(checked) { ConfigManager.getAppConfig(it)?.useWhitelist == args.isWhiteList } + if (!args.filterOnlyEnabled) AppScopeAdapter(checked, args.hideMyself, null) + else AppScopeAdapter(checked, args.hideMyself) { + ConfigManager.getAppConfig(it)?.useWhitelist == args.isWhiteList + } } override fun onBack() { diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/TemplateSettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/TemplateSettingsFragment.kt index ca62f1ff8..0eeb8e5be 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/TemplateSettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/TemplateSettingsFragment.kt @@ -79,7 +79,8 @@ class TemplateSettingsFragment : Fragment(R.layout.fragment_template_settings) { } val args = ScopeFragmentArgs( filterOnlyEnabled = false, - checked = viewModel.targetAppList.value.toTypedArray() + checked = viewModel.targetAppList.value.toTypedArray(), + hideMyself = false, ) navigate(R.id.nav_scope, args.toBundle()) } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/AppPresetAdapter.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/AppPresetAdapter.kt index 6185b3b81..e33456bce 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/AppPresetAdapter.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/AppPresetAdapter.kt @@ -10,7 +10,7 @@ import kotlinx.coroutines.runBlocking class AppPresetAdapter( private val presetName: String -) : AppSelectAdapter() { +) : AppSelectAdapter(hideMyself = false) { var packages = mutableListOf() fun updateList() { diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt index e044e8d80..48cc0443d 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt @@ -534,7 +534,8 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { val args = ScopeFragmentArgs( filterOnlyEnabled = false, - checked = pack.config.extraAppList.toTypedArray() + checked = pack.config.extraAppList.toTypedArray(), + hideMyself = false, ) navigate(R.id.nav_scope, args.toBundle()) true @@ -549,7 +550,8 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { val args = ScopeFragmentArgs( filterOnlyEnabled = false, isOpposite = true, - checked = pack.config.extraOppositeAppList.toTypedArray() + checked = pack.config.extraOppositeAppList.toTypedArray(), + hideMyself = false, ) navigate(R.id.nav_scope, args.toBundle()) true diff --git a/app/src/main/res/navigation/home_nav_graph.xml b/app/src/main/res/navigation/home_nav_graph.xml index d1c83c893..4c37135de 100644 --- a/app/src/main/res/navigation/home_nav_graph.xml +++ b/app/src/main/res/navigation/home_nav_graph.xml @@ -183,6 +183,11 @@ android:name="filterOnlyEnabled" app:argType="boolean" /> + + Date: Thu, 2 Apr 2026 21:45:06 +0300 Subject: [PATCH 090/162] Accept null array for calling apps --- .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt | 2 +- .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt | 2 +- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index f04f12830..c65be41ad 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -69,7 +69,7 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { { getPackageNameFromPackageSettings(param.getArgument(4)) }, { Utils.binderLocalScope { - getPackagesForUidMethod.invoke(param.getArgument(1), it) as Array + getPackagesForUidMethod.invoke(param.getArgument(1), it) as Array? } }, { param.result = true }, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 026f36f93..9f001a765 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -74,7 +74,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { { getPackageNameFromPackageSettings(param.getArgument(4)) }, { Utils.binderLocalScope { - getPackagesForUidMethod.invoke(param.getArgument(1), it) as Array + getPackagesForUidMethod.invoke(param.getArgument(1), it) as Array? } }, { param.result = true }, diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 505879e6c..5f83457ee 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -248,7 +248,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework methodName: String, findCallingUid: () -> Int?, findTargetApp: () -> String?, - findCallingApps: (Int) -> Array, + findCallingApps: (Int) -> Array?, applyReturnValue: () -> Unit, ) { val callingUid = findCallingUid() @@ -262,7 +262,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework return } val callingApps = findCallingApps(callingUid) - val caller = callingApps.firstOrNull { service.shouldHide(it, targetApp) } + val caller = callingApps?.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { logD(TAG, "@$methodName caller: $callingUid $caller, target: $targetApp") applyReturnValue() From e5f3c40c0b8167502afb338028d7ff6ef5f99373 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 2 Apr 2026 22:06:44 +0300 Subject: [PATCH 091/162] Fix argument indexes for SDK29 --- .../java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index 1208bc4fc..0f9685915 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -53,8 +53,8 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { ) { param -> applyPackageHiding( param.methodName, - { param.getArgument(1) as Int? }, - { param.getArgument(3) as String? }, + { param.getArgument(3) as Int? }, + { param.getArgument(1) as String? }, { getCallingApps(service, it) }, { param.result = null }, ) From c7b0542c93b09c21bdba07291cd86e4bfcafe7c4 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 2 Apr 2026 22:20:06 +0300 Subject: [PATCH 092/162] Ignore if packageSettings returns null --- .../java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index 40a07645f..db11035aa 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -98,7 +98,9 @@ object Utils4Zygote { return service } - fun getPackageNameFromPackageSettings(packageSettings: Any): String? { + fun getPackageNameFromPackageSettings(packageSettings: Any?): String? { + if (packageSettings == null) return null + return try { callMethod(packageSettings, "getPackageName") as String? } catch (_: Throwable) { From e0ad056d1b317876f823460614b3a17a762b33b7 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 4 Apr 2026 14:58:13 +0300 Subject: [PATCH 093/162] upgrade androidvmtools and panamaport --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 279f697c0..24aba7ec9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,8 +6,8 @@ material = "1.13.0" hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" -r8_annotations = "v1.0.0" -androidvmtools = "33b8aa9" +r8_annotations = "v1.0.1" +androidvmtools = "e7e8de1" zygoteloader = "bf5078e182" [plugins] From c0a6a869e3c1ed60aea2f465c7d4727ed6d38214 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 10 Apr 2026 21:22:58 +0300 Subject: [PATCH 094/162] Fix a specific system crash --- .../org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index c1f2b01f6..fa0b3b1c9 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -46,7 +46,11 @@ class BulkHooker private constructor() { ) if (applyHook(clazz, element)) { - hooks.computeIfAbsent(clazz) { _ -> mutableListOf() }.add(element) + if (clazz !in hooks) { + hooks[clazz] = mutableListOf() + } + + hooks[clazz]!!.add(element) } else { logI(ZygoteEntry.TAG, "Invalid hook removed: $clazz -> $methodName($paramCount)") } @@ -149,14 +153,14 @@ class BulkHooker private constructor() { for (executable in executables) { if (!element.hookFinished) { - logD(ZygoteEntry.TAG, "Hooked: $executable") + // logD(ZygoteEntry.TAG, "Hooked: $executable") val memoryAddresses = Hooks.hook( executable, Hooks.EntryPointType.DIRECT, element.impl, Hooks.EntryPointType.DIRECT ) - logV(ZygoteEntry.TAG, "Memory address map: $memoryAddresses") + // logV(ZygoteEntry.TAG, "Memory address map: $memoryAddresses") if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { element.memoryAddresses = memoryAddresses From bf42621a4557e3f5f48d0ef821cf656c0b25a77a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 14 Apr 2026 13:13:11 +0300 Subject: [PATCH 095/162] Convert log* message to lambda function --- .../receiver/AppChangeReceiver.kt | 3 +- .../hidemyapplist/service/ConfigManager.kt | 8 +-- .../hidemyapplist/service/ServiceClient.kt | 4 +- .../frknkrc44/hma_oss/zygote/ZygoteEntry.java | 10 ++-- .../hma_oss/zygote/hook/AccessibilityHook.kt | 4 +- .../hma_oss/zygote/hook/ActivityHook.kt | 12 ++--- .../zygote/hook/AppDataIsolationHook.kt | 18 +++---- .../zygote/hook/ContentProviderHook.kt | 18 +++---- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 26 +++++----- .../hma_oss/zygote/hook/PlatformCompatHook.kt | 8 +-- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget33.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 12 ++--- .../zygote/hook/PmsPackageEventsHook.kt | 2 +- .../hma_oss/zygote/hook/ZygoteHook.kt | 4 +- .../hma_oss/zygote/service/BulkHooker.kt | 22 ++++---- .../hma_oss/zygote/service/HMAService.kt | 50 +++++++++---------- .../zygote/service/SystemServerHook.kt | 10 ++-- .../hma_oss/zygote/service/UserService.kt | 18 +++---- .../frknkrc44/hma_oss/zygote/util/Logcat.kt | 21 ++++---- .../hma_oss/zygote/util/Utils4Zygote.kt | 2 +- 24 files changed, 132 insertions(+), 130 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/receiver/AppChangeReceiver.kt b/app/src/main/java/icu/nullptr/hidemyapplist/receiver/AppChangeReceiver.kt index 57c5dbe24..29902499c 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/receiver/AppChangeReceiver.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/receiver/AppChangeReceiver.kt @@ -5,6 +5,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.util.Log +import icu.nullptr.hidemyapplist.service.ServiceClient import icu.nullptr.hidemyapplist.util.PackageHelper class AppChangeReceiver : BroadcastReceiver() { @@ -29,7 +30,7 @@ class AppChangeReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action in actions) { - Log.i(TAG, "Received intent: $intent") + ServiceClient.log(Log.INFO, TAG, "Received intent: $intent") PackageHelper.invalidateCache() // ServiceClient.handlePackageEvent(intent.action, intent.data?.encodedSchemeSpecificPart) } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index d56aeb335..80cc23108 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -212,13 +212,13 @@ object ConfigManager { } fun updateTemplate(name: String, template: JsonConfig.Template) { - Log.d(TAG, "updateTemplate: $name list = ${template.appList}") + ServiceClient.log(Log.DEBUG, TAG, "updateTemplate: $name list = ${template.appList}") config.templates[name] = template saveConfig() } fun updateTemplateAppliedApps(name: String, appliedList: List) { - Log.d(TAG, "updateTemplateAppliedApps: $name list = $appliedList") + ServiceClient.log(Log.DEBUG, TAG, "updateTemplateAppliedApps: $name list = $appliedList") config.scope.forEach { (app, appInfo) -> if (appliedList.contains(app)) appInfo.applyTemplates.add(name) else appInfo.applyTemplates.remove(name) @@ -262,13 +262,13 @@ object ConfigManager { } fun updateSettingTemplate(name: String, template: JsonConfig.SettingsTemplate) { - Log.d(TAG, "updateSettingTemplate: $name list = ${template.settingsList}") + ServiceClient.log(Log.DEBUG, TAG, "updateSettingTemplate: $name list = ${template.settingsList}") config.settingsTemplates[name] = template saveConfig() } fun updateSettingTemplateAppliedApps(name: String, appliedList: List) { - Log.d(TAG, "updateSettingTemplateAppliedApps: $name list = $appliedList") + ServiceClient.log(Log.DEBUG, TAG, "updateSettingTemplateAppliedApps: $name list = $appliedList") config.scope.forEach { (app, appInfo) -> if (appliedList.contains(app)) appInfo.applySettingTemplates.add(name) else appInfo.applySettingTemplates.remove(name) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt index 502021a0c..1d59c7077 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt @@ -15,8 +15,8 @@ object ServiceClient : IHMAService, IBinder.DeathRecipient { private class ServiceProxy(private val obj: IHMAService) : InvocationHandler { override fun invoke(proxy: Any?, method: Method, args: Array?): Any? { val result = method.invoke(obj, *args.orEmpty()) - if (result == null) Log.i(TAG, "Call service method ${method.name}") - else Log.i(TAG, "Call service method ${method.name} with result " + result.toString().take(20)) + if (result == null) Log.d(TAG, "Call service method ${method.name}") + else Log.d(TAG, "Call service method ${method.name} with result " + result.toString().take(20)) return result } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java index fff5d1213..64d880d0e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java @@ -1,7 +1,7 @@ package org.frknkrc44.hma_oss.zygote; -import static org.frknkrc44.hma_oss.zygote.util.Logcat.logE; -import static org.frknkrc44.hma_oss.zygote.util.Logcat.logI; +import static org.frknkrc44.hma_oss.zygote.util.Logcat.logELegacy; +import static org.frknkrc44.hma_oss.zygote.util.Logcat.logILegacy; import com.v7878.r8.annotations.DoNotObfuscate; import com.v7878.r8.annotations.DoNotObfuscateType; @@ -26,17 +26,17 @@ public static void premain() throws Throwable { @DoNotObfuscate @DoNotShrink public static void main() throws Throwable { - logI(TAG, "Injected into " + ZygoteLoader.getPackageName(), null); + logILegacy(TAG, "Injected into " + ZygoteLoader.getPackageName(), null); try { SystemServerHook.init(); } catch (Throwable th) { - logE(TAG, "An exception occurred while SystemServerHook init", th); + logELegacy(TAG, "An exception occurred while SystemServerHook init", th); // do not print "Done" if there is an issue return; } - logI(TAG, "Done", null); + logILegacy(TAG, "Done", null); } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 9edae2ed9..35a892ca4 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -54,7 +54,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { if (caller != null) { val returnedList = java.util.ArrayList() - logD(TAG, "@${param.methodName} returned empty list for ${callingApps.contentToString()}") + logD(TAG, { "@${param.methodName} returned empty list for ${callingApps.contentToString()}" }) val returnParcel = param.frame.type().returnType().simpleName.contains("Parcel") param.result = if (returnParcel) { @@ -66,7 +66,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { // service.increasePMFilterCount(caller) } } catch (e: Throwable) { - logE(TAG, "Fatal error occurred, ignore hooks", e) + logE(TAG, { "Fatal error occurred, ignore hooks" }, e) } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index fe89814bf..ea4060ab9 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -33,7 +33,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { } override fun load() { - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { hookBefore( @@ -48,7 +48,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { if (service.shouldHideActivityLaunch(caller, targetApp)) { logD( TAG, - "@executeRequest: insecure query from $caller, target: ${intent?.component}" + { "@executeRequest: insecure query from $caller, target: ${intent?.component}" } ) param.result = fakeReturnCode service.increaseALFilterCount(caller) @@ -63,7 +63,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { }, "checkStartAnyActivityPermission", ) { param -> - logV(TAG, "${param.methodName}: ${param.args.contentToString()}") + logV(TAG, { "${param.methodName}: ${param.args.contentToString()}" }) // just an empty hook that does nothing } @@ -87,16 +87,16 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { val callingApps = Utils4Zygote.getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller != null) { - logV(TAG, "@${param.methodName}: $caller requested a resolve info") + logV(TAG, { "@${param.methodName}: $caller requested a resolve info" }) val filteredList = list.filter { resolveInfo -> val targetApp = Utils.getPackageNameFromResolveInfo(resolveInfo) - logV(TAG, "@${param.methodName}: Checking $targetApp for $caller") + logV(TAG, { "@${param.methodName}: Checking $targetApp for $caller" }) (!service.shouldHideActivityLaunch(caller, targetApp)).apply { if (!this) { - logD(TAG, "@${param.methodName}: Filtered $targetApp from $caller") + logD(TAG, { "@${param.methodName}: Filtered $targetApp from $caller" }) } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index d1c5d758d..d6262d883 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -32,7 +32,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { override fun load() { if (!(service.config.altAppDataIsolation || service.config.altVoldAppDataIsolation)) return - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { hookBefore( @@ -52,7 +52,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { true ) - logI(TAG, "ProcessList - App data isolation is forced") + logI(TAG, { "ProcessList - App data isolation is forced" }) } } @@ -61,7 +61,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { if (!fuseEnabled) { voldHookSkipped = true - logE(TAG, "ProcessList - FUSE storage is not enabled, skip vold hook") + logE(TAG, { "ProcessList - FUSE storage is not enabled, skip vold hook" }) } else { val isolationEnabled = getBooleanField( param.thisObject, @@ -75,7 +75,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { true ) - logI(TAG, "ProcessList - Vold app data isolation is forced") + logI(TAG, { "ProcessList - Vold app data isolation is forced" }) } } } @@ -105,7 +105,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { logD( TAG, - "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" + { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" } ) // Do not isolate this module for safety @@ -122,7 +122,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { val isSystemApp = service.systemApps.any { apps.contains(it) } logD( TAG, - "@needsStorageDataIsolation $uid and ${apps.contentToString()} - isSystemApp: $isSystemApp" + { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - isSystemApp: $isSystemApp" } ) if (isSystemApp) { @@ -141,7 +141,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) if (!fuseEnabled) { - logE(TAG, "StorageManagerService - FUSE storage is not enabled, skip vold hook") + logE(TAG, { "StorageManagerService - FUSE storage is not enabled, skip vold hook" }) voldHookSkipped = true return@hookBefore } @@ -158,7 +158,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { true ) - logI(TAG, "StorageManagerService - Vold app data isolation is forced") + logI(TAG, { "StorageManagerService - Vold app data isolation is forced" }) } } } @@ -179,7 +179,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { if (packageName in service.systemApps || packageName == BuildConfig.APP_PACKAGE_NAME) { logD( TAG, - "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" + { "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" } ) keysToRemove += pid break diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 107a8bf89..1ae6cc54c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -43,18 +43,18 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val segments = uri.pathSegments if (segments.isEmpty()) return@hookAfter - logD(TAG, "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args") + logD(TAG, { "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args" }) val database = segments[0] if (segments.size >= 2) { val name = segments[1] - logD(TAG, "@spoofSettings QUERY received caller: $caller, database: $database, name: $name") + logD(TAG, { "@spoofSettings QUERY received caller: $caller, database: $database, name: $name" }) val replacement = service.getSpoofedSetting(caller, name, database) if (replacement != null) { - logD(TAG, "@spoofSettings QUERY $name in $database replaced for $caller") + logD(TAG, { "@spoofSettings QUERY $name in $database replaced for $caller" }) param.result = MatrixCursor(arrayOf("name", "value"), 1).apply { addRow(arrayOf(replacement.name, replacement.value)) } @@ -62,7 +62,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { service.increaseSettingsFilterCount(caller) } } else { - logD(TAG, "@spoofSettings LIST_QUERY received caller: $caller, database: $database") + logD(TAG, { "@spoofSettings LIST_QUERY received caller: $caller, database: $database" }) val result = param.result as? Cursor? ?: return@hookAfter @@ -72,13 +72,13 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { } } - logD(TAG, "@spoofSetting LIST_QUERY columns: ${columns.keys}") + logD(TAG, { "@spoofSetting LIST_QUERY columns: ${columns.keys}" }) val keyColumn = columns["name"] val valueColumn = columns["value"] if (keyColumn == null || valueColumn == null) { - logD(TAG, "@spoofSettings LIST_QUERY invalid query: $caller ($keyColumn, $valueColumn)") + logD(TAG, { "@spoofSettings LIST_QUERY invalid query: $caller ($keyColumn, $valueColumn)" }) return@hookAfter } @@ -88,7 +88,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val replacement = service.getSpoofedSetting(caller, name, database) val value = if (replacement != null) { - logD(TAG, "@spoofSettings QUERY $name in $database replaced for $caller") + logD(TAG, { "@spoofSettings QUERY $name in $database replaced for $caller" }) service.increaseSettingsFilterCount(caller) @@ -135,14 +135,14 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val name = param.args[nameIdx] as String? val method = param.args[nameIdx - 1] as String? - logD(TAG, "@spoofSettings CALL received caller: ${callingApps.contentToString()}, method: $method, name: $name") + logD(TAG, { "@spoofSettings CALL received caller: ${callingApps.contentToString()}, method: $method, name: $name" }) when (method) { "GET_global", "GET_secure", "GET_system" -> { val database = method.substring(method.indexOf('_') + 1) val replacement = service.getSpoofedSetting(caller, name, database) if (replacement != null) { - logD(TAG, "@spoofSettings CALL $name in $database replaced for $caller") + logD(TAG, { "@spoofSettings CALL $name in $database replaced for $caller" }) param.result = Bundle().apply { putString(Settings.NameValueTable.VALUE, replacement.value) putInt("_generation_index", -1) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 4c7fb5c13..55f722b76 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -36,7 +36,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { if (defaultInputMethod?.value != null) { try { val component = ComponentName.unflattenFromString(defaultInputMethod.value!!)!! - logD(TAG, "Package component: \"$component\"") + logD(TAG, { "Package component: \"$component\"" }) val pkgManager = Utils4Zygote.getPackageManager() val kbdPackage = Utils.binderLocalScope { @@ -50,7 +50,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { null, ) } catch (e: Throwable) { - logV(TAG, e.message ?: "", e) + logV(TAG, { e.message ?: "" }, e) } } @@ -80,7 +80,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, "@${param.methodName} spoofed input method for $caller") + logD(TAG, { "@${param.methodName} spoofed input method for $caller" }) val fakeIMInfo = getFakeInputMethodInfo(caller) val userHandle = param.getArgument(1) as Int @@ -103,10 +103,10 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { method.declaringClass.name, method.name, ) { param -> - logD(TAG, "@${param.methodName}: hook init") + logD(TAG, { "@${param.methodName}: hook init" }) val currentResult = param.result ?: return@hookAfter - logD(TAG, "@${param.methodName}: Result: $currentResult Args: ${param.args.contentToString()}") + logD(TAG, { "@${param.methodName}: Result: $currentResult Args: ${param.args.contentToString()}" }) val callingUid = if (param.args.count { it is Int } > 2) { param.args.lastOrNull { it is Int && it > 999 } as? Int ?: return@hookAfter @@ -114,7 +114,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { Binder.getCallingUid() } - logD(TAG, "@${param.methodName}: Caller ID: $callingUid") + logD(TAG, { "@${param.methodName}: Caller ID: $callingUid" }) val returnType = param.frame.type().returnType() if (returnType.simpleName == "InputMethodInfoSafeList") { @@ -149,7 +149,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, "@${param.methodName}: spoofed input method for $caller") + logD(TAG, { "@${param.methodName}: spoofed input method for $caller" }) val fakeIMInfo = getFakeInputMethodInfo(caller) if (!isIMExists(fakeIMInfo.packageName)) { @@ -214,7 +214,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}") + logD(TAG, { "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}" }) // TODO: Find a method to get exact value for spoofed input method param.result = null @@ -227,7 +227,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}") + logD(TAG, { "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}" }) // TODO: Find a method to get exact list for spoofed input method Collections.emptyList().let { list -> @@ -245,18 +245,18 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } fun calculateReturnedInputMethodList(callingUid: Int, inList: List): List { - logV(TAG, "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}") + logV(TAG, { "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}" }) val caller = Utils4Zygote.getCallingApps(service, callingUid) .firstOrNull { callerIsSpoofed(it) } ?: return inList - logD(TAG, "@getInputMethodList: spoofed input method for $caller") + logD(TAG, { "@getInputMethodList: spoofed input method for $caller" }) val calculatedList = inList.filter { imInfo -> !service.shouldHide(caller, imInfo.packageName) } - logV(TAG, "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}") + logV(TAG, { "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}" }) val fakeIMInfo = getFakeInputMethodInfo(caller) @@ -281,7 +281,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { - logW(TAG, "@$methodName: PROBABLY spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections. Do not care this message if you are sure the keyboard is installed correctly.") + logW(TAG, { "@$methodName: PROBABLY spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections. Do not care this message if you are sure the keyboard is installed correctly." }) } private fun callerIsSpoofed(caller: String) = diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index e139b3909..ae3044cdc 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -22,8 +22,8 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { override fun load() { if (!service.config.forceMountData) return - logI(TAG, "Load hook") - logI(TAG, "App data isolation enabled: $sAppDataIsolationEnabled") + logI(TAG, { "Load hook" }) + logI(TAG, { "App data isolation enabled: $sAppDataIsolationEnabled" }) BulkHooker.instance.hookBefore( PLATFORM_COMPAT_CLASS, @@ -40,10 +40,10 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { if (app == BuildConfig.APP_PACKAGE_NAME || app in service.systemApps) return@hookBefore if (service.isHookEnabled(app)) { param.result = true - logD(TAG, "force mount data: ${appInfo.uid} $app") + logD(TAG, { "force mount data: ${appInfo.uid} $app" }) } }.onFailure { - logE(TAG, "Fatal error occurred, disable hooks", it) + logE(TAG, { "Fatal error occurred, disable hooks" }, it) } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index 0f9685915..5e7bb153d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -17,7 +17,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 754e236e6..1531df7a1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -43,7 +43,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { } override fun load() { - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index b932ea3d7..f019e7760 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -43,7 +43,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { } override fun load() { - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index c65be41ad..addaae5d2 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -56,7 +56,7 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 9f001a765..53c90f67c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -61,7 +61,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 5f83457ee..28cdb8b10 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -54,7 +54,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingApps = getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller != null) { - logD(TAG, "@getPackageStates: incoming query from $caller") + logD(TAG, { "@getPackageStates: incoming query from $caller" }) val result = param.result as ArrayMap<*, *> val markedToRemove = mutableListOf() @@ -70,7 +70,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (markedToRemove.isNotEmpty()) { val copyResult = ArrayMap(result) copyResult.removeAll(markedToRemove) - logD(TAG, "@getPackageStates: removed ${markedToRemove.size} entries from $caller") + logD(TAG, { "@getPackageStates: removed ${markedToRemove.size} entries from $caller" }) param.result = copyResult service.increasePMFilterCount(caller) } @@ -254,20 +254,20 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = findCallingUid() if (callingUid == null || callingUid == Constants.UID_SYSTEM) return val targetApp = findTargetApp() ?: return - logV(TAG, "@$methodName incoming query: $callingUid => $targetApp") + logV(TAG, { "@$methodName incoming query: $callingUid => $targetApp" }) if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { applyReturnValue() service.increasePMFilterCount(callingUid) - logD(TAG, "@$methodName caller cache: $callingUid, target: $targetApp") + logD(TAG, { "@$methodName caller cache: $callingUid, target: $targetApp" }) return } val callingApps = findCallingApps(callingUid) val caller = callingApps?.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { - logD(TAG, "@$methodName caller: $callingUid $caller, target: $targetApp") + logD(TAG, { "@$methodName caller: $callingUid $caller, target: $targetApp" }) applyReturnValue() val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, "@${methodName}: query from $caller") + if (last != caller) logI(TAG, { "@${methodName}: query from $caller" }) HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index 86b38b111..9e0c93e49 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -12,7 +12,7 @@ class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { override val TAG = "PmsPackageEventsHook" override fun load() { - logI(TAG, "Load hook") + logI(TAG, { "Load hook" }) BulkHooker.instance.apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index acc90a372..8e6e8532a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -14,7 +14,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { ZYGOTE_PROCESS_CLASS, "start", ) { param -> - logD(TAG, "@startZygoteProcess: Starting ${param.args.contentToString()}") + logD(TAG, { "@startZygoteProcess: Starting ${param.args.contentToString()}" }) // ignore if the GIDs array is null val gIDsIndex = param.args.indexOfFirst { it is IntArray } @@ -28,7 +28,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { // add more security, reject if not available in GID_PAIRS perms = perms.filter { Constants.GID_PAIRS.containsValue(it) } - logD(TAG, "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now") + logD(TAG, { "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now" }) param.setArgument(gIDsIndex, gIDs.filter { it !in perms }.toIntArray()) service.increaseOthersFilterCount(caller) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index fa0b3b1c9..e3f0ed85a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -34,7 +34,7 @@ class BulkHooker private constructor() { } if (inDisabledHooks == true) { - logI(ZygoteEntry.TAG, "Disabled hook: $clazz -> $methodName($paramCount)") + logI(ZygoteEntry.TAG, { "Disabled hook: $clazz -> $methodName($paramCount)" }) return } @@ -52,7 +52,7 @@ class BulkHooker private constructor() { hooks[clazz]!!.add(element) } else { - logI(ZygoteEntry.TAG, "Invalid hook removed: $clazz -> $methodName($paramCount)") + logI(ZygoteEntry.TAG, { "Invalid hook removed: $clazz -> $methodName($paramCount)" }) } } @@ -69,14 +69,14 @@ class BulkHooker private constructor() { try { hook(HookParam(clazz, original, frame, methodName, value)) } catch (it: Throwable) { - logE(ZygoteEntry.TAG, it.message ?: "Unknown error on hook", it) + logE(ZygoteEntry.TAG, { it.message ?: "Unknown error on hook" }, it) } if (!value.replace) { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logD(ZygoteEntry.TAG, it.message ?: "Unknown error on original function", it) + logD(ZygoteEntry.TAG, { it.message ?: "Unknown error on original function" }, it) value.throwable = it } } @@ -106,7 +106,7 @@ class BulkHooker private constructor() { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logD(ZygoteEntry.TAG, it.message ?: "Unknown error on original function", it) + logD(ZygoteEntry.TAG, { it.message ?: "Unknown error on original function" }, it) value.throwable = it } @@ -117,7 +117,7 @@ class BulkHooker private constructor() { try { hook(HookParam(clazz, original, frame, methodName, value)) } catch (it: Throwable) { - logE(ZygoteEntry.TAG, it.message ?: "Unknown error on hook", it) + logE(ZygoteEntry.TAG, { it.message ?: "Unknown error on hook" }, it) } value.throwable?.let { @@ -139,7 +139,7 @@ class BulkHooker private constructor() { try { curClazz = Class.forName(clazz, true, loader) } catch (ex: ClassNotFoundException) { - logE(ZygoteEntry.TAG, "Class $clazz not found", ex) + logE(ZygoteEntry.TAG, { "Class $clazz not found" }, ex) return false } @@ -153,14 +153,14 @@ class BulkHooker private constructor() { for (executable in executables) { if (!element.hookFinished) { - // logD(ZygoteEntry.TAG, "Hooked: $executable") + logD(ZygoteEntry.TAG, { "Hooked: $executable" }) val memoryAddresses = Hooks.hook( executable, Hooks.EntryPointType.DIRECT, element.impl, Hooks.EntryPointType.DIRECT ) - // logV(ZygoteEntry.TAG, "Memory address map: $memoryAddresses") + logV(ZygoteEntry.TAG, { "Memory address map: $memoryAddresses" }) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { element.memoryAddresses = memoryAddresses @@ -237,7 +237,7 @@ class BulkHooker private constructor() { try { curClazz = Class.forName(clazz, true, loader) } catch (ex: ClassNotFoundException) { - logE(ZygoteEntry.TAG, "Class $clazz not found", ex) + logE(ZygoteEntry.TAG, { "Class $clazz not found" }, ex) return null } @@ -264,7 +264,7 @@ class BulkHooker private constructor() { return methods.firstOrNull() } - logI(ZygoteEntry.TAG, "Invalid hook detected: $clazzNames -> $methodNames($paramCount)") + logI(ZygoteEntry.TAG, { "Invalid hook detected: $clazzNames -> $methodNames($paramCount)" }) return null } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 67cee8368..67890a0d1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -89,10 +89,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { loadFilterCount() loadConfig() installHooks() - logI(TAG, "HMA service initialized") + logI(TAG, { "HMA service initialized" }) AppPresets.instance.loggerFunction = { level, msg -> - logWithLevel(level, "AppPresets", msg) + logWithLevel(level, "AppPresets", { msg }) } reloadPresetsFromScratch() } @@ -132,7 +132,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logFile.createNewFile() logcatAvailable = true - logI(TAG, "Data dir: $dataDir") + logI(TAG, { "Data dir: $dataDir" }) } private fun loadConfig() { @@ -141,7 +141,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { runCatching { if (it.exists()) it.delete() }.onFailure { e -> - logW(TAG, "Failed to delete filter count, skip it", e) + logW(TAG, { "Failed to delete filter count, skip it" }, e) } } @@ -150,44 +150,44 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { runCatching { if (it.exists()) it.delete() }.onFailure { e -> - logW(TAG, "Failed to delete preset cache, skip it", e) + logW(TAG, { "Failed to delete preset cache, skip it" }, e) } } if (!configFile.exists()) { - logI(TAG, "Config file not found") + logI(TAG, { "Config file not found" }) return } val loading = runCatching { val json = configFile.readText() JsonConfig.parse(json) }.getOrElse { - logE(TAG, "Failed to parse config.json", it) + logE(TAG, { "Failed to parse config.json" }, it) return } if (loading.configVersion != BuildConfig.CONFIG_VERSION) { - logW(TAG, "Config version mismatch, need to reload") + logW(TAG, { "Config version mismatch, need to reload" }) return } cleanRemnantsFromConfig(loading) config = loading - logI(TAG, "Config loaded") + logI(TAG, { "Config loaded" }) } private fun loadFilterCount() { if (!filterCountFile.exists()) { - logI(TAG, "Filter count file not found") + logI(TAG, { "Filter count file not found" }) return } val loading = runCatching { val json = filterCountFile.readText() FilterHolder.parse(json) }.getOrElse { - logE(TAG, "Failed to parse filter_count.json", it) + logE(TAG, { "Failed to parse filter_count.json" }, it) return } filterHolder = loading - logI(TAG, "Filter counts loaded") + logI(TAG, { "Filter counts loaded" }) } private fun installHooks() { @@ -220,7 +220,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { frameworkHooks.add(ZygoteHook(this)) frameworkHooks.forEach(IFrameworkHook::load) - logI(TAG, "Hooks installed") + logI(TAG, { "Hooks installed" }) } fun increasePMFilterCount(callingUid: Int?, amount: Int = 1) = increaseFilterCount( @@ -378,20 +378,20 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { if (caller == BuildConfig.APP_PACKAGE_NAME) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED val appConfig = config.scope[caller] ?: return Constants.FAKE_INSTALLATION_SOURCE_DISABLED if (!appConfig.hideInstallationSource) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED - logD(TAG, "@shouldHideInstallationSource $caller: $query") + logD(TAG, { "@shouldHideInstallationSource $caller: $query" }) if (caller == query && appConfig.excludeTargetInstallationSource) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED try { val uid = getPackageUidCompat(pms, query, 0L, callingHandle.hashCode()) logD( TAG, - "@shouldHideInstallationSource UID for $caller, ${callingHandle.hashCode()}: $query, $uid" + { "@shouldHideInstallationSource UID for $caller, ${callingHandle.hashCode()}: $query, $uid" } ) if (uid < 0) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED // invalid package installation source request } catch (e: Throwable) { logD( TAG, - "@shouldHideInstallationSource UID error for $caller, ${callingHandle.hashCode()}", + { "@shouldHideInstallationSource UID error for $caller, ${callingHandle.hashCode()}" }, e ) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED @@ -411,7 +411,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { override fun stopService(cleanEnv: Boolean) { if (!cleanEnv) return - logI(TAG, "Clean runtime environment") + logI(TAG, { "Clean runtime environment" }) File(dataDir).deleteRecursively() } @@ -429,7 +429,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { val newConfig = JsonConfig.parse(json) cleanRemnantsFromConfig(newConfig) if (newConfig.configVersion != BuildConfig.CONFIG_VERSION) { - logW(TAG, "Sync config: version mismatch, need reboot") + logW(TAG, { "Sync config: version mismatch, need reboot" }) return } config = newConfig @@ -440,7 +440,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { // remove filter counts for apps if they are not in config filterHolder.filterCounts.removeIf { key, _ -> !config.scope.containsKey(key) } }.onSuccess { - logD(TAG, "Config synced") + logD(TAG, { "Config synced" }) }.onFailure { return@synchronized } @@ -458,7 +458,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { runCatching { filterCountFile.writeText(filterHolder.toString()) }.onSuccess { - logD(TAG, "Filter count synced") + logD(TAG, { "Filter count synced" }) }.onFailure { return@onFailure } @@ -499,10 +499,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid < 0) { val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { - logI(TAG, "The manager app signature is verified successfully") + logI(TAG, { "The manager app signature is verified successfully" }) appUid = pkgInfo!!.applicationInfo!!.uid } else { - logE(TAG, "The manager app itself is modified, skipping") + logE(TAG, { "The manager app itself is modified, skipping" }) appUid = -1 } } @@ -516,7 +516,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid >= 0) { - logI(TAG, "The manager app is uninstalled") + logI(TAG, { "The manager app is uninstalled" }) appUid = -1 } @@ -542,7 +542,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun log(level: Int, tag: String, message: String) { - logWithLevel(level, tag, message) + logWithLevel(level, tag, { message }) } override fun getPackageNames(userId: Int) = binderLocalScope { @@ -583,7 +583,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } AppPresets.instance.reloadPresets(apps) - logI(TAG, "All presets are loaded") + logI(TAG, { "All presets are loaded" }) } override fun getDetailedFilterStats() = filterHolder.toString() diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index b299a9c43..25c7f4624 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -25,7 +25,7 @@ object SystemServerHook { @Throws(Throwable::class) fun onSystemServer(loader: ClassLoader?) { - logV(TAG, "Class loader found: $loader") + logV(TAG, { "Class loader found: $loader" }) classLoader = loader @@ -35,13 +35,13 @@ object SystemServerHook { thread { val pms = Utils4Zygote.waitForService("package") as IPackageManager val pmn = Utils4Zygote.waitForService("package_native") - logD(TAG, "Got pms: $pms, $pmn") + logD(TAG, { "Got pms: $pms, $pmn" }) runCatching { UserService.register(pms, pmn) - logI(TAG, "User service started") + logI(TAG, { "User service started" }) }.onFailure { - logE(TAG, "System service crashed", it) + logE(TAG, { "System service crashed" }, it) } } } @@ -69,7 +69,7 @@ object SystemServerHook { try { checkSystemServer(frame) } catch (th: Throwable) { - logE(TAG, "An exception occurred while checkSystemServer", th) + logE(TAG, { "An exception occurred while checkSystemServer" }, th) } Transformers.invokeExact(original, frame) }, Hooks.EntryPointType.DIRECT) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index 2b4c2ecbd..2e6e881c5 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -23,7 +23,7 @@ object UserService { private val uidObserver = object : UidObserverAdapter() { override fun onUidActive(uid: Int) { if (HMAService.instance == null) { - logE(TAG, "HMAService instance is not available, maybe stopped") + logE(TAG, { "HMAService instance is not available, maybe stopped" }) return } @@ -47,18 +47,18 @@ object UserService { provider?.call("android", Constants.PROVIDER_AUTHORITY, "", null, extras) } if (reply == null) { - logE(TAG, "Failed to send binder to app") + logE(TAG, { "Failed to send binder to app" }) return } - logI(TAG, "Send binder to app") + logI(TAG, { "Send binder to app" }) } catch (e: Throwable) { - logE(TAG, "onUidActive", e) + logE(TAG, { "onUidActive" }, e) } } } fun register(pms: IPackageManager, pmn: Any?) { - logI(TAG, "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}") + logI(TAG, { "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}" }) var appUid = -1 @@ -66,7 +66,7 @@ object UserService { val pkgInfo = getPackageInfoCompat(pms, BuildConfig.APP_PACKAGE_NAME, 0L, 0) if (pkgInfo != null) { if (verifyAppSignature(pkgInfo.applicationInfo?.sourceDir)) { - logI(TAG, "The manager app signature is verified successfully") + logI(TAG, { "The manager app signature is verified successfully" }) appUid = pkgInfo.applicationInfo!!.uid } else { throw AssertionError("The manager app is modified, skipping") @@ -75,11 +75,11 @@ object UserService { assert(appUid >= 0) { "App UID cannot be -1 or lower" } - logD(TAG, "Client uid: $appUid") + logD(TAG, { "Client uid: $appUid" }) } catch (e: Throwable) { logE( TAG, - "Fatal: Cannot get package details\nCompile this app from source with your changes", + { "Fatal: Cannot get package details\nCompile this app from source with your changes" }, e ) } @@ -92,7 +92,7 @@ object UserService { null ) - logI(TAG, "Registered observer") + logI(TAG, { "Registered observer" }) val service = HMAService(pms, pmn) service.appUid = appUid diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index c1bde066e..f81a62c8e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -28,12 +28,12 @@ object Logcat { if (!endsWith('\n')) append('\n') } - fun logWithLevel(level: Int, tag: String, msg: String, cause: Throwable? = null) { + fun logWithLevel(level: Int, tag: String, msg: () -> String, cause: Throwable? = null) { if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return if (level == Log.VERBOSE && !BuildConfig.DEBUG) return - val parsedMsg = parseLog(level, tag, msg, cause) + val parsedMsg = parseLog(level, tag, msg(), cause) HMAService.instance?.apply { executor.execute { @@ -53,18 +53,19 @@ object Logcat { Log.i("HMA-OSS", msg) } - @JvmStatic - fun logV(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.VERBOSE, tag, msg, cause) + fun logV(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.VERBOSE, tag, msg, cause) - @JvmStatic - fun logD(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.DEBUG, tag, msg, cause) + fun logD(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.DEBUG, tag, msg, cause) - @JvmStatic - fun logI(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.INFO, tag, msg, cause) + fun logI(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.INFO, tag, msg, cause) + + fun logW(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.WARN, tag, msg, cause) + + fun logE(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.ERROR, tag, msg, cause) @JvmStatic - fun logW(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.WARN, tag, msg, cause) + fun logILegacy(tag: String, msg: String, cause: Throwable? = null) = logI(tag, { msg }, cause) @JvmStatic - fun logE(tag: String, msg: String, cause: Throwable? = null) = logWithLevel(Log.ERROR, tag, msg, cause) + fun logELegacy(tag: String, msg: String, cause: Throwable? = null) = logE(tag, { msg }, cause) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index db11035aa..51ecc985f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -86,7 +86,7 @@ object Utils4Zygote { String::class.java, ).invoke(null, name) as IBinder? } catch (e: Throwable) { - logE(TAG, "An error occurred on waitForService", e) + logE(TAG, { "An error occurred on waitForService" }, e) } var service: IBinder? = null From b335028da503e9fc45959c5711d76b1568ffaa68 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 14 Apr 2026 13:29:25 +0300 Subject: [PATCH 096/162] Try to fix log view --- app/src/main/res/layout/log_item_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/log_item_view.xml b/app/src/main/res/layout/log_item_view.xml index 91e94a64e..4675494dd 100644 --- a/app/src/main/res/layout/log_item_view.xml +++ b/app/src/main/res/layout/log_item_view.xml @@ -38,6 +38,7 @@ android:layout_height="wrap_content" android:layout_marginVertical="2dp" android:fontFamily="monospace" + android:inputType="textMultiLine" android:textAppearance="?textAppearanceBodySmall" tools:text="HMA service initialized" /> From 354f0a3dea667ff8e76b56479aa58631e65b3882 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 14 Apr 2026 14:09:44 +0300 Subject: [PATCH 097/162] Try to fix potential accessibility based detections --- .../hma_oss/zygote/hook/AccessibilityHook.kt | 82 +++++++++++++------ 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 35a892ca4..8cac7d564 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -2,12 +2,12 @@ package org.frknkrc44.hma_oss.zygote.hook import android.accessibilityservice.AccessibilityServiceInfo import android.content.pm.ParceledListSlice +import icu.nullptr.hidemyapplist.common.Utils import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService -import org.frknkrc44.hma_oss.zygote.service.HookParam import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS @@ -16,15 +16,51 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { override fun load() { BulkHooker.instance.apply { - hookBefore( + @Suppress("UNCHECKED_CAST") + hookAfter( ACCESSIBILITY_SERVICE_CLASS, "getInstalledAccessibilityServiceList", - ) { param -> hookedMethod(param) } + ) { param -> + val callingApps = Utils4Zygote.getCallingApps(service) + if (callingApps.isEmpty()) return@hookAfter + + val currentResult = param.result ?: return@hookAfter + val isParcel = "Parcel" in param.frame.type().returnType().simpleName + val inList = if (isParcel) { + (currentResult as ParceledListSlice).list + } else { + currentResult as List + } + + val calculatedList = calculateReturnedAccessibilityList(callingApps, inList) + param.result = if (isParcel) { + ParceledListSlice(calculatedList) + } else { + calculatedList + } + } hookBefore( ACCESSIBILITY_SERVICE_CLASS, "getEnabledAccessibilityServiceList", - ) { param -> hookedMethod(param) } + ) { param -> + val callingApps = Utils4Zygote.getCallingApps(service) + if (callingApps.isEmpty()) return@hookBefore + + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } + if (caller != null) { + logD(TAG, { "@${param.methodName} returning empty list for ${callingApps.contentToString()}" }) + + val returnedList = java.util.ArrayList() + + val returnParcel = "Parcel" in param.frame.type().returnType().simpleName + param.result = if (returnParcel) { + ParceledListSlice(returnedList) + } else { + returnedList + } + } + } hookBefore( ACCESSIBILITY_SERVICE_CLASS, @@ -42,31 +78,23 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { } } - private fun callerIsSpoofed(caller: String) = - service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) + private fun calculateReturnedAccessibilityList( + callingApps: Array, + inList: List, + ): List { + logV(TAG, { "@getInstalledAccessibilityServiceList*calculator: $callingApps - Current: $inList" }) - private fun hookedMethod(param: HookParam) { - try { - val callingApps = Utils4Zygote.getCallingApps(service) - if (callingApps.isEmpty()) return + val caller = callingApps.firstOrNull { callerIsSpoofed(it) } ?: return inList - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - val returnedList = java.util.ArrayList() + val calculatedList = inList.filter { asInfo -> + !service.shouldHide(caller, Utils.getPackageNameFromResolveInfo(asInfo.resolveInfo)) + } - logD(TAG, { "@${param.methodName} returned empty list for ${callingApps.contentToString()}" }) + logV(TAG, { "@getInstalledAccessibilityServiceList*calculator: $caller - Calculated: $calculatedList" }) - val returnParcel = param.frame.type().returnType().simpleName.contains("Parcel") - param.result = if (returnParcel) { - ParceledListSlice(returnedList) - } else { - returnedList - } - - // service.increasePMFilterCount(caller) - } - } catch (e: Throwable) { - logE(TAG, { "Fatal error occurred, ignore hooks" }, e) - } + return calculatedList } + + private fun callerIsSpoofed(caller: String) = + service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) } From ce79f04c7d024d4f394adabec908ed5f42042916 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 14 Apr 2026 14:51:06 +0300 Subject: [PATCH 098/162] Add "returnType", rename isParcel/returnParcel variable --- .../frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt | 10 ++++------ .../java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 6 +++--- .../frknkrc44/hma_oss/zygote/service/BulkHookerData.kt | 8 +++++++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 8cac7d564..2e275a050 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -25,15 +25,15 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { if (callingApps.isEmpty()) return@hookAfter val currentResult = param.result ?: return@hookAfter - val isParcel = "Parcel" in param.frame.type().returnType().simpleName - val inList = if (isParcel) { + val returnsParcel = "Parcel" in param.returnType.simpleName + val inList = if (returnsParcel) { (currentResult as ParceledListSlice).list } else { currentResult as List } val calculatedList = calculateReturnedAccessibilityList(callingApps, inList) - param.result = if (isParcel) { + param.result = if (returnsParcel) { ParceledListSlice(calculatedList) } else { calculatedList @@ -52,9 +52,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { logD(TAG, { "@${param.methodName} returning empty list for ${callingApps.contentToString()}" }) val returnedList = java.util.ArrayList() - - val returnParcel = "Parcel" in param.frame.type().returnType().simpleName - param.result = if (returnParcel) { + param.result = if ("Parcel" in param.returnType.simpleName) { ParceledListSlice(returnedList) } else { returnedList diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 55f722b76..40f0fba95 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -116,7 +116,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { logD(TAG, { "@${param.methodName}: Caller ID: $callingUid" }) - val returnType = param.frame.type().returnType() + val returnType = param.returnType if (returnType.simpleName == "InputMethodInfoSafeList") { val inList = callStaticMethod( currentResult.javaClass, @@ -157,7 +157,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } listOf(fakeIMInfo).let { list -> - val returnType = param.frame.type().returnType() + val returnType = param.returnType param.result = if (returnType.simpleName == "InputMethodInfoSafeList") { returnType.getDeclaredMethod( "create", @@ -231,7 +231,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { // TODO: Find a method to get exact list for spoofed input method Collections.emptyList().let { list -> - val returnType = param.frame.type().returnType() + val returnType = param.returnType param.result = if (returnType.simpleName == "InputMethodSubtypeSafeList") { returnType.getDeclaredMethod( "create", diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt index 3ae92caa2..7ab82f179 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt @@ -1,5 +1,6 @@ package org.frknkrc44.hma_oss.zygote.service +import android.util.Pair import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.vmtools.HookTransformer import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote @@ -30,6 +31,11 @@ data class HookParam( get() = returnValue.result set(newValue) { returnValue.result = newValue } + /** + * @return Class of the return type + */ + val returnType: Class<*> get() = frame.type().returnType() + /** * Returns the first argument */ @@ -55,7 +61,7 @@ data class HookElement( val methodName: String, val hookOnce: Boolean, var method: Executable? = null, - var memoryAddresses: android.util.Pair? = null, + var memoryAddresses: Pair? = null, var hookFinished: Boolean = false, val paramCount: Int = -1, var applyCount: Int = 0, From afcd7c3afd18ba2446799ae8b6c1ebc20572291d Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 14 Apr 2026 16:09:32 +0300 Subject: [PATCH 099/162] Optimize the logging methods --- .../hma_oss/zygote/hook/AccessibilityHook.kt | 6 +- .../hma_oss/zygote/hook/ActivityHook.kt | 15 ++--- .../zygote/hook/AppDataIsolationHook.kt | 27 +++------ .../zygote/hook/ContentProviderHook.kt | 18 +++--- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 26 ++++----- .../hma_oss/zygote/hook/PlatformCompatHook.kt | 8 +-- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget33.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 12 ++-- .../zygote/hook/PmsPackageEventsHook.kt | 2 +- .../hma_oss/zygote/hook/ZygoteHook.kt | 4 +- .../hma_oss/zygote/service/BulkHooker.kt | 22 +++---- .../hma_oss/zygote/service/HMAService.kt | 57 ++++++++----------- .../zygote/service/SystemServerHook.kt | 10 ++-- .../hma_oss/zygote/service/UserService.kt | 22 +++---- .../frknkrc44/hma_oss/zygote/util/Logcat.kt | 16 +++--- .../hma_oss/zygote/util/Utils4Zygote.kt | 2 +- 20 files changed, 117 insertions(+), 140 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 2e275a050..7f0041376 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -49,7 +49,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, { "@${param.methodName} returning empty list for ${callingApps.contentToString()}" }) + logD(TAG) { "@${param.methodName} returning empty list for ${callingApps.contentToString()}" } val returnedList = java.util.ArrayList() param.result = if ("Parcel" in param.returnType.simpleName) { @@ -80,7 +80,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { callingApps: Array, inList: List, ): List { - logV(TAG, { "@getInstalledAccessibilityServiceList*calculator: $callingApps - Current: $inList" }) + logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $callingApps - Current: $inList" } val caller = callingApps.firstOrNull { callerIsSpoofed(it) } ?: return inList @@ -88,7 +88,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { !service.shouldHide(caller, Utils.getPackageNameFromResolveInfo(asInfo.resolveInfo)) } - logV(TAG, { "@getInstalledAccessibilityServiceList*calculator: $caller - Calculated: $calculatedList" }) + logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Calculated: $calculatedList" } return calculatedList } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index ea4060ab9..b03ca0f5f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -33,7 +33,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { } override fun load() { - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { hookBefore( @@ -46,10 +46,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { val targetApp = intent?.component?.packageName if (service.shouldHideActivityLaunch(caller, targetApp)) { - logD( - TAG, - { "@executeRequest: insecure query from $caller, target: ${intent?.component}" } - ) + logD(TAG) { "@executeRequest: insecure query from $caller, target: ${intent?.component}" } param.result = fakeReturnCode service.increaseALFilterCount(caller) } @@ -63,7 +60,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { }, "checkStartAnyActivityPermission", ) { param -> - logV(TAG, { "${param.methodName}: ${param.args.contentToString()}" }) + logV(TAG) { "${param.methodName}: ${param.args.contentToString()}" } // just an empty hook that does nothing } @@ -87,16 +84,16 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { val callingApps = Utils4Zygote.getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller != null) { - logV(TAG, { "@${param.methodName}: $caller requested a resolve info" }) + logV(TAG) { "@${param.methodName}: $caller requested a resolve info" } val filteredList = list.filter { resolveInfo -> val targetApp = Utils.getPackageNameFromResolveInfo(resolveInfo) - logV(TAG, { "@${param.methodName}: Checking $targetApp for $caller" }) + logV(TAG) { "@${param.methodName}: Checking $targetApp for $caller" } (!service.shouldHideActivityLaunch(caller, targetApp)).apply { if (!this) { - logD(TAG, { "@${param.methodName}: Filtered $targetApp from $caller" }) + logD(TAG) { "@${param.methodName}: Filtered $targetApp from $caller" } } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index d6262d883..8caeda1da 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -32,7 +32,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { override fun load() { if (!(service.config.altAppDataIsolation || service.config.altVoldAppDataIsolation)) return - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { hookBefore( @@ -52,7 +52,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { true ) - logI(TAG, { "ProcessList - App data isolation is forced" }) + logI(TAG) { "ProcessList - App data isolation is forced" } } } @@ -61,7 +61,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { if (!fuseEnabled) { voldHookSkipped = true - logE(TAG, { "ProcessList - FUSE storage is not enabled, skip vold hook" }) + logE(TAG) { "ProcessList - FUSE storage is not enabled, skip vold hook" } } else { val isolationEnabled = getBooleanField( param.thisObject, @@ -75,7 +75,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { true ) - logI(TAG, { "ProcessList - Vold app data isolation is forced" }) + logI(TAG) { "ProcessList - Vold app data isolation is forced" } } } } @@ -103,10 +103,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { val apps = Utils4Zygote.getCallingApps(service, uid) - logD( - TAG, - { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" } - ) + logD(TAG) { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" } // Do not isolate this module for safety if (apps.contains(BuildConfig.APP_PACKAGE_NAME)) { @@ -120,10 +117,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { if (service.config.skipSystemAppDataIsolation) { val isSystemApp = service.systemApps.any { apps.contains(it) } - logD( - TAG, - { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - isSystemApp: $isSystemApp" } - ) + logD(TAG) { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - isSystemApp: $isSystemApp" } if (isSystemApp) { param.result = false @@ -141,7 +135,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) if (!fuseEnabled) { - logE(TAG, { "StorageManagerService - FUSE storage is not enabled, skip vold hook" }) + logE(TAG) { "StorageManagerService - FUSE storage is not enabled, skip vold hook" } voldHookSkipped = true return@hookBefore } @@ -158,7 +152,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { true ) - logI(TAG, { "StorageManagerService - Vold app data isolation is forced" }) + logI(TAG) { "StorageManagerService - Vold app data isolation is forced" } } } } @@ -177,10 +171,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { val packageName = entry.value as String if (packageName in service.systemApps || packageName == BuildConfig.APP_PACKAGE_NAME) { - logD( - TAG, - { "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" } - ) + logD(TAG) { "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" } keysToRemove += pid break } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 1ae6cc54c..ff164586c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -43,18 +43,18 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val segments = uri.pathSegments if (segments.isEmpty()) return@hookAfter - logD(TAG, { "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args" }) + logD(TAG) { "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args" } val database = segments[0] if (segments.size >= 2) { val name = segments[1] - logD(TAG, { "@spoofSettings QUERY received caller: $caller, database: $database, name: $name" }) + logD(TAG) { "@spoofSettings QUERY received caller: $caller, database: $database, name: $name" } val replacement = service.getSpoofedSetting(caller, name, database) if (replacement != null) { - logD(TAG, { "@spoofSettings QUERY $name in $database replaced for $caller" }) + logD(TAG) { "@spoofSettings QUERY $name in $database replaced for $caller" } param.result = MatrixCursor(arrayOf("name", "value"), 1).apply { addRow(arrayOf(replacement.name, replacement.value)) } @@ -62,7 +62,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { service.increaseSettingsFilterCount(caller) } } else { - logD(TAG, { "@spoofSettings LIST_QUERY received caller: $caller, database: $database" }) + logD(TAG) { "@spoofSettings LIST_QUERY received caller: $caller, database: $database" } val result = param.result as? Cursor? ?: return@hookAfter @@ -72,13 +72,13 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { } } - logD(TAG, { "@spoofSetting LIST_QUERY columns: ${columns.keys}" }) + logD(TAG) { "@spoofSetting LIST_QUERY columns: ${columns.keys}" } val keyColumn = columns["name"] val valueColumn = columns["value"] if (keyColumn == null || valueColumn == null) { - logD(TAG, { "@spoofSettings LIST_QUERY invalid query: $caller ($keyColumn, $valueColumn)" }) + logD(TAG) { "@spoofSettings LIST_QUERY invalid query: $caller ($keyColumn, $valueColumn)" } return@hookAfter } @@ -88,7 +88,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val replacement = service.getSpoofedSetting(caller, name, database) val value = if (replacement != null) { - logD(TAG, { "@spoofSettings QUERY $name in $database replaced for $caller" }) + logD(TAG) { "@spoofSettings QUERY $name in $database replaced for $caller" } service.increaseSettingsFilterCount(caller) @@ -135,14 +135,14 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val name = param.args[nameIdx] as String? val method = param.args[nameIdx - 1] as String? - logD(TAG, { "@spoofSettings CALL received caller: ${callingApps.contentToString()}, method: $method, name: $name" }) + logD(TAG) { "@spoofSettings CALL received caller: ${callingApps.contentToString()}, method: $method, name: $name" } when (method) { "GET_global", "GET_secure", "GET_system" -> { val database = method.substring(method.indexOf('_') + 1) val replacement = service.getSpoofedSetting(caller, name, database) if (replacement != null) { - logD(TAG, { "@spoofSettings CALL $name in $database replaced for $caller" }) + logD(TAG) { "@spoofSettings CALL $name in $database replaced for $caller" } param.result = Bundle().apply { putString(Settings.NameValueTable.VALUE, replacement.value) putInt("_generation_index", -1) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 40f0fba95..303309c6e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -36,7 +36,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { if (defaultInputMethod?.value != null) { try { val component = ComponentName.unflattenFromString(defaultInputMethod.value!!)!! - logD(TAG, { "Package component: \"$component\"" }) + logD(TAG) { "Package component: \"$component\"" } val pkgManager = Utils4Zygote.getPackageManager() val kbdPackage = Utils.binderLocalScope { @@ -50,7 +50,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { null, ) } catch (e: Throwable) { - logV(TAG, { e.message ?: "" }, e) + logV(TAG, e) { e.message ?: "" } } } @@ -80,7 +80,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, { "@${param.methodName} spoofed input method for $caller" }) + logD(TAG) { "@${param.methodName} spoofed input method for $caller" } val fakeIMInfo = getFakeInputMethodInfo(caller) val userHandle = param.getArgument(1) as Int @@ -103,10 +103,10 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { method.declaringClass.name, method.name, ) { param -> - logD(TAG, { "@${param.methodName}: hook init" }) + logD(TAG) { "@${param.methodName}: hook init" } val currentResult = param.result ?: return@hookAfter - logD(TAG, { "@${param.methodName}: Result: $currentResult Args: ${param.args.contentToString()}" }) + logD(TAG) { "@${param.methodName}: Result: $currentResult Args: ${param.args.contentToString()}" } val callingUid = if (param.args.count { it is Int } > 2) { param.args.lastOrNull { it is Int && it > 999 } as? Int ?: return@hookAfter @@ -114,7 +114,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { Binder.getCallingUid() } - logD(TAG, { "@${param.methodName}: Caller ID: $callingUid" }) + logD(TAG) { "@${param.methodName}: Caller ID: $callingUid" } val returnType = param.returnType if (returnType.simpleName == "InputMethodInfoSafeList") { @@ -149,7 +149,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, { "@${param.methodName}: spoofed input method for $caller" }) + logD(TAG) { "@${param.methodName}: spoofed input method for $caller" } val fakeIMInfo = getFakeInputMethodInfo(caller) if (!isIMExists(fakeIMInfo.packageName)) { @@ -214,7 +214,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, { "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}" }) + logD(TAG) { "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}" } // TODO: Find a method to get exact value for spoofed input method param.result = null @@ -227,7 +227,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { - logD(TAG, { "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}" }) + logD(TAG) { "@${param.methodName}: spoofed input method subtype for ${callingApps.contentToString()}" } // TODO: Find a method to get exact list for spoofed input method Collections.emptyList().let { list -> @@ -245,18 +245,18 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } fun calculateReturnedInputMethodList(callingUid: Int, inList: List): List { - logV(TAG, { "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}" }) + logV(TAG) { "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}" } val caller = Utils4Zygote.getCallingApps(service, callingUid) .firstOrNull { callerIsSpoofed(it) } ?: return inList - logD(TAG, { "@getInputMethodList: spoofed input method for $caller" }) + logD(TAG) { "@getInputMethodList: spoofed input method for $caller" } val calculatedList = inList.filter { imInfo -> !service.shouldHide(caller, imInfo.packageName) } - logV(TAG, { "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}" }) + logV(TAG) { "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}" } val fakeIMInfo = getFakeInputMethodInfo(caller) @@ -281,7 +281,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun warnNotInstalledKeyboard(methodName: String, packageName: String) { - logW(TAG, { "@$methodName: PROBABLY spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections. Do not care this message if you are sure the keyboard is installed correctly." }) + logW(TAG) { "@$methodName: PROBABLY spoofing for a not installed keyboard, please install $packageName or spoof for another keyboard by using settings templates to reduce detections. Do not care this message if you are sure the keyboard is installed correctly." } } private fun callerIsSpoofed(caller: String) = diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt index ae3044cdc..814ed1f5a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PlatformCompatHook.kt @@ -22,8 +22,8 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { override fun load() { if (!service.config.forceMountData) return - logI(TAG, { "Load hook" }) - logI(TAG, { "App data isolation enabled: $sAppDataIsolationEnabled" }) + logI(TAG) { "Load hook" } + logI(TAG) { "App data isolation enabled: $sAppDataIsolationEnabled" } BulkHooker.instance.hookBefore( PLATFORM_COMPAT_CLASS, @@ -40,10 +40,10 @@ class PlatformCompatHook(private val service: HMAService) : IFrameworkHook { if (app == BuildConfig.APP_PACKAGE_NAME || app in service.systemApps) return@hookBefore if (service.isHookEnabled(app)) { param.result = true - logD(TAG, { "force mount data: ${appInfo.uid} $app" }) + logD(TAG) { "force mount data: ${appInfo.uid} $app" } } }.onFailure { - logE(TAG, { "Fatal error occurred, disable hooks" }, it) + logE(TAG, it) { "Fatal error occurred, disable hooks" } } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index 5e7bb153d..820797513 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -17,7 +17,7 @@ class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 1531df7a1..542520928 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -43,7 +43,7 @@ class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { } override fun load() { - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index f019e7760..ecf287b2d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -43,7 +43,7 @@ class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { } override fun load() { - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index addaae5d2..6035c0a8a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -56,7 +56,7 @@ class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 53c90f67c..35fa7b056 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -61,7 +61,7 @@ class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { @Suppress("UNCHECKED_CAST") override fun load() { - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { hookBefore( diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 28cdb8b10..7df637681 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -54,7 +54,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingApps = getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller != null) { - logD(TAG, { "@getPackageStates: incoming query from $caller" }) + logD(TAG) { "@getPackageStates: incoming query from $caller" } val result = param.result as ArrayMap<*, *> val markedToRemove = mutableListOf() @@ -70,7 +70,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework if (markedToRemove.isNotEmpty()) { val copyResult = ArrayMap(result) copyResult.removeAll(markedToRemove) - logD(TAG, { "@getPackageStates: removed ${markedToRemove.size} entries from $caller" }) + logD(TAG) { "@getPackageStates: removed ${markedToRemove.size} entries from $caller" } param.result = copyResult service.increasePMFilterCount(caller) } @@ -254,20 +254,20 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = findCallingUid() if (callingUid == null || callingUid == Constants.UID_SYSTEM) return val targetApp = findTargetApp() ?: return - logV(TAG, { "@$methodName incoming query: $callingUid => $targetApp" }) + logV(TAG) { "@$methodName incoming query: $callingUid => $targetApp" } if (HMAServiceCache.instance.shouldHideFromUid(callingUid, targetApp) == true) { applyReturnValue() service.increasePMFilterCount(callingUid) - logD(TAG, { "@$methodName caller cache: $callingUid, target: $targetApp" }) + logD(TAG) { "@$methodName caller cache: $callingUid, target: $targetApp" } return } val callingApps = findCallingApps(callingUid) val caller = callingApps?.firstOrNull { service.shouldHide(it, targetApp) } if (caller != null) { - logD(TAG, { "@$methodName caller: $callingUid $caller, target: $targetApp" }) + logD(TAG) { "@$methodName caller: $callingUid $caller, target: $targetApp" } applyReturnValue() val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG, { "@${methodName}: query from $caller" }) + if (last != caller) logI(TAG) { "@${methodName}: query from $caller" } HMAServiceCache.instance.putShouldHideUidCache(callingUid, caller, targetApp) service.increasePMFilterCount(caller) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt index 9e0c93e49..9c6a3bbb6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsPackageEventsHook.kt @@ -12,7 +12,7 @@ class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { override val TAG = "PmsPackageEventsHook" override fun load() { - logI(TAG, { "Load hook" }) + logI(TAG) { "Load hook" } BulkHooker.instance.apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index 8e6e8532a..97dd1a101 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -14,7 +14,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { ZYGOTE_PROCESS_CLASS, "start", ) { param -> - logD(TAG, { "@startZygoteProcess: Starting ${param.args.contentToString()}" }) + logD(TAG) { "@startZygoteProcess: Starting ${param.args.contentToString()}" } // ignore if the GIDs array is null val gIDsIndex = param.args.indexOfFirst { it is IntArray } @@ -28,7 +28,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { // add more security, reject if not available in GID_PAIRS perms = perms.filter { Constants.GID_PAIRS.containsValue(it) } - logD(TAG, { "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now" }) + logD(TAG) { "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now" } param.setArgument(gIDsIndex, gIDs.filter { it !in perms }.toIntArray()) service.increaseOthersFilterCount(caller) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index e3f0ed85a..6d5377c11 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -34,7 +34,7 @@ class BulkHooker private constructor() { } if (inDisabledHooks == true) { - logI(ZygoteEntry.TAG, { "Disabled hook: $clazz -> $methodName($paramCount)" }) + logI(ZygoteEntry.TAG) { "Disabled hook: $clazz -> $methodName($paramCount)" } return } @@ -52,7 +52,7 @@ class BulkHooker private constructor() { hooks[clazz]!!.add(element) } else { - logI(ZygoteEntry.TAG, { "Invalid hook removed: $clazz -> $methodName($paramCount)" }) + logI(ZygoteEntry.TAG) { "Invalid hook removed: $clazz -> $methodName($paramCount)" } } } @@ -69,14 +69,14 @@ class BulkHooker private constructor() { try { hook(HookParam(clazz, original, frame, methodName, value)) } catch (it: Throwable) { - logE(ZygoteEntry.TAG, { it.message ?: "Unknown error on hook" }, it) + logE(ZygoteEntry.TAG, it) { it.message ?: "Unknown error on hook" } } if (!value.replace) { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logD(ZygoteEntry.TAG, { it.message ?: "Unknown error on original function" }, it) + logD(ZygoteEntry.TAG, it) { it.message ?: "Unknown error on original function" } value.throwable = it } } @@ -106,7 +106,7 @@ class BulkHooker private constructor() { try { invokeExactCompat(clazz, methodName, original, frame, value) } catch (it: Throwable) { - logD(ZygoteEntry.TAG, { it.message ?: "Unknown error on original function" }, it) + logD(ZygoteEntry.TAG, it) { it.message ?: "Unknown error on original function" } value.throwable = it } @@ -117,7 +117,7 @@ class BulkHooker private constructor() { try { hook(HookParam(clazz, original, frame, methodName, value)) } catch (it: Throwable) { - logE(ZygoteEntry.TAG, { it.message ?: "Unknown error on hook" }, it) + logE(ZygoteEntry.TAG, it) { it.message ?: "Unknown error on hook" } } value.throwable?.let { @@ -139,7 +139,7 @@ class BulkHooker private constructor() { try { curClazz = Class.forName(clazz, true, loader) } catch (ex: ClassNotFoundException) { - logE(ZygoteEntry.TAG, { "Class $clazz not found" }, ex) + logE(ZygoteEntry.TAG, ex) { "Class $clazz not found" } return false } @@ -153,14 +153,14 @@ class BulkHooker private constructor() { for (executable in executables) { if (!element.hookFinished) { - logD(ZygoteEntry.TAG, { "Hooked: $executable" }) + logD(ZygoteEntry.TAG) { "Hooked: $executable" } val memoryAddresses = Hooks.hook( executable, Hooks.EntryPointType.DIRECT, element.impl, Hooks.EntryPointType.DIRECT ) - logV(ZygoteEntry.TAG, { "Memory address map: $memoryAddresses" }) + logV(ZygoteEntry.TAG) { "Memory address map: $memoryAddresses" } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { element.memoryAddresses = memoryAddresses @@ -237,7 +237,7 @@ class BulkHooker private constructor() { try { curClazz = Class.forName(clazz, true, loader) } catch (ex: ClassNotFoundException) { - logE(ZygoteEntry.TAG, { "Class $clazz not found" }, ex) + logE(ZygoteEntry.TAG, ex) { "Class $clazz not found" } return null } @@ -264,7 +264,7 @@ class BulkHooker private constructor() { return methods.firstOrNull() } - logI(ZygoteEntry.TAG, { "Invalid hook detected: $clazzNames -> $methodNames($paramCount)" }) + logI(ZygoteEntry.TAG) { "Invalid hook detected: $clazzNames -> $methodNames($paramCount)" } return null } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 67890a0d1..3073099c3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -89,10 +89,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { loadFilterCount() loadConfig() installHooks() - logI(TAG, { "HMA service initialized" }) + logI(TAG) { "HMA service initialized" } AppPresets.instance.loggerFunction = { level, msg -> - logWithLevel(level, "AppPresets", { msg }) + logWithLevel(level, "AppPresets") { msg } } reloadPresetsFromScratch() } @@ -132,7 +132,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logFile.createNewFile() logcatAvailable = true - logI(TAG, { "Data dir: $dataDir" }) + logI(TAG) { "Data dir: $dataDir" } } private fun loadConfig() { @@ -141,7 +141,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { runCatching { if (it.exists()) it.delete() }.onFailure { e -> - logW(TAG, { "Failed to delete filter count, skip it" }, e) + logW(TAG, e) { "Failed to delete filter count, skip it" } } } @@ -150,44 +150,44 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { runCatching { if (it.exists()) it.delete() }.onFailure { e -> - logW(TAG, { "Failed to delete preset cache, skip it" }, e) + logW(TAG, e) { "Failed to delete preset cache, skip it" } } } if (!configFile.exists()) { - logI(TAG, { "Config file not found" }) + logI(TAG) { "Config file not found" } return } val loading = runCatching { val json = configFile.readText() JsonConfig.parse(json) }.getOrElse { - logE(TAG, { "Failed to parse config.json" }, it) + logE(TAG, it) { "Failed to parse config.json" } return } if (loading.configVersion != BuildConfig.CONFIG_VERSION) { - logW(TAG, { "Config version mismatch, need to reload" }) + logW(TAG) { "Config version mismatch, need to reload" } return } cleanRemnantsFromConfig(loading) config = loading - logI(TAG, { "Config loaded" }) + logI(TAG) { "Config loaded" } } private fun loadFilterCount() { if (!filterCountFile.exists()) { - logI(TAG, { "Filter count file not found" }) + logI(TAG) { "Filter count file not found" } return } val loading = runCatching { val json = filterCountFile.readText() FilterHolder.parse(json) }.getOrElse { - logE(TAG, { "Failed to parse filter_count.json" }, it) + logE(TAG, it) { "Failed to parse filter_count.json" } return } filterHolder = loading - logI(TAG, { "Filter counts loaded" }) + logI(TAG) { "Filter counts loaded" } } private fun installHooks() { @@ -220,7 +220,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { frameworkHooks.add(ZygoteHook(this)) frameworkHooks.forEach(IFrameworkHook::load) - logI(TAG, { "Hooks installed" }) + logI(TAG) { "Hooks installed" } } fun increasePMFilterCount(callingUid: Int?, amount: Int = 1) = increaseFilterCount( @@ -378,22 +378,15 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { if (caller == BuildConfig.APP_PACKAGE_NAME) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED val appConfig = config.scope[caller] ?: return Constants.FAKE_INSTALLATION_SOURCE_DISABLED if (!appConfig.hideInstallationSource) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED - logD(TAG, { "@shouldHideInstallationSource $caller: $query" }) + logD(TAG) { "@shouldHideInstallationSource $caller: $query" } if (caller == query && appConfig.excludeTargetInstallationSource) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED try { val uid = getPackageUidCompat(pms, query, 0L, callingHandle.hashCode()) - logD( - TAG, - { "@shouldHideInstallationSource UID for $caller, ${callingHandle.hashCode()}: $query, $uid" } - ) + logD(TAG) { "@shouldHideInstallationSource UID for $caller, ${callingHandle.hashCode()}: $query, $uid" } if (uid < 0) return Constants.FAKE_INSTALLATION_SOURCE_DISABLED // invalid package installation source request } catch (e: Throwable) { - logD( - TAG, - { "@shouldHideInstallationSource UID error for $caller, ${callingHandle.hashCode()}" }, - e - ) + logD(TAG, e) { "@shouldHideInstallationSource UID error for $caller, ${callingHandle.hashCode()}" } return Constants.FAKE_INSTALLATION_SOURCE_DISABLED } @@ -411,7 +404,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { override fun stopService(cleanEnv: Boolean) { if (!cleanEnv) return - logI(TAG, { "Clean runtime environment" }) + logI(TAG) { "Clean runtime environment" } File(dataDir).deleteRecursively() } @@ -429,7 +422,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { val newConfig = JsonConfig.parse(json) cleanRemnantsFromConfig(newConfig) if (newConfig.configVersion != BuildConfig.CONFIG_VERSION) { - logW(TAG, { "Sync config: version mismatch, need reboot" }) + logW(TAG) { "Sync config: version mismatch, need reboot" } return } config = newConfig @@ -440,7 +433,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { // remove filter counts for apps if they are not in config filterHolder.filterCounts.removeIf { key, _ -> !config.scope.containsKey(key) } }.onSuccess { - logD(TAG, { "Config synced" }) + logD(TAG) { "Config synced" } }.onFailure { return@synchronized } @@ -458,7 +451,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { runCatching { filterCountFile.writeText(filterHolder.toString()) }.onSuccess { - logD(TAG, { "Filter count synced" }) + logD(TAG) { "Filter count synced" } }.onFailure { return@onFailure } @@ -499,10 +492,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid < 0) { val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { - logI(TAG, { "The manager app signature is verified successfully" }) + logI(TAG) { "The manager app signature is verified successfully" } appUid = pkgInfo!!.applicationInfo!!.uid } else { - logE(TAG, { "The manager app itself is modified, skipping" }) + logE(TAG) { "The manager app itself is modified, skipping" } appUid = -1 } } @@ -516,7 +509,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid >= 0) { - logI(TAG, { "The manager app is uninstalled" }) + logI(TAG) { "The manager app is uninstalled" } appUid = -1 } @@ -542,7 +535,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } override fun log(level: Int, tag: String, message: String) { - logWithLevel(level, tag, { message }) + logWithLevel(level, tag) { message } } override fun getPackageNames(userId: Int) = binderLocalScope { @@ -583,7 +576,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } AppPresets.instance.reloadPresets(apps) - logI(TAG, { "All presets are loaded" }) + logI(TAG) { "All presets are loaded" } } override fun getDetailedFilterStats() = filterHolder.toString() diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 25c7f4624..492542e41 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -25,7 +25,7 @@ object SystemServerHook { @Throws(Throwable::class) fun onSystemServer(loader: ClassLoader?) { - logV(TAG, { "Class loader found: $loader" }) + logV(TAG) { "Class loader found: $loader" } classLoader = loader @@ -35,13 +35,13 @@ object SystemServerHook { thread { val pms = Utils4Zygote.waitForService("package") as IPackageManager val pmn = Utils4Zygote.waitForService("package_native") - logD(TAG, { "Got pms: $pms, $pmn" }) + logD(TAG) { "Got pms: $pms, $pmn" } runCatching { UserService.register(pms, pmn) - logI(TAG, { "User service started" }) + logI(TAG) { "User service started" } }.onFailure { - logE(TAG, { "System service crashed" }, it) + logE(TAG, it) { "System service crashed" } } } } @@ -69,7 +69,7 @@ object SystemServerHook { try { checkSystemServer(frame) } catch (th: Throwable) { - logE(TAG, { "An exception occurred while checkSystemServer" }, th) + logE(TAG, th) { "An exception occurred while checkSystemServer" } } Transformers.invokeExact(original, frame) }, Hooks.EntryPointType.DIRECT) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index 2e6e881c5..b7e94ba0f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -23,7 +23,7 @@ object UserService { private val uidObserver = object : UidObserverAdapter() { override fun onUidActive(uid: Int) { if (HMAService.instance == null) { - logE(TAG, { "HMAService instance is not available, maybe stopped" }) + logE(TAG) { "HMAService instance is not available, maybe stopped" } return } @@ -47,18 +47,18 @@ object UserService { provider?.call("android", Constants.PROVIDER_AUTHORITY, "", null, extras) } if (reply == null) { - logE(TAG, { "Failed to send binder to app" }) + logE(TAG) { "Failed to send binder to app" } return } - logI(TAG, { "Send binder to app" }) + logI(TAG) { "Send binder to app" } } catch (e: Throwable) { - logE(TAG, { "onUidActive" }, e) + logE(TAG, e) { "onUidActive" } } } } fun register(pms: IPackageManager, pmn: Any?) { - logI(TAG, { "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}" }) + logI(TAG) { "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}" } var appUid = -1 @@ -66,7 +66,7 @@ object UserService { val pkgInfo = getPackageInfoCompat(pms, BuildConfig.APP_PACKAGE_NAME, 0L, 0) if (pkgInfo != null) { if (verifyAppSignature(pkgInfo.applicationInfo?.sourceDir)) { - logI(TAG, { "The manager app signature is verified successfully" }) + logI(TAG) { "The manager app signature is verified successfully" } appUid = pkgInfo.applicationInfo!!.uid } else { throw AssertionError("The manager app is modified, skipping") @@ -75,13 +75,9 @@ object UserService { assert(appUid >= 0) { "App UID cannot be -1 or lower" } - logD(TAG, { "Client uid: $appUid" }) + logD(TAG) { "Client uid: $appUid" } } catch (e: Throwable) { - logE( - TAG, - { "Fatal: Cannot get package details\nCompile this app from source with your changes" }, - e - ) + logE(TAG, e) { "Fatal: Cannot get package details\nCompile this app from source with your changes" } } Utils4Zygote.waitForService("activity") @@ -92,7 +88,7 @@ object UserService { null ) - logI(TAG, { "Registered observer" }) + logI(TAG) { "Registered observer" } val service = HMAService(pms, pmn) service.appUid = appUid diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index f81a62c8e..7048946fe 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -28,7 +28,7 @@ object Logcat { if (!endsWith('\n')) append('\n') } - fun logWithLevel(level: Int, tag: String, msg: () -> String, cause: Throwable? = null) { + fun logWithLevel(level: Int, tag: String, cause: Throwable? = null, msg: () -> String) { if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return if (level == Log.VERBOSE && !BuildConfig.DEBUG) return @@ -53,19 +53,19 @@ object Logcat { Log.i("HMA-OSS", msg) } - fun logV(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.VERBOSE, tag, msg, cause) + fun logV(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.VERBOSE, tag, cause, msg) - fun logD(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.DEBUG, tag, msg, cause) + fun logD(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.DEBUG, tag, cause, msg) - fun logI(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.INFO, tag, msg, cause) + fun logI(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.INFO, tag, cause, msg) - fun logW(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.WARN, tag, msg, cause) + fun logW(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.WARN, tag, cause, msg) - fun logE(tag: String, msg: () -> String, cause: Throwable? = null) = logWithLevel(Log.ERROR, tag, msg, cause) + fun logE(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.ERROR, tag, cause, msg) @JvmStatic - fun logILegacy(tag: String, msg: String, cause: Throwable? = null) = logI(tag, { msg }, cause) + fun logILegacy(tag: String, msg: String, cause: Throwable?) = logI(tag, cause) { msg } @JvmStatic - fun logELegacy(tag: String, msg: String, cause: Throwable? = null) = logE(tag, { msg }, cause) + fun logELegacy(tag: String, msg: String, cause: Throwable?) = logE(tag, cause) { msg } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index 51ecc985f..8eec99dda 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -86,7 +86,7 @@ object Utils4Zygote { String::class.java, ).invoke(null, name) as IBinder? } catch (e: Throwable) { - logE(TAG, { "An error occurred on waitForService" }, e) + logE(TAG, e) { "An error occurred on waitForService" } } var service: IBinder? = null From cbe69767f238809336727763093342856d83c13b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 14 Apr 2026 16:28:47 +0300 Subject: [PATCH 100/162] Reorganize the Logcat class --- .../frknkrc44/hma_oss/zygote/util/Logcat.kt | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index 7048946fe..444ac5cce 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -12,6 +12,37 @@ import java.util.Locale object Logcat { private var logdReady: Boolean? = null + fun logV(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.VERBOSE, tag, cause, msg) + + fun logD(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.DEBUG, tag, cause, msg) + + fun logI(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.INFO, tag, cause, msg) + + fun logW(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.WARN, tag, cause, msg) + + fun logE(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.ERROR, tag, cause, msg) + + @JvmStatic + fun logILegacy(tag: String, msg: String, cause: Throwable?) = logI(tag, cause) { msg } + + @JvmStatic + fun logELegacy(tag: String, msg: String, cause: Throwable?) = logE(tag, cause) { msg } + + fun logWithLevel(level: Int, tag: String, cause: Throwable? = null, msg: () -> String) { + if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return + if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return + if (level == Log.VERBOSE && !BuildConfig.DEBUG) return + + val parsedMsg = parseLog(level, tag, msg(), cause) + + HMAService.instance?.apply { + executor.execute { + addLog(parsedMsg) + println(parsedMsg) + } + } ?: println(parsedMsg) + } + private fun parseLog(level: Int, tag: String, msg: String, cause: Throwable? = null) = buildString { val levelStr = when (level) { Log.VERBOSE -> "VERBS" @@ -28,20 +59,6 @@ object Logcat { if (!endsWith('\n')) append('\n') } - fun logWithLevel(level: Int, tag: String, cause: Throwable? = null, msg: () -> String) { - if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return - if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return - if (level == Log.VERBOSE && !BuildConfig.DEBUG) return - - val parsedMsg = parseLog(level, tag, msg(), cause) - - HMAService.instance?.apply { - executor.execute { - addLog(parsedMsg) - println(parsedMsg) - } - } ?: println(parsedMsg) - } private fun println(msg: String) { if (logdReady == null) { @@ -52,20 +69,4 @@ object Logcat { Log.i("HMA-OSS", msg) } - - fun logV(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.VERBOSE, tag, cause, msg) - - fun logD(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.DEBUG, tag, cause, msg) - - fun logI(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.INFO, tag, cause, msg) - - fun logW(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.WARN, tag, cause, msg) - - fun logE(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.ERROR, tag, cause, msg) - - @JvmStatic - fun logILegacy(tag: String, msg: String, cause: Throwable?) = logI(tag, cause) { msg } - - @JvmStatic - fun logELegacy(tag: String, msg: String, cause: Throwable?) = logE(tag, cause) { msg } } From 3ef2f61fa6dadb15080983b8ab417b6365400bbf Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 15 Apr 2026 08:49:05 +0300 Subject: [PATCH 101/162] Try to fix system app checks --- .../org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 16 ++++++++++------ .../hma_oss/zygote/service/HMAService.kt | 9 +++++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 303309c6e..5f8de0a96 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -140,10 +140,10 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { findAltMethod( listOf(IMM_SERVICE_CLASS), listOf("getEnabledInputMethodList", "getEnabledInputMethodListInternal"), - )?.let { + )?.let { method -> hookBefore( - it.declaringClass.name, - it.name, + method.declaringClass.name, + method.name, ) { param -> val callingApps = Utils4Zygote.getCallingApps(service) @@ -259,9 +259,11 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { logV(TAG) { "@getInputMethodList*calculator: $callingUid - Calculated: ${calculatedList.map { it.component }}" } val fakeIMInfo = getFakeInputMethodInfo(caller) - - if (!(isIMExists(fakeIMInfo.packageName) && calculatedList.any { it.packageName == fakeIMInfo.packageName })) { - warnNotInstalledKeyboard("getInputMethodList*calculator", fakeIMInfo.packageName) + val imExists = isIMExists(fakeIMInfo.packageName) + if (!(imExists && calculatedList.any { it.packageName == fakeIMInfo.packageName })) { + if (!imExists) { + warnNotInstalledKeyboard("getInputMethodList*calculator", fakeIMInfo.packageName) + } if (!calculatedList.any { it.packageName == fakeIMInfo.packageName }) { return (calculatedList + fakeIMInfo).sortedWith { info1, info2 -> @@ -274,6 +276,8 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun isIMExists(packageName: String, inUserId: Int? = null): Boolean { + if (packageName in service.systemApps) return true + val userId = inUserId ?: Binder.getCallingUserHandle().hashCode() return Utils.binderLocalScope { Utils.getPackageUidCompat(service.pms, packageName, PackageManager.MATCH_ALL.toLong(), userId) >= 0 diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 3073099c3..ad8ff3cd4 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -3,6 +3,7 @@ package org.frknkrc44.hma_oss.zygote.service import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.IPackageManager +import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.os.UserHandle @@ -191,8 +192,12 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } private fun installHooks() { - getInstalledApplicationsCompat(pms, 0, 0).mapNotNullTo(systemApps) { appInfo -> - if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) appInfo.packageName else null + getInstalledApplicationsCompat(pms, PackageManager.MATCH_ALL.toLong(), 0) + .mapNotNullTo(systemApps) { appInfo -> + val isSystemApp = appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0 || + appInfo.flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0 + + if (isSystemApp) appInfo.packageName else null } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { From 18a681537a829f3652c7b0d87ba7208768a65b7a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 15 Apr 2026 08:59:06 +0300 Subject: [PATCH 102/162] Try to fix accessibility hook behavior --- .../java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 7f0041376..784e0892c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -82,7 +82,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { ): List { logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $callingApps - Current: $inList" } - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } ?: return inList + val caller = callingApps.firstOrNull { service.isHookEnabled(it) } ?: return inList val calculatedList = inList.filter { asInfo -> !service.shouldHide(caller, Utils.getPackageNameFromResolveInfo(asInfo.resolveInfo)) From f4fcea6200cc9cdcb1052a8081776b9c6298e260 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 15 Apr 2026 09:29:33 +0300 Subject: [PATCH 103/162] Try to improve the accessibility hook performance --- .../frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 784e0892c..42926ae93 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -23,6 +23,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { ) { param -> val callingApps = Utils4Zygote.getCallingApps(service) if (callingApps.isEmpty()) return@hookAfter + val caller = callingApps.firstOrNull { service.isHookEnabled(it) } ?: return@hookAfter val currentResult = param.result ?: return@hookAfter val returnsParcel = "Parcel" in param.returnType.simpleName @@ -32,7 +33,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { currentResult as List } - val calculatedList = calculateReturnedAccessibilityList(callingApps, inList) + val calculatedList = calculateReturnedAccessibilityList(caller, inList) param.result = if (returnsParcel) { ParceledListSlice(calculatedList) } else { @@ -77,12 +78,10 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { } private fun calculateReturnedAccessibilityList( - callingApps: Array, + caller: String, inList: List, ): List { - logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $callingApps - Current: $inList" } - - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } ?: return inList + logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Current: $inList" } val calculatedList = inList.filter { asInfo -> !service.shouldHide(caller, Utils.getPackageNameFromResolveInfo(asInfo.resolveInfo)) From cc8e2f98a48b3aaf3bdf006957cc33309768e30e Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 15 Apr 2026 09:31:02 +0300 Subject: [PATCH 104/162] Move calculateReturnedAccessibilityList functions into the hook --- .../hma_oss/zygote/hook/AccessibilityHook.kt | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index 42926ae93..ae301ca0a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -33,7 +33,14 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { currentResult as List } - val calculatedList = calculateReturnedAccessibilityList(caller, inList) + logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Current: $inList" } + + val calculatedList = inList.filter { asInfo -> + !service.shouldHide(caller, Utils.getPackageNameFromResolveInfo(asInfo.resolveInfo)) + } + + logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Calculated: $calculatedList" } + param.result = if (returnsParcel) { ParceledListSlice(calculatedList) } else { @@ -77,21 +84,6 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { } } - private fun calculateReturnedAccessibilityList( - caller: String, - inList: List, - ): List { - logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Current: $inList" } - - val calculatedList = inList.filter { asInfo -> - !service.shouldHide(caller, Utils.getPackageNameFromResolveInfo(asInfo.resolveInfo)) - } - - logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Calculated: $calculatedList" } - - return calculatedList - } - private fun callerIsSpoofed(caller: String) = service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) } From 8bc0ec0e8fe7db340d6322c6ea18328483c6136a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Wed, 15 Apr 2026 09:33:47 +0300 Subject: [PATCH 105/162] Remove getInstalledAccessibilityServiceList hook --- .gitignore | 2 ++ .../hma_oss/zygote/hook/AccessibilityHook.kt | 35 ------------------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index bd436ac56..257b15f0c 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,5 @@ lint/tmp/ updates/ translators.json + +.kotlin/ diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index ae301ca0a..d0a573a50 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -2,12 +2,10 @@ package org.frknkrc44.hma_oss.zygote.hook import android.accessibilityservice.AccessibilityServiceInfo import android.content.pm.ParceledListSlice -import icu.nullptr.hidemyapplist.common.Utils import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS @@ -16,38 +14,6 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { override fun load() { BulkHooker.instance.apply { - @Suppress("UNCHECKED_CAST") - hookAfter( - ACCESSIBILITY_SERVICE_CLASS, - "getInstalledAccessibilityServiceList", - ) { param -> - val callingApps = Utils4Zygote.getCallingApps(service) - if (callingApps.isEmpty()) return@hookAfter - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } ?: return@hookAfter - - val currentResult = param.result ?: return@hookAfter - val returnsParcel = "Parcel" in param.returnType.simpleName - val inList = if (returnsParcel) { - (currentResult as ParceledListSlice).list - } else { - currentResult as List - } - - logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Current: $inList" } - - val calculatedList = inList.filter { asInfo -> - !service.shouldHide(caller, Utils.getPackageNameFromResolveInfo(asInfo.resolveInfo)) - } - - logV(TAG) { "@getInstalledAccessibilityServiceList*calculator: $caller - Calculated: $calculatedList" } - - param.result = if (returnsParcel) { - ParceledListSlice(calculatedList) - } else { - calculatedList - } - } - hookBefore( ACCESSIBILITY_SERVICE_CLASS, "getEnabledAccessibilityServiceList", @@ -78,7 +44,6 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { param.result = 0L - // service.increasePMFilterCount(caller) } } } From bb038aa256a790b7d4e940234f384be068e409c0 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 17 Apr 2026 12:41:03 +0300 Subject: [PATCH 106/162] Move enableInternet to PrefManager --- .../hidemyapplist/service/ConfigManager.kt | 16 -------------- .../hidemyapplist/service/PrefManager.kt | 22 +++++++++++++++++++ .../ui/fragment/SettingsFragment.kt | 5 ++--- .../hma_oss/ui/fragment/AboutFragment.kt | 3 +-- .../hma_oss/ui/fragment/HomeFragment.kt | 8 +++---- .../hidemyapplist/common/JsonConfig.kt | 10 --------- 6 files changed, 29 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 80cc23108..163b46834 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -3,7 +3,6 @@ package icu.nullptr.hidemyapplist.service import android.os.Build import android.util.Log import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp -import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast @@ -151,21 +150,6 @@ object ConfigManager { showToast(R.string.settings_need_reboot) } - var enableInternet: Int - get() = config.enableInternet - set(value) { - config.enableInternet = value - saveConfig() - } - - fun setEnableInternet(value: Boolean) { - enableInternet = if (value) { - Constants.ENABLE_INTERNET_ON - } else { - Constants.ENABLE_INTERNET_OFF - } - } - fun importConfig(json: String) { config = JsonConfig.parse(json) config.configVersion = BuildConfig.CONFIG_VERSION diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt index d02b4970a..05030e005 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/PrefManager.kt @@ -6,6 +6,7 @@ import android.content.pm.PackageManager import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.edit import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp +import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.data.AppConstants import icu.nullptr.hidemyapplist.ui.util.get import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent @@ -25,6 +26,7 @@ object PrefManager { private const val PREF_BYPASS_RISKY_PACKAGE_WARNING = "bypass_risky_package_warning" + private const val PREF_ENABLE_INTERNET = "enable_internet" private const val PREF_DISABLE_UPDATE = "disable_update" private const val PREF_APP_FILTER_SHOW_SYSTEM = "app_filter_show_system" @@ -93,6 +95,26 @@ object PrefManager { get() = pref.getBoolean(PREF_BYPASS_RISKY_PACKAGE_WARNING, false) set(value) = pref.edit { putBoolean(PREF_BYPASS_RISKY_PACKAGE_WARNING, value) } + /** + * Enable/disable the Internet connection in the manager app + * + * States: + * - ENABLE_INTERNET_UNKNOWN - The user didn't pass the dialog yet + * - ENABLE_INTERNET_ON - The user granted the Internet permission + * - ENABLE_INTERNET_OFF - The user rejected the Internet permission + */ + var enableInternet: Int + get() = pref.getInt(PREF_ENABLE_INTERNET, Constants.ENABLE_INTERNET_UNKNOWN) + set(value) = pref.edit { putInt(PREF_ENABLE_INTERNET, value) } + + fun setEnableInternet(value: Boolean) { + enableInternet = if (value) { + Constants.ENABLE_INTERNET_ON + } else { + Constants.ENABLE_INTERNET_OFF + } + } + var disableUpdate: Boolean get() = pref.getBoolean(PREF_DISABLE_UPDATE, false) set(value) = pref.edit { putBoolean(PREF_DISABLE_UPDATE, value) } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt index 3fe8f25cb..17dd89851 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt @@ -25,7 +25,6 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.PropertyUtils import icu.nullptr.hidemyapplist.service.ConfigManager -import icu.nullptr.hidemyapplist.service.ConfigManager.setEnableInternet import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient import icu.nullptr.hidemyapplist.ui.util.enabledString @@ -100,7 +99,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen "skipSystemAppDataIsolation" -> ConfigManager.skipSystemAppDataIsolation "disableActivityLaunchProtection" -> ConfigManager.disableActivityLaunchProtection "forceMountData" -> ConfigManager.forceMountData - "enableInternet" -> ConfigManager.enableInternet == Constants.ENABLE_INTERNET_ON + "enableInternet" -> PrefManager.enableInternet == Constants.ENABLE_INTERNET_ON "disableUpdate" -> PrefManager.disableUpdate "packageQueryWorkaround" -> ConfigManager.packageQueryWorkaround else -> throw IllegalArgumentException("Invalid key: $key") @@ -139,7 +138,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen "detailLog" -> ConfigManager.detailLog = value "errorOnlyLog" -> ConfigManager.errorOnlyLog = value "forceMountData" -> ConfigManager.forceMountData = value - "enableInternet" -> setEnableInternet(value) + "enableInternet" -> PrefManager.setEnableInternet(value) "disableUpdate" -> PrefManager.disableUpdate = value "hideIcon" -> PrefManager.hideIcon = value "bypassRiskyPackageWarning" -> PrefManager.bypassRiskyPackageWarning = value diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt index e9e1e18e0..4919e6f01 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt @@ -16,7 +16,6 @@ import androidx.transition.TransitionManager import com.bumptech.glide.Glide import dev.androidbroadcast.vbpd.viewBinding import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.ui.util.AccessibilityUtils import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor @@ -173,7 +172,7 @@ class AboutFragment : Fragment(R.layout.fragment_about) { fun addTranslatorItem(layout: LinearLayout, avatarUrl: String, name: String) { val newLayout = FragmentAboutListItemBinding.inflate(layoutInflater) - if (ConfigManager.enableInternet == Constants.ENABLE_INTERNET_ON) { + if (PrefManager.enableInternet == Constants.ENABLE_INTERNET_ON) { Glide.with(this) .load(avatarUrl) .placeholder(R.drawable.outline_info_24) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 922dcc0cd..dc56530c5 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -361,7 +361,7 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } private fun loadDialogs() { - if (ConfigManager.enableInternet == Constants.ENABLE_INTERNET_UNKNOWN) { + if (PrefManager.enableInternet == Constants.ENABLE_INTERNET_UNKNOWN) { loadEnableInternetDialog() return } @@ -375,17 +375,17 @@ class HomeFragment : Fragment(R.layout.fragment_home) { .setTitle(R.string.settings_enable_internet) .setMessage(R.string.settings_enable_internet_summary) .setPositiveButton(R.string.yes) { _, _ -> - ConfigManager.enableInternet = Constants.ENABLE_INTERNET_ON + PrefManager.enableInternet = Constants.ENABLE_INTERNET_ON loadUpdateDialog() } .setNegativeButton(R.string.no) { _, _ -> - ConfigManager.enableInternet = Constants.ENABLE_INTERNET_OFF + PrefManager.enableInternet = Constants.ENABLE_INTERNET_OFF } .show() } private fun loadUpdateDialog() { - if (ConfigManager.enableInternet != Constants.ENABLE_INTERNET_ON || + if (PrefManager.enableInternet != Constants.ENABLE_INTERNET_ON || hmaApp.updateDialogSkipped || PrefManager.disableUpdate || isTestBuild) { return } diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt index fbe398221..5c0a59a69 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt @@ -71,16 +71,6 @@ data class JsonConfig( */ var packageQueryWorkaround: Boolean = false, - /** - * Enable/disable the Internet connection in the manager app - * - * States: - * - ENABLE_INTERNET_UNKNOWN - The user didn't pass the dialog yet - * - ENABLE_INTERNET_ON - The user granted the Internet permission - * - ENABLE_INTERNET_OFF - The user rejected the Internet permission - */ - var enableInternet: Int = ENABLE_INTERNET_UNKNOWN, - val templates: MutableMap = mutableMapOf(), val settingsTemplates: MutableMap = mutableMapOf(), From 2a5d37bfc1fea94b819654d9500f10b8903e3ccf Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 17 Apr 2026 12:42:30 +0300 Subject: [PATCH 107/162] Replace if with when in HomeFragment --- .../hma_oss/ui/fragment/HomeFragment.kt | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index dc56530c5..37b95a246 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -135,45 +135,49 @@ class HomeFragment : Fragment(R.layout.fragment_home) { val backgroundDrawable = GradientDrawable() backgroundDrawable.setColor(homeItemBackgroundColor()) - if (i == 0) { - backgroundDrawable.setCornerRadii( - floatArrayOf( - softCorner, - softCorner, - softCorner, - softCorner, - squareCorner, - squareCorner, - squareCorner, - squareCorner + when (i) { + 0 -> { + backgroundDrawable.setCornerRadii( + floatArrayOf( + softCorner, + softCorner, + softCorner, + softCorner, + squareCorner, + squareCorner, + squareCorner, + squareCorner + ) ) - ) - } else if (i == childCount - 1) { - backgroundDrawable.setCornerRadii( - floatArrayOf( - squareCorner, - squareCorner, - squareCorner, - squareCorner, - softCorner, - softCorner, - softCorner, - softCorner + } + childCount - 1 -> { + backgroundDrawable.setCornerRadii( + floatArrayOf( + squareCorner, + squareCorner, + squareCorner, + squareCorner, + softCorner, + softCorner, + softCorner, + softCorner + ) ) - ) - } else { - backgroundDrawable.setCornerRadii( - floatArrayOf( - squareCorner, - squareCorner, - squareCorner, - squareCorner, - squareCorner, - squareCorner, - squareCorner, - squareCorner + } + else -> { + backgroundDrawable.setCornerRadii( + floatArrayOf( + squareCorner, + squareCorner, + squareCorner, + squareCorner, + squareCorner, + squareCorner, + squareCorner, + squareCorner + ) ) - ) + } } val ripple = attrDrawable(android.R.attr.selectableItemBackground) From fa4bb79b3843bf04b335d128208daeb4670f807a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 17 Apr 2026 13:05:55 +0300 Subject: [PATCH 108/162] Fix log parsing --- .../main/java/icu/nullptr/hidemyapplist/adapter/LogAdapter.kt | 2 +- .../src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/adapter/LogAdapter.kt b/app/src/main/java/icu/nullptr/hidemyapplist/adapter/LogAdapter.kt index 3d1d39307..36324851d 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/adapter/LogAdapter.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/adapter/LogAdapter.kt @@ -23,7 +23,7 @@ class LogAdapter(context: Context) : RecyclerView.Adapter companion object { private val debugLevels = arrayOf("DEBUG", "VERBS") - private val pattern = Pattern.compile("\\[ ?(.*)] (.*) \\((.*?)\\) (.*)", Pattern.DOTALL) + private val pattern = Pattern.compile("\\[ ?(.*)] <(.*)> \\((.*?)\\) (.*)", Pattern.DOTALL) fun parseLog(text: String): LogItem? { val matcher = pattern.matcher(text) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt index 444ac5cce..53e878ddb 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Logcat.kt @@ -53,7 +53,7 @@ object Logcat { else -> "?WTF?" } val date = SimpleDateFormat("MM-dd HH:mm:ss", Locale.getDefault()).format(Date()) - append("[$levelStr] $date ($tag) $msg") + append("[$levelStr] <$date> ($tag) $msg") if (!endsWith('\n')) append('\n') if (cause != null) append(Log.getStackTraceString(cause)) if (!endsWith('\n')) append('\n') From b1e969acb3799ebe23aca4041b8097694276a3fe Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 17 Apr 2026 19:51:01 +0300 Subject: [PATCH 109/162] Try to fix isCallerInstallerOfRecord hook --- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 7df637681..d67fb4622 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -23,6 +23,8 @@ import java.util.concurrent.atomic.AtomicReference abstract class PmsHookTargetBase(protected val service: HMAService) : IFrameworkHook { + private val androidPkgClazzNames = arrayOf("AndroidPackage", "PackageImpl") + protected var lastFilteredApp: AtomicReference = AtomicReference(null) protected val psPackageInfo by lazy { @@ -115,7 +117,9 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework val callingUid = param.args.last { it is Int } as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val pkg = param.args[1] ?: return@hookBefore + val pkg = param.args.lastOrNull { + it?.javaClass?.simpleName in androidPkgClazzNames + } ?: return@hookBefore val query = callMethod( pkg, if (pkg.javaClass.simpleName == "PackageImpl") { From 18a478df390e68c321d33c33875590025c6e72be Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 18 Apr 2026 21:00:13 +0300 Subject: [PATCH 110/162] Try to implement FD read/write --- .../hidemyapplist/service/ConfigManager.kt | 10 +++++- .../hidemyapplist/service/ServiceClient.kt | 27 ++++++++++++++-- .../hidemyapplist/ui/fragment/LogsFragment.kt | 27 +++++++++++----- app/src/main/res/layout/fragment_logs.xml | 7 +++++ app/src/main/res/values/arrays.xml | 4 +++ .../hidemyapplist/common/IHMAService.aidl | 4 +++ .../nullptr/hidemyapplist/common/Constants.kt | 3 ++ .../hidemyapplist/common/JsonConfig.kt | 1 - .../hma_oss/zygote/service/HMAService.kt | 31 +++++++++++++++++++ 9 files changed, 103 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 163b46834..f0a1fa68e 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -1,8 +1,10 @@ package icu.nullptr.hidemyapplist.service import android.os.Build +import android.os.ParcelFileDescriptor import android.util.Log import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp +import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast @@ -71,8 +73,14 @@ object ConfigManager { fun saveConfig() { val text = config.toString() - ServiceClient.writeConfig(text) configFile.writeText(text) + + try { + ServiceClient.writeConfig(text) + } catch (_: Throwable) { + val parcelFD = ParcelFileDescriptor.open(configFile, ParcelFileDescriptor.MODE_READ_ONLY) + ServiceClient.writeFD(Constants.PARCEL_TYPE_CONFIG, parcelFD) + } } var detailLog: Boolean diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt index 1d59c7077..725e30364 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ServiceClient.kt @@ -2,8 +2,11 @@ package icu.nullptr.hidemyapplist.service import android.os.Bundle import android.os.IBinder +import android.os.ParcelFileDescriptor import android.util.Log +import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.IHMAService +import java.io.FileInputStream import java.lang.reflect.InvocationHandler import java.lang.reflect.Method import java.lang.reflect.Proxy @@ -44,7 +47,14 @@ object ServiceClient : IHMAService, IBinder.DeathRecipient { override fun getFilterCount() = service?.filterCount ?: 0 - override fun getLogs() = service?.logs + override fun getLogs(): String? { + val parcelFD = readFD(Constants.PARCEL_TYPE_LOG) ?: return service?.logs + val readStream = FileInputStream(parcelFD.fileDescriptor) + return readStream.readBytes().decodeToString().also { + readStream.close() + parcelFD.close() + } + } override fun clearLogs() { service?.clearLogs() @@ -57,7 +67,14 @@ object ServiceClient : IHMAService, IBinder.DeathRecipient { override fun getPackagesForPreset(presetName: String) = service?.getPackagesForPreset(presetName) - override fun readConfig() = service?.readConfig() + override fun readConfig(): String? { + val parcelFD = service?.readFD(Constants.PARCEL_TYPE_CONFIG) ?: return service?.readConfig() + val readStream = FileInputStream(parcelFD.fileDescriptor) + return readStream.readBytes().decodeToString().also { + readStream.close() + parcelFD.close() + } + } override fun writeConfig(json: String) { service?.writeConfig(json) @@ -109,4 +126,10 @@ object ServiceClient : IHMAService, IBinder.DeathRecipient { } catch (_: Throwable) { null } override fun getLoadedHooks() = service?.loadedHooks + + override fun readFD(type: Int) = service?.readFD(type) + + override fun writeFD(type: Int, fd: ParcelFileDescriptor) { + service?.writeFD(type, fd) + } } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt index 54900d801..473fed91a 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt @@ -4,11 +4,13 @@ import android.os.Bundle import android.view.MenuItem import android.view.View import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.MyApp import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient @@ -56,18 +58,22 @@ class LogsFragment : Fragment(R.layout.fragment_logs) { } private fun updateLogs() { - lifecycleScope.launch { + binding.serviceOff.isVisible = ServiceClient.serviceVersion <= 0 + + if (binding.serviceOff.isVisible) return + + binding.loadingIndicator.isVisible = true + + MyApp.hmaApp.globalScope.launch { logCache = try { ServiceClient.logs } catch (_: Throwable) { - "[ERROR] 01-01 01:01:01 (${getString(R.string.app_name)}) Cannot read logs due to Binder issues, try reading ${ServiceClient.logFileLocation} manually" + "[ERROR] <01-01 01:01:01> (${getString(R.string.app_name)}) Cannot read logs due to Binder issues, try reading ${ServiceClient.logFileLocation} manually" } + val raw = logCache?.split("\n") - if (raw == null) { - binding.serviceOff.visibility = View.VISIBLE - } else { - binding.serviceOff.visibility = View.GONE - adapter.logs = buildList { + if (raw != null) { + val logList = buildList { val cur = StringBuilder() for (line in raw) { if (line.startsWith('[')) { @@ -85,11 +91,18 @@ class LogsFragment : Fragment(R.layout.fragment_logs) { } if (!PrefManager.logFilter_reverseOrder) reverse() } + + lifecycleScope.launch { + binding.loadingIndicator.visibility = View.INVISIBLE + adapter.logs = logList + } } } } private fun onMenuOptionSelected(item: MenuItem) { + if (binding.loadingIndicator.isVisible) return + when (item.itemId) { R.id.menu_refresh -> updateLogs() R.id.menu_save -> { diff --git a/app/src/main/res/layout/fragment_logs.xml b/app/src/main/res/layout/fragment_logs.xml index f17cdd202..63157f2fc 100644 --- a/app/src/main/res/layout/fragment_logs.xml +++ b/app/src/main/res/layout/fragment_logs.xml @@ -15,6 +15,13 @@ android:layout_width="match_parent" android:layout_height="?actionBarSize" android:elevation="0dp" /> + + 256K 512K 1M + 4M + 8M 256 512 1024 + 4096 + 8192 diff --git a/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl b/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl index 72df034d8..a50a79447 100644 --- a/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl +++ b/common/src/main/aidl/icu/nullptr/hidemyapplist/common/IHMAService.aidl @@ -43,4 +43,8 @@ interface IHMAService { String getServiceVersionName() = 18; String[] getLoadedHooks() = 19; + + ParcelFileDescriptor readFD(int type) = 20; + + void writeFD(int type, in ParcelFileDescriptor fd) = 21; } diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt index 6ac4eb26d..c245934b8 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt @@ -27,6 +27,9 @@ object Constants { const val ENABLE_INTERNET_OFF = 1 const val ENABLE_INTERNET_ON = 2 + const val PARCEL_TYPE_LOG = 0 + const val PARCEL_TYPE_CONFIG = 1 + /** * Defines the GID for the group that allows write access to the internal media storage. */ diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt index 5c0a59a69..15a619c83 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/JsonConfig.kt @@ -1,6 +1,5 @@ package icu.nullptr.hidemyapplist.common -import icu.nullptr.hidemyapplist.common.Constants.ENABLE_INTERNET_UNKNOWN import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index ad8ff3cd4..5ce9c3838 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -6,11 +6,15 @@ import android.content.pm.IPackageManager import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.os.ParcelFileDescriptor +import android.os.RemoteException import android.os.UserHandle import android.provider.Settings import android.util.Log import icu.nullptr.hidemyapplist.common.AppPresets import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Constants.PARCEL_TYPE_CONFIG +import icu.nullptr.hidemyapplist.common.Constants.PARCEL_TYPE_LOG import icu.nullptr.hidemyapplist.common.FilterHolder import icu.nullptr.hidemyapplist.common.IHMAService import icu.nullptr.hidemyapplist.common.JsonConfig @@ -48,6 +52,7 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.UserManagerApis import java.io.File +import java.io.FileInputStream import java.lang.reflect.Modifier import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -613,4 +618,30 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { return hookList.toTypedArray() } + + override fun readFD(type: Int): ParcelFileDescriptor { + return when (type) { + PARCEL_TYPE_LOG -> { + ParcelFileDescriptor.open(logFile, ParcelFileDescriptor.MODE_READ_ONLY) + } + PARCEL_TYPE_CONFIG -> { + ParcelFileDescriptor.open(configFile, ParcelFileDescriptor.MODE_READ_ONLY) + } + else -> throw RemoteException("Invalid type for read: $type") + } + } + + override fun writeFD(type: Int, fd: ParcelFileDescriptor) { + val receiveStream = FileInputStream(fd.fileDescriptor) + + when (type) { + PARCEL_TYPE_CONFIG -> { + writeConfig(receiveStream.readBytes().decodeToString()) + } + else -> throw RemoteException("Invalid type for write: $type") + } + + receiveStream.close() + fd.close() + } } From 440dfaac52356e62872758c92fdd510889921704 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 18 Apr 2026 22:05:40 +0300 Subject: [PATCH 111/162] Send config to the backend before saving into app --- .../java/icu/nullptr/hidemyapplist/service/ConfigManager.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index f0a1fa68e..9c6325337 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -73,7 +73,6 @@ object ConfigManager { fun saveConfig() { val text = config.toString() - configFile.writeText(text) try { ServiceClient.writeConfig(text) @@ -81,6 +80,8 @@ object ConfigManager { val parcelFD = ParcelFileDescriptor.open(configFile, ParcelFileDescriptor.MODE_READ_ONLY) ServiceClient.writeFD(Constants.PARCEL_TYPE_CONFIG, parcelFD) } + + configFile.writeText(text) } var detailLog: Boolean From 79ff3d96036cd65a88524d9e91934caa19ce882b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 19 Apr 2026 13:32:56 +0300 Subject: [PATCH 112/162] Add "Nuko" app icon by OukaroMF --- app/src/main/AndroidManifest.xml | 12 ++++ .../hidemyapplist/data/AppConstants.kt | 2 + .../drawable/ic_launcher_alt_5_foreground.xml | 54 ++++++++++++++++++ .../mipmap-anydpi-v26/ic_launcher_alt_5.xml | 6 ++ .../ic_launcher_alt_5_foreground.webp | Bin 0 -> 1120 bytes .../ic_launcher_alt_5_foreground.webp | Bin 0 -> 726 bytes .../ic_launcher_alt_5_foreground.webp | Bin 0 -> 1582 bytes .../ic_launcher_alt_5_foreground.webp | Bin 0 -> 2730 bytes .../ic_launcher_alt_5_foreground.webp | Bin 0 -> 4170 bytes app/src/main/res/values/colors.xml | 1 + 10 files changed, 75 insertions(+) create mode 100644 app/src/main/res/drawable/ic_launcher_alt_5_foreground.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_5.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_alt_5_foreground.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_alt_5_foreground.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_alt_5_foreground.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_alt_5_foreground.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_alt_5_foreground.webp diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 543b8549b..f8d68b73c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -70,6 +70,18 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_5.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_5.xml new file mode 100644 index 000000000..aea5f6b1f --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_5.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_alt_5_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_alt_5_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..dfa20a216c018d27bc4b813c0a73724c37718f9b GIT binary patch literal 1120 zcmV-m1fTm-Nk&Fk1ONb6MM6+kP&iCW1ONapp+G1Q70H#he{q#Rnk??_?(XjH?(XjH z$KCzhtz`qVKOBA~UeR#@S~(rFHSSL5u8UoTLvqGoyWg-ufFbJiM5D=3nE(g|x^JP$xqQ*jLdZXA{Ug zQA#Oht$+m)B)BwVuKAllc8`*Jb5aji5=d}tJXgNLh`~jxbw3sS39z%O_WyuULyNZS zK}Pr~Uv~7mm_Xi$!qadx{<|9?27ud*=K3L}ONGEe`T%)VXT#M9EP@KpVu2A-05DZO z92GEDHUZ5lvp2|)$=h%-Gyo^98UR;QO3t#0e``+B(j#P~{QwYBY&M4#hG;kc0zg=J zvkm~J+20QT@7s!28XIo|X2;-OSmzqPg&|IcJ&HCzM1wh}O_WT)u!~*+0flQY1GncJ z_SoT|M-j#DU}({}oi>zALg7bfab5-hco%Ml0ej#08>$v;T=p-Ze5GfD4YzOJj*_s; z00bJ2Mf{sLUIEG{px0)u1AA}UqHJ|341s$4_Bs$i50Bw_4`?^H0?@2pg+Z}bGAT*3 zN&#Sw_bJw?9)?4q$`gJOK@Smf8%kFIjc%p_fP}cY#pg9D*vs2Nyu-O@v*=U1P+kWL2=$25bs=3EEViO(ra)N>*W(CD5n%bpNDJR{lJP zQs|Qm5mW8I9GZRa)-~TWGJGFs&t&=c^s34Hg$x2(&2&MN0h&`d=NoKRl?q&RmYL*$ z<{8Xed<>95r#z=pWRX+R1dMv{IEJ19@{zMIQmPF6#+>xHx8gBlOY1d$7Hu z50{v&Hu~t`HF*7?kAQk>qhpK)>obVj~X=*tS_u*O7-aBW1|?7*UYNl4+_Z+b{Ak=bPa<_K!XS+NCxt9PB@N zSU{)ftaXe+9v09nfwlAOKY939(V3rVf62p~1ubLkn@XP7IZ)7JUa8b!PLH6bhnv18 z2!~9y0tZNh2_r1hnJ|H2k8nd&%z4b654)bdX mj(O14{BUQA{c=2QLK|j2kPI3DZQ^gXG^N>K6k;KHW`jxerE6w7xv3hOusOIVBBv=cvvbG6INr2-x z_gmK}yy5Gkb|!{LR&80^>LQuC)TK!g!uB2UzAz>|Igz#yO1^;Lz8EcI*mBEuWbL zk(r1%E6a?R)bg28OQ_hOAb>-OKtLEQ6a)(h3Zlx0DJ6h`Ar%M;Virg&1cHJ9W{HAe zVPQcayewWV%Dv&bKRo;Ax<1@K7hbUc?*GI8@#){|K6b9#`WL(HecM2`ZQG{htg>y} zwr#sAcFMNxbI;X`lS;n!prx(#R!NKK{{+x~96tR18y~sx3Jma+!8fb1XZ*$UvA)*) zcsJ(Uat2SKY5mZd;lf#X!x{8%*M;&G+oi&&bs&u^?7&qET{$?Uz{w3yoAjT zlNkzri%*}$2zm|k8S;N3iTjWd<&HDz(08-Edw9iJu|6EHZS8Ruxvx(@M;;@RP?c4Z z#5qY^+a;m&4N2VFB%!4Dl2DlSl>9~#%H5H~wd7V1@~Tw?A>VpM5b~+H7KFS? z4+J6Cymx{Sr4FltP+aAvAmozSugF0ZUGPkmgD9r_sZ|c5u)@(ZIf(qSTfWOdM88CN Icy#Dr*v}ekqyPW_ literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_alt_5_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_alt_5_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..500ce1fa4dfb38ddbe15c493125265553eed1930 GIT binary patch literal 1582 zcmV+}2GRLaNk&E{1^@t8MM6+kP&iB(1^@sr*T6Lp^@iHEZ6s;`vGbg-x+^1M0(f7| zSwjjJRPv?={<>`0woTia(bl!?dt=+SZQHhO8=uRwZl%_U&y1dJ^AEhM&TE{<72CE6 zHL`8lN}s(qlf$CP7Boqa1a1h6Z6iriDgz!15Ax5EX<3jYo3>@!w(T$5wr$(CZQFdd zZQHi7&slq~nE*M~wkc9YO3q;$8WFJsau(s4+qk>$wpx*z4RjrH?`-N2xp!0%kxNG( zTz7Z(+v7%(B&kg=R08G=@-+XfB1vi`0dKgXaFreK_iW_Q6TnXYJ4fI1A#h+5R3#jAx6j$vV;U7NU%UbFcHEUdj5o^v7t1vFUvVukn<(tda1fmI48OFCY`Gzkg;S#&sS@YaZ#pV+MX*LNKB&=^ z-a-m~--g*Vk&`Kc$%FW|4cTG}O2{XdycJbW1iXGJZF`+W87LIIUfN1%Uj7;{7Xo!P zR<5!L^e-yxjBJ#qFHua6ZCHu*l@l!hmg5p5RF_1CP){()k~>!Q(oZEeQAd#inU)hO zi9-$Rt0&=-M6jjR^4Nvve84)O!cG=v1dAD090Y@(iq^=$rNE(%bUt9808plUvVq%glY0+t_hL%46Ag0Akg z=K^sk#h!k22q4~YD3&4(ub#dD#KCJW5z^CaIY_k>S=2-d0KPnaAOP57GK84o8bzJ< zi%F3D^*FA!Q}ugPPZ@+Jp5kAzU-U%qWj==`z#o`HHBcj{Fz7qxJ=iwsEs!U7#7bOG zrAPtY=ez`Jp)zD5T`|5Wnana|B3m{704QuNJPG|PE|nW5a@B(XusWOGxr1`!c(wS4 zDJerHGL_HIa>Wht(($TXA%qHCS5YCjQ`#0P1hd5;Dr`|cc7cF+RYG#c>i!9%G##h* zg#^5bVAZlk^}C=mLab6E1i*5Ey6^5$2nc~U zHt38E!h04?h~{!c$d-#YHYoS9aA*%G>_L35hEUN_FBgwdai!M$*o8r1H|(3%UsR4~ zj$?BgfWrPHbV&#mLNI6Dnb!c6dwOK_Z3q-5c=N`i84W;Tcapm$0u_QcTU?y7Fese7 zoEoHWs1WS&XJUB6psi(S6uy&}htn4Zg}wZK4bu0y z3qT=QL!+ik_a79dR|2VHeMF-`VL~=jT%Wc86xPtl$MYErK)Gk(TBUuMxd0Qs_pomJ z{0b9x1w>|}^xMXS_xh4mul)ywZ+KNg-T1o!6W$v@X1(-v=E9ipUf+tVoL)~`fC;lz z9);t@IZ#+bFT=Sys$o#>5fbsWt9zr_kT8296i!Q{`Z0YlCQPvT5MJbZ@*Wdr4Xu>t zRPTmtO!$Ted6m+aNeg4bzkIOBbUWCk(GNkwOo)b%T{^uUvnU%9zLx@nl((&x?a%ZD zkT4U>I_{a`Y^O$I!c6dZk(f8`^=fDXBz*5h7g~@#8xiKyIx7CO6o?zG5^a3Lh%mb>q&#s= g$!wjU`!yuY>}vP*wW7j3Ki+Dm|5je)^uLq703!qS0{{R3 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_alt_5_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_alt_5_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..2dcc7221a4a13be307c9895ee2a64526196a7b72 GIT binary patch literal 2730 zcmV;b3RU$|Nk&GZ3IG6CMM6+kP&iDL3IG5vL%~oGHHYH1Z5(<3v9G7y-7g|0KoN3_ zl9}SlFkpke0qkK%b~x99tQz`{d|oNqwk>wEfWj_nX$RdzRTt0|ggJ*X%-L7WO12)4jW2vUzRdNp>|<$cuGrFNW9tKF4d)7t z%~cyXD=94^sERfuAU2YuNY37F#xdhFqky3Bf3%Q9vX#<5015FVz@k3t{ha_h()O>G zlwVcfbM84;+ugl;+}+*X-QC^Y-F3IO8#&1NviU6m>n-3AP6$hI?h0@j-2iT}ZGxB; zOtFCJw0B^U%_e3KL{r4;Mv`bddtd9< zG(omaQSJ}_33;q}UFZh20kQ4r+ zQ&Pcyg8u}-5oL+`L`$MQ(SztkbR^mkjftv+4Q37y-4#|^Dv*nE*Vku#THG`z{?O^>agrrAz!Ept&p zSeu#P9nP&<(X<5{E)rT?chR(mY}=IJa5l4vs0ImxsIGDZ^ z0e9? za6`duVO`luo3P~8i-hKj`Y(|b{xY)(Cm;~^W;T|qOjQDy3gh9G%pW?lCKX`=gI_Ex zFHtEAmc-Oa^_fM(S7F~TAaL7RT&6PTFA%9V7L}vKlM8mLLBLQLkQAX;iIeb(g>_S* zA17_pKmbuUsD2Jy@^-BOun~(F)UI4_4iXjg-!2C?+BcCdG@XD57(x^3(1v{m7{r1D z6(-wO>-C=p6O%lnNN8FP4ON67B!VM1x6BxnA@kYj$TTrp?af{I4U zHa)m{LM0O!YN57-I4y_-V&E=aN0gg8X)PH%2d|<-6}pkq8AL?-pe)S<${@xr2o1MS z4LxU~|H9E$Rgll|qL17T8Eso76e>gn(}qLc%M=`sR2t~GryU$xI%+qsap zXxnWs^Dkw6QAiAqs1YsJ02Z`GB@zqqPfRGf%|e|7vKB3}0ZL=p^~PXn@rqmtI0}LV zY~W%CD=}t3x2ZL!Zm`T0G$;4JTFjv+Z*zSm7-0gO7$qp)v2h2)bq6b<*9=eoPF^4o z5h9}26vYZ6qPQnWf=g_0kt7yLn-Ezj0k~d60*Lm}DeW5?He2`(@? za$Byl_#aw|kOWvb-lLg?K!m1_2|L)r_$c#@8ZPLj(jhn404u(h#RUmCpwzE<3tik9 zdTbJr5j6NJae>m#Kum-|rXWV+UB;1^KoUTYF0mD~cA<-sVT!OomhXmsa)PDTw_mLN zd16z?&;yeo5wNhTRm)FzaZZ#(1)CE^6Wrk8ca1GCeT#n#)rJcY0m5G5@`xoeUB)~5 zBsP70*EvFv6=zP4bYE@Z9CEOe_LX-gL!pVY6*RC?B^{AU29(x+A_M^cD7^9#f8usq`; zHKs@ZT4TJ?#ijk{son6Eum_OTsPwB{h9Z}PF?(G0&v6@wjY{9zNjvJ2@*onMzhD0; zwH2iKPyptT4Y#Q;Rerrkio-r#^D8oe30Uh~z2$ zR78mb(K>-2bC=Wzg4{$gWlZ!si33r|%7e*EY6WHQaupE}@s3(VG_b<4e#@Mu6^w;v z+2kxUNVR0|aKJ%jX8lUPQ8OrSf7#dJFBvU&01iZ}(C}Szp>_}`AUI?|IJg!4m~%%B z@lvO;!v3yhM9`s_NWUFGgsqoC79Ii+dvdt*a0JP8C>5r301*{qKYUhfIgeYAi66qj z!qSGVVAVqWu!Xw5yc{ubJAMq)j4mFL%NOE@Uy?ZAv5cAcVWNo--ZKsWh%HR6luWBH z0uWKgo7s+E2Le)wz~N7}UF4Hx2v&9v~ZpCgw5kYQqA zM5OJ+59i9vC>_e`3-QCdyg1Xi)U_AlhaV2(O|Qnj!cVS5_n2@U*&q!*{E~^`(S*)g zh#&q%W@dzvZ^jR^nbqZ^@Ld4ydaGV4T576^ z_;4=$)NyjFa?(~U%0v&dA+bItlE*fg10N>rOpFW<=T4(N1s~oe(aDo*HLGwhe3(Cw zSY9&a4Ou)5KI~TM8N`pK&9dSm_%I(cu`^DIqZTWI55Ht)jGcFF$1wMjTNj~+`Jjcp zWh1!v$iwhqx5A(xJ*kmOrZ31u4-+;-4eKljj`+60ZbT2WK~%7^J2(>ij%me(TQ33+ zbM7AwZdQn-VZ%N|4>M8e>i{0sOT{A_KY|`Mu2q>H8Lw-WKB~!d@G$2Rb!*y?%N6noYDg=yene$32Rwa!*ZAsw5zvj{xQ zg(`ilY)a;L%~1O`xq18SN-_qVg8xJ#GhJEgV%goHo%*@Qp%+#$|bAta*G`~uQi4S zW+}3JzzP_PxURzPflF|DLT7BB3S7W6V771S1{~cMyw(_MU>Cr*2Zxk9+&$d*6yb};!wtwD6FPz_6`0ApPX&bAojNRkvu-4lMy%*;QO@=j?3Y1`Dv?qB4?q_%A-?gyd> z6-Yn^3ZbxAT42G=^Smd36#py!SNyN|U-7@pzALS(=SPJWIEi*Z08q<70H89^Tq231 zU$hRy*PoJQZP@71GY_s>sPB#|E_~?VC0jRIxokxfEflXpYmJ400yzS{8H^98V!`18 zAI8RTFHg`0jf`BdMb&qIHMQ?xwPYVRe8(gFH^WLdlV^{zQA;epP)}kD z_>UXE?mwz_8YLRD0;+OEiM;IEWR@y3B8p5PQ{OSOY2R5X(am5~#_RkzTB%s7s>_%t z`N)d2NDXHivO~}a3Q5U#WOV^?ULcoIJ=ejg{Gpw2K$o+a6Pe*mjJVKsIT;JnMc@&D zB;>16DhEg5K@^ip&W_}M+eFu1C}T1lND?_Ak|Ryh;dZAW0SS^4d0`>|KW@p=r4rcw z7lT0w_yn=CbfSwE%IK`92)iRilEoP)lu%bLqDhe+@gnDmhyZD078D4BnMo&U%qjiJ z@$qB8lDdp5kymDx?1lJZ9|lUr+ue~W9uYzR$B2QzFblNIU`{|xkR7a($eM*RBE{nH zP7g~2TJr8{d36XyKfg^0AAVYh0;(`3!@~S>rT?ieW95NFtoDn5sQs?Cwj=3!xw83l z-AWi^0^$QX-Li-(C&BU0^uhzO<(HE~LE91+CI=gM0-2H_u%dD*9lt=Av*q(91JJc} zi4T7lnmS=gmsC8{I()u%up}TffGZsuS-x-=n1c8B6h?{~zNn3^cw5yBQT2XUC)#Q^GJLjnUmwPms9 zKPP8MKm&=J9m}4&GoEely)~&AscCuBu1!LW_ z!>F5)zal8KSo`cuD1a*V1f`X%05em*cx84oPbEf%rj_4I0`S#SwjV`%&E`CQQiF_~ zQyi~^2oi)GQV%@ZgUuHIm@#^PjlrwJI#g2V2k;*`a!QJ4!1d%9EvgBHUbV+nv+=T&u| z^s(eq-zpFjFqX#Sx7(d7x4K zi|$7wo|xTW4*(ETF*TU=tO#i2WbnbW8L0V)+`dIaGnYF2UZ_1;(V>A_bLe!^%ztOF zMK2P9~~?un>UnNIBdxYJP(1Yu;$o3RGY z!JQozRHFm(jjG1UHztj;I;bxtwo|=I#U>S7;3=TKoqqYtLJ+`o>nZZs)zOmRO;L-; zQ{ap6V7sMzWIQMDGHvOvRBnKw0OvramM$|OD^1O?TXqJ7oEDZ*yigd#k%LE%P+a>FPw0D+WoO?~x8W@TrDn}h{ z(25Y~9ui$* z!*D-M&BaiwGostK{tBsDX zQ?5DHu_3Ymfl+K}oEWkI?m^6{P!?nX8ar!fT$qvNfoH{pUBwm6OjdZ8uE+Vc{Ykr#;X_L3CM`ERYER@B{!%MI(UI+<=QEl$jTJ zWW#c1L_k&1J`Gqr1y?o+tg0ENc?)nw12Q9`aOx7cLdj+d-|EE`vT&mLnC?Xu6TMvV zb?oBE@)tWVdM}ZND{h{>jY~Ik0j>~7?}YSb$P&nMo3AdkZ{%)VF$7y%v#F*oz!fsl zDnGZnHKyVUP)A^MtwgeLg)9sy9-jscAj_Nm*-|qR6<2^N5~GWT`tP_xW)h-wv_T@s zveCwf_+&T)R}3@B(cEY=3|DBgFC$%HO2rk8BRY`xy++^)0Zpuo&6AY7Ra7w!wNN;? zp%+ys1Lzqp^MVU-#mKPmv-^lsQH3-UgL6gMq$O2Up?}-B-Kv@AF2EJyt7q=|HfTvN zu55fj-AwfgTp`nG5fk@24^6?9WS-^at7Oaq6;%ibcW|g~S+?K`i46W@x8cZ=!Q0e? zWcxp^7#xuS>@1(`9#o-p8|`z}mu^eo3Q0Kn)kIgaT!brb9)BmhZ%I=zh0-5y<5kba zmS2D>lp!!OH@fjltXzmHMzW}@waPqwfd^BF-YoFC{g5x?3Ylo*!@C}fr{Rjh&*Yr( zsn=pEs?bJTtu0lh!Zvd=p|8w(ti`l zvC7H#LR6t-k&KW!UcQXumP8eL%H#dxT-j2lEV<@FOd+5$N0_Z{mMLZWCB2wJZopZn zdx^;~WrRS0Ox(>{um-xxAd#T0tal|k$&KI-0!t-26X=qViGj@nRwA3Ya;n~Er;ZLqK~ zm=9eSyU&X#L{H%uB=NR!vi^Gcg_uJ09FcnoWf;8piVIatp>LIhnsonhxKJC`9YOenw1OFENI8!wx|dqVI`h`7k?g+^kgQ4nsbR zC}aT5dD_@nkz1E*m8JWzSqmP5CPcO}@OSiTTTh-mv?M3SEz z7JCZSk8;5}47=HbB}DYgFN*ZBv!no*%ZILhBfW=DzhK3MSVFXYbGFDVD?8)sVa?LC zEz#000000 #000000 #000000 + #005F78 ?colorPrimary ?colorOnSurfaceInverse From 80fbc75126027eb21d5b5bf8bafd251b9cb0ead5 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 19 Apr 2026 14:28:50 +0300 Subject: [PATCH 113/162] Add foreground tick for selected icon --- .../icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt | 2 ++ .../hma_oss/ui/preference/AppIconPreference.kt | 13 +++++++++++++ app/src/main/res/drawable/check_24px.xml | 5 +++++ 3 files changed, 20 insertions(+) create mode 100644 app/src/main/res/drawable/check_24px.xml diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt index 9e3f7af4f..c9eea3446 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt @@ -132,4 +132,6 @@ object ThemeUtils { fun Fragment.homeItemBackgroundColor(forceNoTrans: Boolean = false) = requireContext().homeItemBackgroundColor(forceNoTrans) fun Int.asDrawable(context: Context) = ResourcesCompat.getDrawable(context.resources, this, context.theme)!! + + fun Int.asColor(context: Context) = ResourcesCompat.getColor(context.resources, this, context.theme) } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/preference/AppIconPreference.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/preference/AppIconPreference.kt index 9eba3a235..7091fe78e 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/preference/AppIconPreference.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/preference/AppIconPreference.kt @@ -4,6 +4,8 @@ import android.annotation.SuppressLint import android.content.ComponentName import android.content.Context import android.content.pm.PackageManager +import android.graphics.drawable.GradientDrawable +import android.graphics.drawable.LayerDrawable import android.util.AttributeSet import android.view.Gravity import android.view.LayoutInflater @@ -16,6 +18,7 @@ import androidx.preference.Preference import androidx.preference.PreferenceViewHolder import icu.nullptr.hidemyapplist.data.AppConstants.allAppIcons import icu.nullptr.hidemyapplist.service.PrefManager +import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.asColor import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.asDrawable import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent import org.frknkrc44.hma_oss.BuildConfig @@ -54,12 +57,22 @@ class AppIconPreference(context: Context, attrs: AttributeSet?) : Preference(con val radioButton = object : AppCompatRadioButton(context) { override fun setChecked(checked: Boolean) { if (PrefManager.hideIcon) { + foreground = null alpha = 0.4f return } super.setChecked(checked) + foreground = if (checked) LayerDrawable( + arrayOf( + GradientDrawable().apply { + setColor(R.color.gray.asColor(context) - 0x44000000) + cornerRadius = 96.0f + }, + R.drawable.check_24px.asDrawable(context) + ) + ) else null alpha = if (checked) 1.0f else 0.4f } } diff --git a/app/src/main/res/drawable/check_24px.xml b/app/src/main/res/drawable/check_24px.xml new file mode 100644 index 000000000..d195b96d9 --- /dev/null +++ b/app/src/main/res/drawable/check_24px.xml @@ -0,0 +1,5 @@ + + + + + From 81aa5f362d077a11c2dd93bd7b8724f18c820c82 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sun, 19 Apr 2026 14:47:50 +0300 Subject: [PATCH 114/162] Fix new icon --- .../ic_launcher_alt_5_foreground.webp | Bin 1120 -> 1128 bytes .../ic_launcher_alt_5_foreground.webp | Bin 726 -> 654 bytes .../ic_launcher_alt_5_foreground.webp | Bin 1582 -> 1628 bytes .../ic_launcher_alt_5_foreground.webp | Bin 2730 -> 2762 bytes .../ic_launcher_alt_5_foreground.webp | Bin 4170 -> 4220 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_alt_5_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_alt_5_foreground.webp index dfa20a216c018d27bc4b813c0a73724c37718f9b..27a593a441fc825301fbb1d6c1cf9e15b21b125c 100644 GIT binary patch literal 1128 zcmV-u1eg0#Nk&Fs1ONb6MM6+kP&iCf1ONapp+G1Q=LajYZC6pRLk9mU#uftRGe0sK zAh(SqNusi=fiZF%yw<42{?~)nzI@|f04}hC00i*vz^!dtwX)7RSHF8k zOaoc~ebEVhS;io8ho?tqny_T^4gh%z3V}hPs4(Qsc`1;puYTdxh_M=R0fANTmE#dl zGt*-Ot$J*+#`d!J6MmV^7yGds$IbS-#_Gr-T}`1gV^BO)15Pf--mjgdIyUBGZmI3W@~Dz>wUUrJI_&C*k= zR7pCt{i#tF%k}@ZecU#yCTKvGcA9>Up)IY>^CS{|r6BWyd)qlr4Q;0q-c+o@W}UsF zCN~WcWu(StWn+3u^UBdAFQu8XUT2x=l~z{%i`d1gYm%8!7-Z(8rK^M}R0^ZMP*H`7 zCeko7p-G8=(2~GFCa@$F0S35e0!qlpYC;jf#i0pBfe0{)K#~g;kP0|SAizlqL?94> zkPsdl2}PlzqJk(q>VH05VClo9W$9pP(em}WbAj{kZ}<8C*B$@9t~d9sIeC9yxH><7 znvb9FOGu+_+tiyA+pgQxwyo5*ZQHhO$98SocHj5X_x0}D`WJk!>9}X~R}<0y37{J4bg<4>t?8I2CT$d%~P$>sBrPHKuEuYX0Wz@NY75!&78X**&{Q9(z`p zSDAQ5z*IGGU%RU1--`r;a4ABn(i0PH(*6M{`@ecst z&S3#S9sEsZehUFSIvjCWHAM^8QmL^<0C@0KW-ZPGw+~)7Tn&C=f-y`@rNoO=_$)EI zp#sW@TL2z~nt(%>Qk^`9G(SnKz;fW+IRFsBstHQWIfHUK$|%2pi!dI$mkP)3n*jA( zM8r7_@@o%>6Ibt3NCgHs`@PVYXvlbqKk z01%JP9lMqSoj<;RExFhsdVrfItIth-`~=Uvz~zL>7L{27O^p>hBEtkwt(k|7T7X`7ciZ literal 1120 zcmV-m1fTm-Nk&Fk1ONb6MM6+kP&iCW1ONapp+G1Q70H#he{q#Rnk??_?(XjH?(XjH z$KCzhtz`qVKOBA~UeR#@S~(rFHSSL5u8UoTLvqGoyWg-ufFbJiM5D=3nE(g|x^JP$xqQ*jLdZXA{Ug zQA#Oht$+m)B)BwVuKAllc8`*Jb5aji5=d}tJXgNLh`~jxbw3sS39z%O_WyuULyNZS zK}Pr~Uv~7mm_Xi$!qadx{<|9?27ud*=K3L}ONGEe`T%)VXT#M9EP@KpVu2A-05DZO z92GEDHUZ5lvp2|)$=h%-Gyo^98UR;QO3t#0e``+B(j#P~{QwYBY&M4#hG;kc0zg=J zvkm~J+20QT@7s!28XIo|X2;-OSmzqPg&|IcJ&HCzM1wh}O_WT)u!~*+0flQY1GncJ z_SoT|M-j#DU}({}oi>zALg7bfab5-hco%Ml0ej#08>$v;T=p-Ze5GfD4YzOJj*_s; z00bJ2Mf{sLUIEG{px0)u1AA}UqHJ|341s$4_Bs$i50Bw_4`?^H0?@2pg+Z}bGAT*3 zN&#Sw_bJw?9)?4q$`gJOK@Smf8%kFIjc%p_fP}cY#pg9D*vs2Nyu-O@v*=U1P+kWL2=$25bs=3EEViO(ra)N>*W(CD5n%bpNDJR{lJP zQs|Qm5mW8I9GZRa)-~TWGJGFs&t&=c^s34Hg$x2(&2&MN0h&`d=NoKRl?q&RmYL*$ z<{8Xed<>95r#z=pWRX+R1dMv{IEJ19@{zMIQmPF6#+>xHx8gBlOY1d$7Hu z50{v&Hu~t`HF*7?kAQk>qhpK)>obVj~X=*tS_u*O7-aBW1|?7*UYNl4+_Z+b{Ak=bPa<_K!XS+NCxt9PB@N zSU{)ftaXe+9v09nfwlAOKY939(V3rVf62p~1ubLkn@XP7IZ)7JUa8b!PLH6bhnv18 z2!~9y0tZNh2_r1hnJ|H2k8nd&%z4b654)bdX mj(O14{BUQA{c=2QLK|j2kPI!9JXy6 zNL14M{~dq-HLecZHgY6tX75w~-A2caBq>r>FEbzdZyx+`C;{|`971;cJ=Wu#29GN2 zZm7oHt*f}ZWtGrY6&|nqK3_gBhu_TPyF1U!2m8$U-KA5z@VZmArEUhz44u}Ub&`6k zFTa~+roa6j-EmHzvZnX$+^dh9tDM-&f4lu2K4zsUR|?8^rm4!8Ub9n)y!s}KsQyvS zuCISRb3#*rWw6;DAoWZ^be=1RHAq$ocAR4~W6cOL@+Qb4N<7YKr$I;vL?9%D1iWOG zD1{Kjpc;^70!maMi4p=*l2DNlDu_Zts1Op*e!Tkg?8jri-2a0C+HKp$7TdOM+qP}n zcD>d~Kf3NyjdQ+*JtF!)0ZzZnzkSP}ZJgabT!rvUDR1uX>1-@Y^I$j+ z$aHqAvZE)MHwkEA$hnpbYu86m*ftPMTLjn`@|mGc9bs4Zk#5ywS=A8$hBEY)RRXRq zKZ0(3?Vgw_Bm0Vlu%%Z}WT=UtTi#teAdRo!sh0qo(L!3EpLpu0msk31h6c#-Bu5{8 zAw%t=RI1rd4|X3p%e5=v7P=kI!uQp14{+u+q(Pk_l!_90D2ZE#BuIad#Is8hB%Mp* zR%I6iAybkd`$7`;V!I#+Xq5yJ!;&CuLK4J{NrIRmNf6X#6$JhjH-f-5XI2m(xZKAJmBfz&oWz5Wra!{53DZQ^gXG^N>K6k;KHW`jxerE6w7xv3hOusOIVBBv=cvvbG6INr2-x z_gmK}yy5Gkb|!{LR&80^>LQuC)TK!g!uB2UzAz>|Igz#yO1^;Lz8EcI*mBEuWbL zk(r1%E6a?R)bg28OQ_hOAb>-OKtLEQ6a)(h3Zlx0DJ6h`Ar%M;Virg&1cHJ9W{HAe zVPQcayewWV%Dv&bKRo;Ax<1@K7hbUc?*GI8@#){|K6b9#`WL(HecM2`ZQG{htg>y} zwr#sAcFMNxbI;X`lS;n!prx(#R!NKK{{+x~96tR18y~sx3Jma+!8fb1XZ*$UvA)*) zcsJ(Uat2SKY5mZd;lf#X!x{8%*M;&G+oi&&bs&u^?7&qET{$?Uz{w3yoAjT zlNkzri%*}$2zm|k8S;N3iTjWd<&HDz(08-Edw9iJu|6EHZS8Ruxvx(@M;;@RP?c4Z z#5qY^+a;m&4N2VFB%!4Dl2DlSl>9~#%H5H~wd7V1@~Tw?A>VpM5b~+H7KFS? z4+J6Cymx{Sr4FltP+aAvAmozSugF0ZUGPkmgD9r_sZ|c5u)@(ZIf(qSTfWOdM88CN Icy#Dr*v}ekqyPW_ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_alt_5_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_alt_5_foreground.webp index 500ce1fa4dfb38ddbe15c493125265553eed1930..9f48b82ea98410b758a1047173e83e21320ab34c 100644 GIT binary patch literal 1628 zcmV-i2BY~>Nk&Fg1^@t8MM6+kP&iCS1^@sr*T6LpHBqs)ZJFeJrf8U%nVFfHnVFdx znwgn)TYvYdzmoI4;d+-4`ej-M{m5(p9a=0kqywKFAI1$Zu3%0imI`?KY>f)XW((1? zfw(3+KJ?l-Sw+ro6UF4>QS%;V5y3@J3%apwySAda*PLi=X&o+D1cQg&bXblWNphrM zu;$Enk3Yw&lm$t$XDl-$RU{0l(UK(TaqmKbCAF-gAA&9{a2yPSN^Py4gS=r)T zA9cN1ByEFE$rH z`*nY=jDV8lBBe-sY~f*Qwi#X5or-K(K~!b%X0YWt6B3GH-k|j>z(l4LHVrE#FTLS8 z`#OUozcIKJ#(-Y>9Bd-V=845(8I9&zel&Q8(@aRJ&bBR zk-9RX@GU%yjfS`38zO@hY2D_nIpuY3dZn`-YwE}l<0F3~s&Jl>ampE1NX$%w4M*GHj}fABRlvUZ&pTqw|5(<@@p z!r#w$F4|lYvjR#H5hWC1M#c$ohO~+BE`kbDOb&iVfT1L3OY8IZ{fLVg0(;C)K}5Od zedJeo8mo=3HCt%^yskt6#r;Z@WUTz}5H2c!u4|--C^GmL=}swQf@k3sqz$Bx$WRhK zMX-?y1^j=)L&w&d{embloEvC-PDGUZ+X*(H6YkAb*zGCKNGGw+;Bp5$@lq*Qw;u$g|R~1)_C1w(dA9e{+Ji*J*Y(Orb#l0CB>A&syo_NY# zi*1W6h&2CjpH$j(zfDMn7dtZiLZl&yt1fQGE)tQJk&4`rA#6eCe&Lf(<%$taP75von9K2k~PLm%7rOHDs z&&BAV@PVDAk%wBH+c`uO`Y95gM&OS~d=lVjb?#a{{6YBpNPZCDXm#Ck(SDMLTCqzp z22`5NzIUNg=PW!4Dy7iZW3!-QMDyjQRFaxYa#}uAnqhxb5I;QORctWU6+Yny!DkF{ zz2~k9B%g>6MD%w$pE0=BKSzZMv}vDkN;=QQWmt`7`<196gMvqR+(Yd7D!$;eLZ~;_ zOf`rEQH~%!yJ5iksE*CKh{3Hgwg{kLA@o?k1S&@iT>m6c7#wTN?&uPrpcyTeNrMW5 zUq?O70ScCziJqpQVnF`Dc?}hJ)w9Sa3Mgnn(GY!x3WIY6EDAIM3L25pZ+;1&Y|e+V zcL4<%g4@sISQDUNVRW3o{y~MoqaOAKl>h~|_s~lT6n9BS?M9$VwA+F$|{WQeGVBVi>#K{Mi-pQkYkLAj9Pu>MNA1yP%nbU{pX_#Cg{$idVSW<9GIYPLbaar@imyBUO+XwtoxxQFhMg@m9u=2ZCzR6qm~U(PcluD#`0woTia(bl!?dt=+SZQHhO8=uRwZl%_U&y1dJ^AEhM&TE{<72CE6 zHL`8lN}s(qlf$CP7Boqa1a1h6Z6iriDgz!15Ax5EX<3jYo3>@!w(T$5wr$(CZQFdd zZQHi7&slq~nE*M~wkc9YO3q;$8WFJsau(s4+qk>$wpx*z4RjrH?`-N2xp!0%kxNG( zTz7Z(+v7%(B&kg=R08G=@-+XfB1vi`0dKgXaFreK_iW_Q6TnXYJ4fI1A#h+5R3#jAx6j$vV;U7NU%UbFcHEUdj5o^v7t1vFUvVukn<(tda1fmI48OFCY`Gzkg;S#&sS@YaZ#pV+MX*LNKB&=^ z-a-m~--g*Vk&`Kc$%FW|4cTG}O2{XdycJbW1iXGJZF`+W87LIIUfN1%Uj7;{7Xo!P zR<5!L^e-yxjBJ#qFHua6ZCHu*l@l!hmg5p5RF_1CP){()k~>!Q(oZEeQAd#inU)hO zi9-$Rt0&=-M6jjR^4Nvve84)O!cG=v1dAD090Y@(iq^=$rNE(%bUt9808plUvVq%glY0+t_hL%46Ag0Akg z=K^sk#h!k22q4~YD3&4(ub#dD#KCJW5z^CaIY_k>S=2-d0KPnaAOP57GK84o8bzJ< zi%F3D^*FA!Q}ugPPZ@+Jp5kAzU-U%qWj==`z#o`HHBcj{Fz7qxJ=iwsEs!U7#7bOG zrAPtY=ez`Jp)zD5T`|5Wnana|B3m{704QuNJPG|PE|nW5a@B(XusWOGxr1`!c(wS4 zDJerHGL_HIa>Wht(($TXA%qHCS5YCjQ`#0P1hd5;Dr`|cc7cF+RYG#c>i!9%G##h* zg#^5bVAZlk^}C=mLab6E1i*5Ey6^5$2nc~U zHt38E!h04?h~{!c$d-#YHYoS9aA*%G>_L35hEUN_FBgwdai!M$*o8r1H|(3%UsR4~ zj$?BgfWrPHbV&#mLNI6Dnb!c6dwOK_Z3q-5c=N`i84W;Tcapm$0u_QcTU?y7Fese7 zoEoHWs1WS&XJUB6psi(S6uy&}htn4Zg}wZK4bu0y z3qT=QL!+ik_a79dR|2VHeMF-`VL~=jT%Wc86xPtl$MYErK)Gk(TBUuMxd0Qs_pomJ z{0b9x1w>|}^xMXS_xh4mul)ywZ+KNg-T1o!6W$v@X1(-v=E9ipUf+tVoL)~`fC;lz z9);t@IZ#+bFT=Sys$o#>5fbsWt9zr_kT8296i!Q{`Z0YlCQPvT5MJbZ@*Wdr4Xu>t zRPTmtO!$Ted6m+aNeg4bzkIOBbUWCk(GNkwOo)b%T{^uUvnU%9zLx@nl((&x?a%ZD zkT4U>I_{a`Y^O$I!c6dZk(f8`^=fDXBz*5h7g~@#8xiKyIx7CO6o?zG5^a3Lh%mb>q&#s= g$!wjU`!yuY>}vP*wW7j3Ki+Dm|5je)^uLq703!qS0{{R3 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_alt_5_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_alt_5_foreground.webp index 2dcc7221a4a13be307c9895ee2a64526196a7b72..87daeb2ca1d66a8dbea34c778e2e612603879f94 100644 GIT binary patch literal 2762 zcmV;*3N`goNk&G(3IG6CMM6+kP&iDs3IG5vL%~oGHHYH1k(5dQWiK4#Dq-L2i--QC^Y-QC^YJKNh@y?WJ)*4J|! zP6{|9OT!@sZyVzd@ z;~N1ZI}zX_F_I)jk~}l(nDqXagw!Ch+(wclDd_=+b{hC^;169AAW1T9>wVj{ZQHhO z+qP}n=Cf_vwsCQ|nwbD8_W!GLvyv{M%j&6PreU55Gwe3+-E-b6-3`Q-Zn^cbWpJ_R zWAV9cpm1##P>JJXX>37;p6>>3xt%2xLW?Nco?3b~zVx^CwV?%6hQ`(hu8xl_Eds}N z1Az+2kt8XS^S0x$%)G}8&%60o(6$Z3A6!Y4#*Qa|RR62~SN*U0e`kJsf4g1m_5F@3 zRn>p0|5U&+DlHN=jH--!7FvlQ%!l=pUVrH7ix^S*%FqdqVojqxJf|e+`LX)eOT6eU%O|90{N=YsiO8(Na z2hW}iStmJd*hSQB3p@OnBQc!OmQe#Fj4F%{5=(_TmpUwqMM=e?%^K;mVC=%#7cRVT z3Flup^}>-C_FB-Qk?M_<3N>Fv$JS@D&Wo&J^zZ_N(M#Y|7&awSR+C2hEIxVRxqO+< zx^UzL-G?>nSotc74F?mCC6+K6gM-mV;zlT;HOnwyiOCntyO1x(bB`Xjc)LaNR;B|N z6Z;rValxp}XyIUAATiZTo4R1`g?zc6d-9M=lo>-vWLwy}!HWq-Z7VY)%e7>YQ5P(@ zkjr%Z!eXJsMuda4yXk;nw6k(FN9DI4I_E+zUr+B5MXEfKk2f%?!NJ5pJFm(&dBg== z-Ul@sp3%as9AwnRf-W*4H0&BQY1)Nc?w+9?FIpugp8SA>)gn`4iEP`nSqJ$F_+PE2 zNc<7#hXdWp)HIRZb2u!UeClu}jl|(Mi%|^(hQ!E}k~$(E1Kf5iwf~<@ddRovYX?uH$lN6ovDiL!$|P zRPn8rSXCej$1LFT=AmUSotCQJs!lF8e_@v)5#b>*N>_Hqs)X?9z8IG^jVgnTGO4A- zu9h+rd`yVXyRda*;bs4rq39U3g1A(r(Ii>1P?=?pJdYwHy28pWOLQ3`vPAgog>{RC z@R89{(U}-Id8D>J$U2Z`8L~x;005X`4`W%Ri129#%NB8R!>izo0RBy3lO-$eh|(?% zgq6H5M~U$X3vyJk$VLUn7?Gk1RFL%(Yji~j#6!y_y)-dC@)Dth`7>Uzon*tZ+Y%tm zDCdMq7p@FjX$a*0s1HHw*?16c^?sbcm6{*3GF0m93xr5c|IhkSr+h>r79yS8MG>G% z2NZs5vc^m{a1AZQsM6J?=mx*~x ze*y*&8DGd!FXJ3Q9X(v8f@qu;Dm^izV4fIV8vm0dzec?d z=X)nbca{oV|YQ04C;IE7Iy zE+U^@1cb`(zraNJ$5B@SPGQuEEosKWMR6x~l#NgUQu1b)$SQGK@v0u9cZN{3MFB6- zVK^_y2?^vaP?rXBPMYL;E8`uv>$n+y0U~j0uv3i7Wn z24qF%!n*I^QZ4(6%!$YA2(m}e*oBKIzU>A3cV28`jp%n55p~S=o43yR7hoG(MBTB7 z_(gRPc1P%a_{K)~QHub8q;ZGvjf0TA7Ps6~WX|w@0YR?%-)A9$96W2k5JBRcYSaXR z{8&}4R0Lh0V+$|OT}Cz8(?Yw=AwQPW~2Vg*?6IW(I`p}TQ?#f0IE?&Bjh81hV3F- zs*HZFjAW_INMuUUmirQb%ydaz|NAZupkzy3Y0=oZ_#vzR>T;ETG=LbLBd{HMIDl50 zxYw#_=i-OV%+8TgZv_yefnDCC766F+IaXyP1Z@Z*_c{QPyPh^Ij-b1;q>7^fv^kPr zhXF{pFt2c#kH!x%+Qss{)1m+}1Xh-u(kTn@L$`$6w=RvIiyuQ^O~I5k^#c45qlr_$ zyDSDEdOnqMJOEm4;Z38)7F>uQdM7fnM_d9xhKs|crT&8-x+NCJ4#PG4FsfQun76V< zFM%Io)OXs=x{cn7A7XTKW7T7*h98nxk;5`3TmYbCfr}NJE>ua_$3MoZC>$F!^*i{GZenmu+0+|#<^uT8>c^w7 ztX$I9@F88IeIQ>;mYM_~qLXa(G*6X}JD|ab7gyf7bdR#E0;q+e9`*;Z`F_Pn?S$@(T2G)#V(O(yY-B(L=PqKNDkko!g`y zBhEz+=_ec>Wue8JHu^#hJVdndxlqDtH1o)dC!vQ7Mt6a$F?ci@eaI5Gf`>>K=ws!2 zh7?kJ^dU!l4IZLoe?|vzK68q#P|Dy7&_l-NRZh01Qex541};1oJ4EEQ)5OBopa{uZ z6@3=_&VwBy+9i_@% literal 2730 zcmV;b3RU$|Nk&GZ3IG6CMM6+kP&iDL3IG5vL%~oGHHYH1Z5(<3v9G7y-7g|0KoN3_ zl9}SlFkpke0qkK%b~x99tQz`{d|oNqwk>wEfWj_nX$RdzRTt0|ggJ*X%-L7WO12)4jW2vUzRdNp>|<$cuGrFNW9tKF4d)7t z%~cyXD=94^sERfuAU2YuNY37F#xdhFqky3Bf3%Q9vX#<5015FVz@k3t{ha_h()O>G zlwVcfbM84;+ugl;+}+*X-QC^Y-F3IO8#&1NviU6m>n-3AP6$hI?h0@j-2iT}ZGxB; zOtFCJw0B^U%_e3KL{r4;Mv`bddtd9< zG(omaQSJ}_33;q}UFZh20kQ4r+ zQ&Pcyg8u}-5oL+`L`$MQ(SztkbR^mkjftv+4Q37y-4#|^Dv*nE*Vku#THG`z{?O^>agrrAz!Ept&p zSeu#P9nP&<(X<5{E)rT?chR(mY}=IJa5l4vs0ImxsIGDZ^ z0e9? za6`duVO`luo3P~8i-hKj`Y(|b{xY)(Cm;~^W;T|qOjQDy3gh9G%pW?lCKX`=gI_Ex zFHtEAmc-Oa^_fM(S7F~TAaL7RT&6PTFA%9V7L}vKlM8mLLBLQLkQAX;iIeb(g>_S* zA17_pKmbuUsD2Jy@^-BOun~(F)UI4_4iXjg-!2C?+BcCdG@XD57(x^3(1v{m7{r1D z6(-wO>-C=p6O%lnNN8FP4ON67B!VM1x6BxnA@kYj$TTrp?af{I4U zHa)m{LM0O!YN57-I4y_-V&E=aN0gg8X)PH%2d|<-6}pkq8AL?-pe)S<${@xr2o1MS z4LxU~|H9E$Rgll|qL17T8Eso76e>gn(}qLc%M=`sR2t~GryU$xI%+qsap zXxnWs^Dkw6QAiAqs1YsJ02Z`GB@zqqPfRGf%|e|7vKB3}0ZL=p^~PXn@rqmtI0}LV zY~W%CD=}t3x2ZL!Zm`T0G$;4JTFjv+Z*zSm7-0gO7$qp)v2h2)bq6b<*9=eoPF^4o z5h9}26vYZ6qPQnWf=g_0kt7yLn-Ezj0k~d60*Lm}DeW5?He2`(@? za$Byl_#aw|kOWvb-lLg?K!m1_2|L)r_$c#@8ZPLj(jhn404u(h#RUmCpwzE<3tik9 zdTbJr5j6NJae>m#Kum-|rXWV+UB;1^KoUTYF0mD~cA<-sVT!OomhXmsa)PDTw_mLN zd16z?&;yeo5wNhTRm)FzaZZ#(1)CE^6Wrk8ca1GCeT#n#)rJcY0m5G5@`xoeUB)~5 zBsP70*EvFv6=zP4bYE@Z9CEOe_LX-gL!pVY6*RC?B^{AU29(x+A_M^cD7^9#f8usq`; zHKs@ZT4TJ?#ijk{son6Eum_OTsPwB{h9Z}PF?(G0&v6@wjY{9zNjvJ2@*onMzhD0; zwH2iKPyptT4Y#Q;Rerrkio-r#^D8oe30Uh~z2$ zR78mb(K>-2bC=Wzg4{$gWlZ!si33r|%7e*EY6WHQaupE}@s3(VG_b<4e#@Mu6^w;v z+2kxUNVR0|aKJ%jX8lUPQ8OrSf7#dJFBvU&01iZ}(C}Szp>_}`AUI?|IJg!4m~%%B z@lvO;!v3yhM9`s_NWUFGgsqoC79Ii+dvdt*a0JP8C>5r301*{qKYUhfIgeYAi66qj z!qSGVVAVqWu!Xw5yc{ubJAMq)j4mFL%NOE@Uy?ZAv5cAcVWNo--ZKsWh%HR6luWBH z0uWKgo7s+E2Le)wz~N7}UF4Hx2v&9v~ZpCgw5kYQqA zM5OJ+59i9vC>_e`3-QCdyg1Xi)U_AlhaV2(O|Qnj!cVS5_n2@U*&q!*{E~^`(S*)g zh#&q%W@dzvZ^jR^nbqZ^@Ld4ydaGV4T576^ z_;4=$)NyjFa?(~U%0v&dA+bItlE*fg10N>rOpFW<=T4(N1s~oe(aDo*HLGwhe3(Cw zSY9&a4Ou)5KI~TM8N`pK&9dSm_%I(cu`^DIqZTWI55Ht)jGcFF$1wMjTNj~+`Jjcp zWh1!v$iwhqx5A(xJ*kmOrZ31u4-+;-4eKljj`+60ZbT2WK~%7^J2(>ij%me(TQ33+ zbM7AwZdQn-VZ%N|4>M8e>i{0sOT{A_KY|`Mu2q>H8Lw-WKB~!d@G$2Rb!*y?%N6noYDg=yene$32Rwa!*ZAsw5zvj{xQ zg(`ilY)a;L%~1O`xq1@2h*p zB@b_almBi<*0#lxqc5tG^A=aDxSFw=nOn@%%*@Qp%*?P{?yOMcC(2I@7GAMrvM)

nP)C{ ztNt}x9r*VJ1SFPA#;*-5y4YIqu}h_bmi{hh{HzSMkINZo7nBtkP~!tXmvh>OlVzE) zWm*Mg2FfnE&@Y_1h!W#7YR*#IIk5}n0uJqxUt6Y5Wb{A@$dM!|lH)t=v3$(TOs|`N zMv){b62F4h!Rp~39A8cVY5v#zulZl|zvh3<|C;}o>~f3O&+_JPUs}Ye`A_qo=0DAU zn*SCr3Wxz>fp{Rz+kmt{x;@?QxBU@_Gcg264-^J!1FeD1Kp$WmuvsG%@QtFg!HlkApeHIP6Xv9ThE*f{y#E-pbUUB13)>%Pu|$If z)dmWWH&6Wv=dr{!mR$m)fGTbT05Wk@5f~E_WzXg;_qoG4czj%b=~XP8fpBw=MJ)zu zj9#kg^EO|O_!Puxh7A&nazh*7HdegfstVJ}%Q{E#hD#2+$eMax0}nMgSSYbf$&-YO-ZPP* zA&}2h<$##S7@EygCnC!{SBV$KF0!WfPKyec7L}qw@!T=vdCG01!s%ZSSRsdJmf{_j z9DR|c#D0s)m7XHPa(rhQ24pbRHXtKIbDnR>BhvYXqb{P|Sz5+G&RM&vA z3@Zb%6)SD^lXUX&qJFJ5p|)zvJP8h%{J8mh~RW}SIM4bUf^HoAHRln`oh>hSkmXhpjNFPt^P z!93>aYN}O0PPV3`t)vDcor(hnLNLznjOjRLCQ5X+)hV50Q0jP7rio8mik6(TN|YK` zYLe2FT@n$vd`};8K%8PuQ+0}^+Dx3Dr-gehw3G~aN>O6Plt*s4WJN2s5-KTjMS^UC zZ^2}8#C~{EMU4V7F)Yog|4o{(lq`iWk5Z)^7tPJ(@zv-JFVskJ5MW_7X^=GxTx|HK z3dPVkNN*}O@wAfQ)wod<;t->a8Ii3VWmIyhTJx%y$SWYg{Tnu!G%OxWh_}_I8Pnzt zZn1J!yZ$8)a$C92`jS0H{E{BOFr=rSJDH5c*(HRk9wO_K) z?}4h(V_u9+9?WHpfAmE$+x_FC+LE-&taVE~n2ag0F*AxnB)K8WDXJ9!nzh>zWc2z! zNj2IxoJ&PZx5n>${j9facwVLe5m8ErX)!rGks*=fha1=I&Xs`LO5?CD$m;!fkXi)9 zi1bSpq3gzH#Izeqcy+n+0XZSi_-ZsHao~}Sl>s0NN7qz+Rw8NzlpHVQQY)Vp5(uF7KHZ|7MFJwStG*;dAm#PUO^| z-qulx0>j!z!M+fyCupzO8wtpvucN@l0=q6~)BTr$j*Y;J8w57;o0W4r#zENB=ni6@^ zD|5Z7-vm#wUeIP5K(@G9l_P!!frYb2Qk#Q37}yq!ip@X*pKWV4nBPI-aN*{ElrOB_ zaQKKsQkzi5w$ISt@HQ@PmmQwKC)o#^<);zW<(;k^B_&dNQkV5jVpC=^gHj92xCTcl>-*RoY|*=H5D z{h9XNdg7m9mzoJk;j|}m-`O+r}p~D5M=ZQ(0sQu$LR*y}IW(9q@ za9jLGi7(|Iknl>_Q6V;7rNnUuCkKFP6-kkHYDY%&qbjJ~Fy0RXQZ|r1B`g zMHZ1a)rSpPG=aiRe-^F7K-x{W`aO=Xy?Da-=Kr$r&#q71{{{RWT>PjzV)&u)-MaPB zKtt*s(SM=eL*)Cr_MgDD`Mcrsi7zblfAICS_R)VjzUk-RI^X{x@~PJFVT&f_e4h?U zysz1`ZIMOhS(T*@T7)c)xKVC}Uqu$Vju&sfuOf@c)&-N}-^jw${5hJjyM~dr2tJ6STe_?yr77%YOR!?=+?Bd;C~r$zb6!+XrA=T&f5k9 ziePNRER7*2=;NX46b+~w!SzZ_Qv@Q^W`GAVGEO$oGa#?X$s(m2%8>3HuEh)y01Ti{SEI1g=W_E2kJJg5)^XClU8wC=Y?W0bzTe}qCN zMPq0m6}O*N3W8(XPQJp654WdF2Z{!i31siQO;Zda14IN-a6%r}r%gWrroVap{KvRDOUU#7i$$t5G{cO-+e_V-Un3bc# z{TAYi3FP4jc39{{6(TXN6eiUBAhLMUIb4aY79h(P96Ya()J<`Pc;;l+{}v0763(@f!$w_%D}Urzm%jpCFT@oBnuW%Ng&IQ^Ag#!>%qh_R zB3!Xq>IB7+SsNRB5vmZ7MP^80m;P=#i2wKhxmdmd?^iXF#csMf^$QH5+^KnMv<7PwG_z94gQj&gNe z5?AO0VR~Ao={w;Hke>ISnbm&P9TyWgc)YJT%76=TMgME2_+NX8{ZWO094x!@ny2ML zC#n!og6BZa#Q%*e1XL8+ktu24!xc9}V}H)(Oe_IaXqrs>AbU1vv9XI#g?z~2pzr@G zls@c2RI$InGa*@+YA$W?g_uG>%$_0}(uJYk;xA(g(N+TcvWBr?<42zS#c_L?Jtlug$6SyK;;6xzL3uMDD+a#n;j;vWp8-$mE&i zTOZ~trQbycrV#OT_To;?(!Po-ZkDZKHqf7!53i)*$nMCj^>h~R?~Me5QPXR zc14m%DAFRm7dkP8E_t_ie9RD$>kLdG;wi(j)qzrXQ7o$b@gp3)0^}@E%BfC7Arr{P z&?K0nQO#Cm!Q+TRq{~znnUyAeo;Rs27B~@w2q?rdB*HG_OQtGIY=J4X=Lclgr$}#$ z4r_75bOTR_fP9_|^oo0#DxqPMo9~M#WXj|hnJ zq}J<9#S0f}v*dYbLgWUD{EuZuk~)^hQs%B`8SN-_qVg8xJ#GhJEgV%goHo%*@Qp%+#$|bAta*G`~uQi4S zW+}3JzzP_PxURzPflF|DLT7BB3S7W6V771S1{~cMyw(_MU>Cr*2Zxk9+&$d*6yb};!wtwD6FPz_6`0ApPX&bAojNRkvu-4lMy%*;QO@=j?3Y1`Dv?qB4?q_%A-?gyd> z6-Yn^3ZbxAT42G=^Smd36#py!SNyN|U-7@pzALS(=SPJWIEi*Z08q<70H89^Tq231 zU$hRy*PoJQZP@71GY_s>sPB#|E_~?VC0jRIxokxfEflXpYmJ400yzS{8H^98V!`18 zAI8RTFHg`0jf`BdMb&qIHMQ?xwPYVRe8(gFH^WLdlV^{zQA;epP)}kD z_>UXE?mwz_8YLRD0;+OEiM;IEWR@y3B8p5PQ{OSOY2R5X(am5~#_RkzTB%s7s>_%t z`N)d2NDXHivO~}a3Q5U#WOV^?ULcoIJ=ejg{Gpw2K$o+a6Pe*mjJVKsIT;JnMc@&D zB;>16DhEg5K@^ip&W_}M+eFu1C}T1lND?_Ak|Ryh;dZAW0SS^4d0`>|KW@p=r4rcw z7lT0w_yn=CbfSwE%IK`92)iRilEoP)lu%bLqDhe+@gnDmhyZD078D4BnMo&U%qjiJ z@$qB8lDdp5kymDx?1lJZ9|lUr+ue~W9uYzR$B2QzFblNIU`{|xkR7a($eM*RBE{nH zP7g~2TJr8{d36XyKfg^0AAVYh0;(`3!@~S>rT?ieW95NFtoDn5sQs?Cwj=3!xw83l z-AWi^0^$QX-Li-(C&BU0^uhzO<(HE~LE91+CI=gM0-2H_u%dD*9lt=Av*q(91JJc} zi4T7lnmS=gmsC8{I()u%up}TffGZsuS-x-=n1c8B6h?{~zNn3^cw5yBQT2XUC)#Q^GJLjnUmwPms9 zKPP8MKm&=J9m}4&GoEely)~&AscCuBu1!LW_ z!>F5)zal8KSo`cuD1a*V1f`X%05em*cx84oPbEf%rj_4I0`S#SwjV`%&E`CQQiF_~ zQyi~^2oi)GQV%@ZgUuHIm@#^PjlrwJI#g2V2k;*`a!QJ4!1d%9EvgBHUbV+nv+=T&u| z^s(eq-zpFjFqX#Sx7(d7x4K zi|$7wo|xTW4*(ETF*TU=tO#i2WbnbW8L0V)+`dIaGnYF2UZ_1;(V>A_bLe!^%ztOF zMK2P9~~?un>UnNIBdxYJP(1Yu;$o3RGY z!JQozRHFm(jjG1UHztj;I;bxtwo|=I#U>S7;3=TKoqqYtLJ+`o>nZZs)zOmRO;L-; zQ{ap6V7sMzWIQMDGHvOvRBnKw0OvramM$|OD^1O?TXqJ7oEDZ*yigd#k%LE%P+a>FPw0D+WoO?~x8W@TrDn}h{ z(25Y~9ui$* z!*D-M&BaiwGostK{tBsDX zQ?5DHu_3Ymfl+K}oEWkI?m^6{P!?nX8ar!fT$qvNfoH{pUBwm6OjdZ8uE+Vc{Ykr#;X_L3CM`ERYER@B{!%MI(UI+<=QEl$jTJ zWW#c1L_k&1J`Gqr1y?o+tg0ENc?)nw12Q9`aOx7cLdj+d-|EE`vT&mLnC?Xu6TMvV zb?oBE@)tWVdM}ZND{h{>jY~Ik0j>~7?}YSb$P&nMo3AdkZ{%)VF$7y%v#F*oz!fsl zDnGZnHKyVUP)A^MtwgeLg)9sy9-jscAj_Nm*-|qR6<2^N5~GWT`tP_xW)h-wv_T@s zveCwf_+&T)R}3@B(cEY=3|DBgFC$%HO2rk8BRY`xy++^)0Zpuo&6AY7Ra7w!wNN;? zp%+ys1Lzqp^MVU-#mKPmv-^lsQH3-UgL6gMq$O2Up?}-B-Kv@AF2EJyt7q=|HfTvN zu55fj-AwfgTp`nG5fk@24^6?9WS-^at7Oaq6;%ibcW|g~S+?K`i46W@x8cZ=!Q0e? zWcxp^7#xuS>@1(`9#o-p8|`z}mu^eo3Q0Kn)kIgaT!brb9)BmhZ%I=zh0-5y<5kba zmS2D>lp!!OH@fjltXzmHMzW}@waPqwfd^BF-YoFC{g5x?3Ylo*!@C}fr{Rjh&*Yr( zsn=pEs?bJTtu0lh!Zvd=p|8w(ti`l zvC7H#LR6t-k&KW!UcQXumP8eL%H#dxT-j2lEV<@FOd+5$N0_Z{mMLZWCB2wJZopZn zdx^;~WrRS0Ox(>{um-xxAd#T0tal|k$&KI-0!t-26X=qViGj@nRwA3Ya;n~Er;ZLqK~ zm=9eSyU&X#L{H%uB=NR!vi^Gcg_uJ09FcnoWf;8piVIatp>LIhnsonhxKJC`9YOenw1OFENI8!wx|dqVI`h`7k?g+^kgQ4nsbR zC}aT5dD_@nkz1E*m8JWzSqmP5CPcO}@OSiTTTh-mv?M3SEz z7JCZSk8;5}47=HbB}DYgFN*ZBv!no*%ZILhBfW=DzhK3MSVFXYbGFDVD?8)sVa?LC zEz Date: Tue, 21 Apr 2026 14:31:24 +0300 Subject: [PATCH 115/162] update androidvmtools --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24aba7ec9..c396f8272 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hidden-api = "4.4.0" androidx-navigation = "2.9.7" vbpd = "2.0.4" r8_annotations = "v1.0.1" -androidvmtools = "e7e8de1" +androidvmtools = "22206a0" zygoteloader = "bf5078e182" [plugins] From c8de22ad2a5509dfb9961f92d3d0d122948a5abe Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 21 Apr 2026 15:08:16 +0300 Subject: [PATCH 116/162] Switch to Coil --- app/build.gradle.kts | 3 +- .../hma_oss/ui/fragment/AboutFragment.kt | 36 +++++++++++-------- gradle/libs.versions.toml | 4 ++- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6114e30d3..8f3c40db5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -156,7 +156,8 @@ dependencies { implementation(libs.androidx.navigation.ui.ktx) implementation(libs.androidx.preference.ktx) implementation(libs.androidx.swiperefreshlayout) - implementation(libs.com.github.bumptech.glide) + implementation(libs.io.coilkt.coil3.coil) + implementation(libs.io.coilkt.coil3.coil.network.okhttp) implementation(libs.dev.androidbroadcast.vbpd) implementation(libs.dev.androidbroadcast.vbpd.reflection) implementation(libs.com.github.topjohnwu.libsu.core) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt index 4919e6f01..df48bb790 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AboutFragment.kt @@ -13,9 +13,14 @@ import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.transition.AutoTransition import androidx.transition.TransitionManager -import com.bumptech.glide.Glide +import coil3.load +import coil3.request.crossfade +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.CircleCropTransformation import dev.androidbroadcast.vbpd.viewBinding import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.data.AppConstants.allAppIcons import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.ui.util.AccessibilityUtils import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor @@ -53,14 +58,12 @@ class AboutFragment : Fragment(R.layout.fragment_about) { backgroundTintList = tint } - Glide.with(this@AboutFragment).let { - val activityName = findEnabledAppComponent(requireContext()) - return@let if (activityName == null) { - it.load(R.mipmap.ic_launcher) - } else { - it.load(requireContext().packageManager.getActivityIcon(activityName)) - } - }.circleCrop().into(appIcon) + val activityName = findEnabledAppComponent(requireContext()) + appIcon.setImageResource( + activityName?.let { + allAppIcons.firstOrNull { it.second == activityName.className }?.first + } ?: R.mipmap.ic_launcher + ) appName.setText(R.string.app_name) appVersion.text = BuildConfig.APP_VERSION_NAME @@ -139,7 +142,7 @@ class AboutFragment : Fragment(R.layout.fragment_about) { clipToOutline = true addLibraryItem(this, "ZygoteLoader (fork)", "MIT License", "https://github.com/aerath-stuff/ZygoteLoader") - addLibraryItem(this, "Glide", "Simplified BSD License", "https://github.com/bumptech/glide") + addLibraryItem(this, "Coil", "Apache-2.0 License", "https://github.com/coil-kt/coil") } } @@ -173,11 +176,14 @@ class AboutFragment : Fragment(R.layout.fragment_about) { val newLayout = FragmentAboutListItemBinding.inflate(layoutInflater) if (PrefManager.enableInternet == Constants.ENABLE_INTERNET_ON) { - Glide.with(this) - .load(avatarUrl) - .placeholder(R.drawable.outline_info_24) - .circleCrop() - .into(newLayout.aboutPersonIcon) + newLayout.aboutPersonIcon.load( + avatarUrl, + builder = { + crossfade(true) + placeholder(R.drawable.outline_info_24) + transformations(CircleCropTransformation()) + } + ) } else { newLayout.aboutPersonIcon.isVisible = false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c396f8272..d2401fea4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ vbpd = "2.0.4" r8_annotations = "v1.0.1" androidvmtools = "22206a0" zygoteloader = "bf5078e182" +coil = "3.4.0" [plugins] agp-app = { id = "com.android.application", version.ref = "agp" } @@ -29,7 +30,6 @@ androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version = "1.2.1" } androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version = "1.2.0" } com-android-tools-build-apksig = { module = "com.android.tools.build:apksig", version.ref = "agp" } -com-github-bumptech-glide = { module = "com.github.bumptech.glide:glide", version = "5.0.5" } dev-androidbroadcast-vbpd = { module = "dev.androidbroadcast.vbpd:vbpd", version.ref = "vbpd" } dev-androidbroadcast-vbpd-reflection = { module = "dev.androidbroadcast.vbpd:vbpd-reflection", version.ref = "vbpd" } com-github-topjohnwu-libsu-core = { module = "com.github.topjohnwu.libsu:core", version = "6.0.0" } @@ -40,3 +40,5 @@ material = { module = "com.google.android.material:material", version.ref = "mat me-zhanghai-android-appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" } io-github-vova7878-androidvmtools = { module = "com.github.aerath-stuff:AndroidVMTools", version.ref = "androidvmtools" } io-github-vova7878-r8annotations = { module = "io.github.vova7878:R8Annotations", version.ref = "r8_annotations" } +io-coilkt-coil3-coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } +io-coilkt-coil3-coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } From 78cb8964295cf0194f6befff51bce79500d58ec1 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 25 Apr 2026 18:12:43 +0300 Subject: [PATCH 117/162] Fix comparation errors --- .../main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt | 2 +- .../java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt index 80cb76833..d350eeb6c 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt @@ -30,7 +30,7 @@ class StatAdapter() : RecyclerView.Adapter() { logs[position] = StatItem(packageName, filterCount, PackageHelper.refreshing) - val resort = logs.sortedWith { it1, it2 -> if (it1.totalCount > it2.totalCount) -1 else 0 } + val resort = logs.sortedWith { it1, it2 -> it1.totalCount.compareTo(it2.totalCount) }.asReversed() val newIndex = resort.indexOfFirst { it.packageName == packageName } logs.clear() diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt index 628f7e57c..771776358 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt @@ -38,8 +38,8 @@ class StatsFragment : Fragment(R.layout.fragment_logs) { fun getTotalCount(key: String) = stats.filterCounts[key]!!.totalCount val countsKeys = stats.filterCounts.keys.sortedWith { key1, key2 -> - if (getTotalCount(key1) > getTotalCount(key2)) -1 else 1 - } + getTotalCount(key1).compareTo(getTotalCount(key2)) + }.asReversed() for (key in countsKeys) { adapter.addOrUpdateEntry( From 492feb3dde07bb0dbad20e99390c7151139e6270 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 25 Apr 2026 18:38:24 +0300 Subject: [PATCH 118/162] Refresh stats after retrieving the package list --- .../frknkrc44/hma_oss/ui/adapter/StatAdapter.kt | 16 +++++++++++++--- .../hma_oss/ui/fragment/StatsFragment.kt | 17 ++++++++++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt index d350eeb6c..1846c288e 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/adapter/StatAdapter.kt @@ -7,7 +7,7 @@ import icu.nullptr.hidemyapplist.common.FilterHolder import icu.nullptr.hidemyapplist.util.PackageHelper import org.frknkrc44.hma_oss.databinding.StatItemViewBinding -class StatAdapter() : RecyclerView.Adapter() { +class StatAdapter(private val onBeginWaitForRefresh: (StatAdapter) -> Unit) : RecyclerView.Adapter() { data class StatItem( val packageName: String, @@ -19,16 +19,20 @@ class StatAdapter() : RecyclerView.Adapter() { private val logs = mutableListOf() + var wasRefreshing = false + internal fun addOrUpdateEntry(packageName: String, filterCount: FilterHolder.FilterCount) { val position = logs.indexOfFirst { it.packageName == packageName } + val refreshing = PackageHelper.refreshing + if (position < 0) { - logs.add(StatItem(packageName, filterCount, PackageHelper.refreshing)) + logs.add(StatItem(packageName, filterCount, refreshing)) notifyItemInserted(logs.size - 1) } else { val item = logs[position] if (item.totalCount == filterCount.totalCount && !item.refreshing) return - logs[position] = StatItem(packageName, filterCount, PackageHelper.refreshing) + logs[position] = StatItem(packageName, filterCount, refreshing) val resort = logs.sortedWith { it1, it2 -> it1.totalCount.compareTo(it2.totalCount) }.asReversed() val newIndex = resort.indexOfFirst { it.packageName == packageName } @@ -43,6 +47,12 @@ class StatAdapter() : RecyclerView.Adapter() { notifyItemChanged(position) } } + + if (!wasRefreshing && refreshing) { + wasRefreshing = true + + onBeginWaitForRefresh(this) + } } internal fun clearEntriesIfNotFound(packageNames: Iterable) { diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt index 771776358..f4cc89037 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt @@ -1,9 +1,11 @@ package org.frknkrc44.hma_oss.ui.fragment +import android.annotation.SuppressLint import android.os.Bundle import android.view.MenuItem import android.view.View import androidx.fragment.app.Fragment +import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -14,6 +16,7 @@ import icu.nullptr.hidemyapplist.ui.util.navController import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags import icu.nullptr.hidemyapplist.ui.util.setupToolbar import icu.nullptr.hidemyapplist.ui.util.showToast +import icu.nullptr.hidemyapplist.util.PackageHelper import kotlinx.coroutines.launch import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.databinding.FragmentLogsBinding @@ -22,7 +25,19 @@ import org.frknkrc44.hma_oss.ui.adapter.StatAdapter class StatsFragment : Fragment(R.layout.fragment_logs) { private val binding by viewBinding(FragmentLogsBinding::bind) - private val adapter by lazy { StatAdapter() } + private val adapter by lazy { StatAdapter { + lifecycleScope.launch { + PackageHelper.isRefreshing + .flowWithLifecycle(lifecycle) + .collect { isRefreshing -> + if (!isRefreshing && it.wasRefreshing) { + it.wasRefreshing = false + + updateLogs() + } + } + } + } } private var statCache: String? = null private fun updateLogs() { From c1ab14992f78414f4867dcd9829df8b362589621 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 25 Apr 2026 21:45:30 +0300 Subject: [PATCH 119/162] Improve the preset lists --- .../common/app_presets/DetectorAppsPreset.kt | 1 + .../common/app_presets/RootAppsPreset.kt | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt index 55b710a27..a025c1de3 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/DetectorAppsPreset.kt @@ -34,6 +34,7 @@ class DetectorAppsPreset : BasePreset(NAME) { "com.atominvention.rootchecker", "com.joeykrim.rootcheck", "com.studio.duckdetector", + "com.eltavine.duckdetector", "com.chuqniudetector", "com.chunqiudetector", "com.longz.detector", diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt index 8f9e6df36..2e277d8cd 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt @@ -9,7 +9,16 @@ class RootAppsPreset(private val appPresets: AppPresets) : BasePreset(NAME) { companion object { const val NAME = "root_apps" const val ACCESS_SUPERUSER_PERM = "\u0000a\u0000n\u0000d\u0000r\u0000o\u0000i\u0000d\u0000.\u0000p\u0000e\u0000r\u0000m\u0000i\u0000s\u0000s\u0000i\u0000o\u0000n\u0000.\u0000A\u0000C\u0000C\u0000E\u0000S\u0000S\u0000_\u0000S\u0000U\u0000P\u0000E\u0000R\u0000U\u0000S\u0000E\u0000R" - const val MOZILLA_WHITELIST = "\u0000o\u0000r\u0000g\u0000.\u0000m\u0000o\u0000z\u0000i\u0000l\u0000l\u0000a\u0000.\u0000g\u0000e\u0000c\u0000k\u0000o" + val WHITELISTS = arrayOf( + // Whitelist the Mozilla apps (why a browser app has ACCESS_SUPERUSER?) + "\u0000o\u0000r\u0000g\u0000.\u0000m\u0000o\u0000z\u0000i\u0000l\u0000l\u0000a\u0000.\u0000g\u0000e\u0000c\u0000k\u0000o", + + // Whitelist the Chinese apps (usually games) + "\u0000M\u0000E\u0000I\u0000Z\u0000U\u0000P\u0000U\u0000S\u0000H", + "\u0000h\u0000k\u0000.\u0000a\u0000l\u0000i\u0000p\u0000a\u0000y\u0000.\u0000w\u0000a\u0000l\u0000l\u0000e\u0000t", + "\u0000c\u0000o\u0000m\u0000.\u0000t\u0000e\u0000n\u0000c\u0000e\u0000n\u0000t\u0000.\u0000m\u0000m", + "\u0000c\u0000o\u0000m\u0000.\u0000h\u0000e\u0000y\u0000t\u0000a\u0000p\u0000.", + ) } override val exactPackageNames = setOf( @@ -105,7 +114,7 @@ class RootAppsPreset(private val appPresets: AppPresets) : BasePreset(NAME) { override fun canBeAddedIntoPreset(appInfo: ApplicationInfo): Boolean { val packageName = appInfo.packageName - // Some of detectors trying to abuse the ACCESS_SUPERUSER permission + // Some of the detectors trying to abuse the ACCESS_SUPERUSER permission if (appPresets.getPresetByName(DetectorAppsPreset.NAME)?.containsPackage(packageName) ?: false) { return false } @@ -173,8 +182,8 @@ class RootAppsPreset(private val appPresets: AppPresets) : BasePreset(NAME) { return checkSplitPackages(appInfo) { key, zipFile -> val manifestStr = appPresets.readManifest(key, zipFile) - // Whitelist the Mozilla apps (why a browser app has ACCESS_SUPERUSER?) - if (manifestStr.contains(MOZILLA_WHITELIST)) { + // Check for whitelists + if (Utils.containsMultiple(manifestStr, *WHITELISTS)) { return@checkSplitPackages false } From 2f622937d7325ab8dafe676456d6d9f17eaa4823 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 25 Apr 2026 22:00:31 +0300 Subject: [PATCH 120/162] Move manifest string checker logic in root apps preset --- .../hidemyapplist/common/app_presets/RootAppsPreset.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt index 2e277d8cd..1e249c987 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/app_presets/RootAppsPreset.kt @@ -180,6 +180,10 @@ class RootAppsPreset(private val appPresets: AppPresets) : BasePreset(NAME) { } return checkSplitPackages(appInfo) { key, zipFile -> + if (findAppsFromLibs(zipFile, libNames) || findAppsFromAssets(zipFile, assetNames)) { + return@checkSplitPackages true + } + val manifestStr = appPresets.readManifest(key, zipFile) // Check for whitelists @@ -194,10 +198,6 @@ class RootAppsPreset(private val appPresets: AppPresets) : BasePreset(NAME) { return@checkSplitPackages true } - if (findAppsFromLibs(zipFile, libNames) || findAppsFromAssets(zipFile, assetNames)) { - return@checkSplitPackages true - } - return@checkSplitPackages false } } From 6113aae15b115f60d5daab00d44d5190dc41faa3 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 25 Apr 2026 23:45:15 +0300 Subject: [PATCH 121/162] Merge all log pages into one --- .../hidemyapplist/ui/fragment/LogsFragment.kt | 37 +------ .../nullptr/hidemyapplist/ui/util/Fragment.kt | 1 + .../hma_oss/ui/fragment/HomeFragment.kt | 8 -- .../hma_oss/ui/fragment/StatsFragment.kt | 19 +--- .../hma_oss/ui/fragment/TabbedLogsFragment.kt | 101 ++++++++++++++++++ app/src/main/res/layout/fragment_home.xml | 4 - app/src/main/res/layout/fragment_logs.xml | 20 ---- .../main/res/layout/fragment_tabbed_logs.xml | 38 +++++++ .../main/res/navigation/home_nav_graph.xml | 7 +- .../hidemyapplist/common/JsonConfig.kt | 1 - 10 files changed, 147 insertions(+), 89 deletions(-) create mode 100644 app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/TabbedLogsFragment.kt create mode 100644 app/src/main/res/layout/fragment_tabbed_logs.xml diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt index 473fed91a..6ff228eb9 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/LogsFragment.kt @@ -16,9 +16,6 @@ import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient import icu.nullptr.hidemyapplist.ui.adapter.LogAdapter import icu.nullptr.hidemyapplist.ui.util.contentResolver -import icu.nullptr.hidemyapplist.ui.util.navController -import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags -import icu.nullptr.hidemyapplist.ui.util.setupToolbar import icu.nullptr.hidemyapplist.ui.util.showToast import kotlinx.coroutines.launch import org.frknkrc44.hma_oss.R @@ -28,7 +25,7 @@ import java.util.Date import java.util.Locale -class LogsFragment : Fragment(R.layout.fragment_logs) { +class LogsFragment(private val loadingIndicator: View) : Fragment(R.layout.fragment_logs) { private val binding by viewBinding(FragmentLogsBinding::bind) private val adapter by lazy { LogAdapter(requireContext()) } @@ -62,7 +59,7 @@ class LogsFragment : Fragment(R.layout.fragment_logs) { if (binding.serviceOff.isVisible) return - binding.loadingIndicator.isVisible = true + loadingIndicator.isVisible = true MyApp.hmaApp.globalScope.launch { logCache = try { @@ -93,15 +90,15 @@ class LogsFragment : Fragment(R.layout.fragment_logs) { } lifecycleScope.launch { - binding.loadingIndicator.visibility = View.INVISIBLE + loadingIndicator.visibility = View.INVISIBLE adapter.logs = logList } } } } - private fun onMenuOptionSelected(item: MenuItem) { - if (binding.loadingIndicator.isVisible) return + fun onMenuOptionSelected(item: MenuItem) { + if (loadingIndicator.isVisible) return when (item.itemId) { R.id.menu_refresh -> updateLogs() @@ -142,33 +139,9 @@ class LogsFragment : Fragment(R.layout.fragment_logs) { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - with(binding.toolbar) { - setupToolbar( - toolbar = this, - title = getString(R.string.title_logs), - menuRes = R.menu.menu_logs, - onMenuOptionSelected = this@LogsFragment::onMenuOptionSelected - ) - setNavigationIcon(R.drawable.baseline_arrow_back_24) - setNavigationOnClickListener { navController.popBackStack() } - // isTitleCentered = true - } - - with(binding.toolbar.menu) { - when (PrefManager.logFilter_level) { - 0 -> findItem(R.id.menu_filter_debug).isChecked = true - 1 -> findItem(R.id.menu_filter_info).isChecked = true - 2 -> findItem(R.id.menu_filter_warn).isChecked = true - 3 -> findItem(R.id.menu_filter_error).isChecked = true - } - findItem(R.id.menu_reverse_order).isChecked = PrefManager.logFilter_reverseOrder - } - binding.list.layoutManager = LinearLayoutManager(context) binding.list.adapter = adapter binding.list.addItemDecoration(DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)) updateLogs() - - setEdge2EdgeFlags(binding.root) } } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt index 19d195eb7..9a2156c50 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Fragment.kt @@ -105,6 +105,7 @@ fun Fragment.setupToolbar( } ?: false } } + toolbar.menu.clear() toolbar.inflateMenu(menuRes) toolbar.setOnMenuItemClickListener(menuProvider::onMenuItemSelected) requireActivity().addMenuProvider(menuProvider) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 37b95a246..20b67db7e 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -250,14 +250,6 @@ class HomeFragment : Fragment(R.layout.fragment_home) { } } - with(binding.navStats) { - text1.text = getString(R.string.title_filter_logs) - icon.setImageResource(R.drawable.outline_cleaning_services_24) - root.setOnClickListener { - navigate(R.id.nav_stats) - } - } - with(binding.navSettings) { text1.text = getString(R.string.title_settings) icon.setImageResource(R.drawable.outline_settings_24) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt index f4cc89037..db6e1328c 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/StatsFragment.kt @@ -1,6 +1,5 @@ package org.frknkrc44.hma_oss.ui.fragment -import android.annotation.SuppressLint import android.os.Bundle import android.view.MenuItem import android.view.View @@ -12,9 +11,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import dev.androidbroadcast.vbpd.viewBinding import icu.nullptr.hidemyapplist.common.FilterHolder import icu.nullptr.hidemyapplist.service.ServiceClient -import icu.nullptr.hidemyapplist.ui.util.navController -import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags -import icu.nullptr.hidemyapplist.ui.util.setupToolbar import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper import kotlinx.coroutines.launch @@ -68,7 +64,7 @@ class StatsFragment : Fragment(R.layout.fragment_logs) { } } - private fun onMenuOptionSelected(item: MenuItem) { + fun onMenuOptionSelected(item: MenuItem) { when (item.itemId) { R.id.menu_refresh -> updateLogs() R.id.menu_delete -> { @@ -81,23 +77,10 @@ class StatsFragment : Fragment(R.layout.fragment_logs) { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - with(binding.toolbar) { - setupToolbar( - toolbar = this, - title = getString(R.string.title_filter_logs), - menuRes = R.menu.menu_stats, - onMenuOptionSelected = this@StatsFragment::onMenuOptionSelected, - ) - setNavigationIcon(R.drawable.baseline_arrow_back_24) - setNavigationOnClickListener { navController.popBackStack() } - } - binding.list.layoutManager = LinearLayoutManager(context) binding.list.adapter = adapter binding.list.addItemDecoration(DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)) - setEdge2EdgeFlags(binding.root) - updateLogs() } } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/TabbedLogsFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/TabbedLogsFragment.kt new file mode 100644 index 000000000..4bb3b5525 --- /dev/null +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/TabbedLogsFragment.kt @@ -0,0 +1,101 @@ +package org.frknkrc44.hma_oss.ui.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 +import com.google.android.material.tabs.TabLayoutMediator +import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.service.PrefManager +import icu.nullptr.hidemyapplist.ui.fragment.LogsFragment +import icu.nullptr.hidemyapplist.ui.util.navController +import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags +import icu.nullptr.hidemyapplist.ui.util.setupToolbar +import org.frknkrc44.hma_oss.R +import org.frknkrc44.hma_oss.databinding.FragmentTabbedLogsBinding + +class TabbedLogsFragment : Fragment() { + private val binding by viewBinding(FragmentTabbedLogsBinding::bind) + + private val tabsList by lazy { + listOf( + getString(R.string.title_logs), + getString(R.string.title_filter_logs), + ) + } + + private val logsFragment by lazy { LogsFragment(binding.loadingIndicator) } + private val statsFragment by lazy { StatsFragment() } + + private val pagerAdapter by lazy { + object : FragmentStateAdapter(parentFragmentManager, lifecycle) { + override fun createFragment(index: Int): Fragment { + return when (index) { + 0 -> logsFragment + 1 -> statsFragment + else -> throw UnsupportedOperationException("Invalid tab index: $index") + } + } + + override fun getItemCount() = tabsList.size + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View = inflater.inflate(R.layout.fragment_tabbed_logs, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + with(binding.toolbar) { + setNavigationIcon(R.drawable.baseline_arrow_back_24) + setNavigationOnClickListener { navController.popBackStack() } + } + + with(binding.viewPager) { + adapter = pagerAdapter + registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + when (position) { + 0 -> { + setupToolbar( + binding.toolbar, + title = getString(R.string.title_logs), + menuRes = R.menu.menu_logs, + onMenuOptionSelected = logsFragment::onMenuOptionSelected, + ) + + with(binding.toolbar.menu) { + when (PrefManager.logFilter_level) { + 0 -> findItem(R.id.menu_filter_debug).isChecked = true + 1 -> findItem(R.id.menu_filter_info).isChecked = true + 2 -> findItem(R.id.menu_filter_warn).isChecked = true + 3 -> findItem(R.id.menu_filter_error).isChecked = true + } + findItem(R.id.menu_reverse_order).isChecked = PrefManager.logFilter_reverseOrder + } + } + 1 -> { + setupToolbar( + binding.toolbar, + title = getString(R.string.title_filter_logs), + menuRes = R.menu.menu_stats, + onMenuOptionSelected = statsFragment::onMenuOptionSelected, + ) + } + } + } + }) + } + + TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position -> + tab.text = tabsList[position] + }.attach() + + setEdge2EdgeFlags(binding.root) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 9ea454b65..b87f4576d 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -67,10 +67,6 @@ android:id="@+id/nav_logs" layout="@layout/view_home_item" /> - - diff --git a/app/src/main/res/layout/fragment_logs.xml b/app/src/main/res/layout/fragment_logs.xml index 63157f2fc..c5a0ae0bb 100644 --- a/app/src/main/res/layout/fragment_logs.xml +++ b/app/src/main/res/layout/fragment_logs.xml @@ -4,26 +4,6 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/home_nav_graph.xml b/app/src/main/res/navigation/home_nav_graph.xml index 4c37135de..9b695264d 100644 --- a/app/src/main/res/navigation/home_nav_graph.xml +++ b/app/src/main/res/navigation/home_nav_graph.xml @@ -11,14 +11,9 @@ - - Date: Tue, 28 Apr 2026 00:54:13 +0300 Subject: [PATCH 122/162] Add version info to injection message --- .../main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java index 64d880d0e..255c7713e 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/ZygoteEntry.java @@ -9,6 +9,7 @@ import com.v7878.r8.annotations.DoNotShrinkType; import com.v7878.zygisk.ZygoteLoader; +import org.frknkrc44.hma_oss.common.BuildConfig; import org.frknkrc44.hma_oss.zygote.service.SystemServerHook; @SuppressWarnings("all") @@ -26,7 +27,7 @@ public static void premain() throws Throwable { @DoNotObfuscate @DoNotShrink public static void main() throws Throwable { - logILegacy(TAG, "Injected into " + ZygoteLoader.getPackageName(), null); + logILegacy(TAG, String.format("Injected into %s - %s", ZygoteLoader.getPackageName(), BuildConfig.APP_VERSION_NAME), null); try { SystemServerHook.init(); From 538a7e485e47b4f753dbaad52a4dc5f351e55fc3 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 7 May 2026 21:12:52 +0300 Subject: [PATCH 123/162] Add partial backup/restore (WIP) --- .../hidemyapplist/service/ConfigManager.kt | 17 + .../ui/fragment/BackupRestoreFragment.kt | 349 ++++++++++++++++++ .../hma_oss/ui/fragment/HomeFragment.kt | 51 +-- .../fragment/SettingsTemplateConfFragment.kt | 4 +- .../res/layout/fragment_backup_restore.xml | 118 ++++++ app/src/main/res/menu/menu_backup_restore.xml | 9 + .../main/res/navigation/home_nav_graph.xml | 10 + app/src/main/res/values/strings.xml | 8 + .../nullptr/hidemyapplist/common/Constants.kt | 2 + .../icu/nullptr/hidemyapplist/common/Utils.kt | 9 + .../hma_oss/zygote/service/HMAService.kt | 10 +- 11 files changed, 533 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt create mode 100644 app/src/main/res/layout/fragment_backup_restore.xml create mode 100644 app/src/main/res/menu/menu_backup_restore.xml diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 9c6325337..2690515e2 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -9,6 +9,7 @@ import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper +import kotlinx.serialization.json.Json import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.common.BuildConfig import java.io.File @@ -324,4 +325,20 @@ object ConfigManager { } } } + + fun getRawConfig(deepCopy: Boolean): JsonConfig { + if (deepCopy) { + val scopeCopy = config.scope.toMutableMap() + val templateCopy = config.templates.toMutableMap() + val settingsTemplateCopy = config.settingsTemplates.toMutableMap() + + return config.copy( + scope = scopeCopy, + templates = templateCopy, + settingsTemplates = settingsTemplateCopy, + ) + } + + return config + } } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt new file mode 100644 index 000000000..8bd8740bd --- /dev/null +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -0,0 +1,349 @@ +package org.frknkrc44.hma_oss.ui.fragment + +import android.icu.text.SimpleDateFormat +import android.os.Bundle +import android.view.MenuItem +import androidx.fragment.app.Fragment +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.view.isVisible +import androidx.navigation.fragment.navArgs +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.common.Constants.CONFIG_VERSION_NO_SETTINGS +import icu.nullptr.hidemyapplist.common.JsonConfig +import icu.nullptr.hidemyapplist.common.Utils.cleanRemnantsFromConfig +import icu.nullptr.hidemyapplist.common.Utils.removeIf +import icu.nullptr.hidemyapplist.service.ConfigManager +import icu.nullptr.hidemyapplist.ui.util.contentResolver +import icu.nullptr.hidemyapplist.ui.util.navController +import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags +import icu.nullptr.hidemyapplist.ui.util.setupToolbar +import icu.nullptr.hidemyapplist.ui.util.showToast +import icu.nullptr.hidemyapplist.util.PackageHelper.loadAppLabel +import org.frknkrc44.hma_oss.R +import org.frknkrc44.hma_oss.databinding.FragmentBackupRestoreBinding +import org.frknkrc44.hma_oss.databinding.LayoutListEmptyBinding +import java.util.Date +import java.util.Locale +import kotlin.getValue + +class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { + + private val binding by viewBinding(FragmentBackupRestoreBinding::bind) + + private val args by lazy { navArgs() } + + private val isBackupMode by lazy { args.value.isBackupMode } + private val includeSettings get() = binding.switchSettings.isChecked + private val trimConfig get() = binding.switchTrimConfig.isChecked + private val overwriteApps get() = binding.switchOverwriteApps.isChecked + private val overwriteTemplates get() = binding.switchOverwriteTemplates.isChecked + private val overwriteSettingsTemplates get() = binding.switchOverwriteTemplates.isChecked + + private enum class BRCategory { + APP, + TEMPLATE, + SETTINGS_TEMPLATE, + } + + private val markedForBackup = BRCategory.entries.associateWith { mutableSetOf() } + + private val backupSAFLauncher = + registerForActivityResult(ActivityResultContracts.CreateDocument("application/json")) backup@{ uri -> + if (uri == null) return@backup + contentResolver.openOutputStream(uri).use { output -> + importedConfig?.let { config -> + clearNotImportedItems(config) + + if (!includeSettings) { + val newConfig = JsonConfig(CONFIG_VERSION_NO_SETTINGS) + newConfig.templates.putAll(config.templates) + newConfig.settingsTemplates.putAll(config.settingsTemplates) + newConfig.scope.putAll(config.scope) + importedConfig = newConfig + } + } + + if (output == null) showToast(R.string.home_export_failed) + else { + showToast(R.string.home_exported) + output.write(importedConfig.toString().toByteArray()) + } + + navController.navigateUp() + } + } + + private var importedConfig: JsonConfig? = null + + private val restoreSAFLauncher = + registerForActivityResult(ActivityResultContracts.GetContent()) restore@{ uri -> + if (uri == null) { + navController.navigateUp() + return@restore + } + + runCatching { + val backupContent = contentResolver + .openInputStream(uri)!!.reader().use { it.readText() } + importedConfig = JsonConfig.parse(backupContent) + loadScreenContents() + }.onFailure { + it.printStackTrace() + navController.navigateUp() + MaterialAlertDialogBuilder(requireContext()) + .setCancelable(false) + .setTitle(R.string.home_import_failed) + .setMessage(it.message) + .setPositiveButton(android.R.string.ok, null) + .setNegativeButton(R.string.show_crash_log) { _, _ -> + MaterialAlertDialogBuilder(requireActivity()) + .setCancelable(false) + .setTitle(R.string.home_import_failed) + .setMessage(it.stackTraceToString()) + .setPositiveButton(android.R.string.ok, null) + .show() + } + .show() + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupToolbar( + binding.toolbar, + title = getString(R.string.home_backup_and_restore), + subtitle = getString( + if (isBackupMode) R.string.home_backup_config + else R.string.home_restore_config + ), + menuRes = R.menu.menu_backup_restore, + onMenuOptionSelected = this@BackupRestoreFragment::onMenuOptionSelected + ) + + if (isBackupMode) { + importedConfig = ConfigManager.getRawConfig(true) + loadScreenContents() + } else { + restoreSAFLauncher.launch("application/json") + } + + setEdge2EdgeFlags(binding.root) + } + + private fun reloadScreenContents() { + binding.manageApps.subText = markedForBackup[BRCategory.APP]!!.size.toString() + binding.templateList.subText = markedForBackup[BRCategory.TEMPLATE]!!.size.toString() + binding.settingsTemplateList.subText = markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.size.toString() + } + + private fun loadScreenContents() { + markedForBackup[BRCategory.APP]!!.addAll(importedConfig!!.scope.keys) + markedForBackup[BRCategory.TEMPLATE]!!.addAll(importedConfig!!.templates.keys) + markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.addAll(importedConfig!!.settingsTemplates.keys) + + with(binding.manageApps) { + text = getString(R.string.backup_restore_apps) + setOnClickListener { + showDialogToSelect(BRCategory.APP) + } + } + + with(binding.templateList) { + text = getString(R.string.backup_restore_templates) + setOnClickListener { + showDialogToSelect(BRCategory.TEMPLATE) + } + } + + with(binding.settingsTemplateList) { + text = getString(R.string.backup_restore_settings_templates) + setOnClickListener { + showDialogToSelect(BRCategory.SETTINGS_TEMPLATE) + } + } + + with(binding.switchSettings) { + isChecked = importedConfig!!.configVersion != CONFIG_VERSION_NO_SETTINGS + isEnabled = isChecked + } + + with(binding.switchOverwriteApps) { + isVisible = !isBackupMode + isChecked = true + + setOnCheckedChangeListener { _, value -> + setText( + if (value) { + R.string.settings_overwrite + } else { + R.string.backup_restore_append + } + ) + } + } + + with(binding.switchOverwriteTemplates) { + isVisible = !isBackupMode + isChecked = true + + setOnCheckedChangeListener { _, value -> + setText( + if (value) { + R.string.settings_overwrite + } else { + R.string.backup_restore_append + } + ) + } + } + + with(binding.switchOverwriteSettingsTemplates) { + isVisible = !isBackupMode + isChecked = true + + setOnCheckedChangeListener { _, value -> + setText( + if (value) { + R.string.settings_overwrite + } else { + R.string.backup_restore_append + } + ) + } + } + + reloadScreenContents() + } + + private fun showDialogToSelect(category: BRCategory) { + val items = when (category) { + BRCategory.APP -> importedConfig!!.scope.keys + BRCategory.TEMPLATE -> importedConfig!!.templates.keys + BRCategory.SETTINGS_TEMPLATE -> importedConfig!!.settingsTemplates.keys + } + + val labels = when (category) { + BRCategory.APP -> items.map { loadAppLabel(it) } + BRCategory.TEMPLATE, BRCategory.SETTINGS_TEMPLATE -> items + }.toTypedArray() + + val checked = items.map { + markedForBackup[category]!!.contains(it) + }.toBooleanArray() + + val title = when (category) { + BRCategory.APP -> getString(R.string.title_app_manage) + BRCategory.TEMPLATE, BRCategory.SETTINGS_TEMPLATE -> getString(R.string.title_template_manage) + } + + val dialog = MaterialAlertDialogBuilder(requireContext()) + .setTitle(title) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.ok) { _, _ -> + val category = markedForBackup[category] + category!!.clear() + category.addAll(items.mapIndexedNotNull { i, name -> + if (checked[i]) name else null + }) + + reloadScreenContents() + } + + if (items.isNotEmpty()) { + dialog.setMultiChoiceItems(labels, checked) { _, i, value -> + checked[i] = value + } + } else { + val emptyView = LayoutListEmptyBinding.inflate(layoutInflater) + emptyView.root.isVisible = true + emptyView.listEmptyIcon.setImageResource(R.drawable.sentiment_very_dissatisfied_24px) + emptyView.listEmptyText.isVisible = false + dialog.setView(emptyView.root) + } + + dialog.show() + } + + private fun onRestore() { + clearNotImportedItems(importedConfig!!) + + if (!overwriteApps || !overwriteTemplates) { + val config = ConfigManager.getRawConfig(false) + + if (!overwriteApps) { + config.scope.map { + importedConfig!!.scope.putIfAbsent(it.key, it.value) + } + } + + if (!overwriteTemplates) { + config.templates.map { + importedConfig!!.templates.putIfAbsent(it.key, it.value) + } + } + + if (!overwriteSettingsTemplates) { + config.settingsTemplates.map { + importedConfig!!.settingsTemplates.putIfAbsent(it.key, it.value) + } + } + } + + if (!includeSettings || importedConfig!!.configVersion == CONFIG_VERSION_NO_SETTINGS) { + val currentConfig = ConfigManager.getRawConfig(true) + + with(currentConfig.scope) { + clear() + putAll(importedConfig!!.scope) + } + + with(currentConfig.templates) { + clear() + putAll(importedConfig!!.templates) + } + + with(currentConfig.settingsTemplates) { + clear() + putAll(importedConfig!!.settingsTemplates) + } + + ConfigManager.importConfig(currentConfig.toString()) + } else { + ConfigManager.importConfig(importedConfig!!.toString()) + } + + showToast(android.R.string.ok) + navController.navigateUp() + } + + private fun clearNotImportedItems(config: JsonConfig) { + config.scope.removeIf { pkg, _ -> + !markedForBackup[BRCategory.APP]!!.contains(pkg) + } + + config.templates.removeIf { template, _ -> + !markedForBackup[BRCategory.TEMPLATE]!!.contains(template) + } + + config.settingsTemplates.removeIf { template, _ -> + !markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.contains(template) + } + + if (trimConfig) { + cleanRemnantsFromConfig(config) + } + } + + @Suppress("unused") + private fun onMenuOptionSelected(item: MenuItem) { + if (isBackupMode) { + val date = SimpleDateFormat("yyyy-MM-dd_HH.mm.ss", Locale.getDefault()).format(Date()) + backupSAFLauncher.launch("HMA-OSS_config_$date.json") + } else { + onRestore() + } + } +} diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 20b67db7e..3777bc77c 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -52,46 +52,6 @@ import kotlin.concurrent.thread class HomeFragment : Fragment(R.layout.fragment_home) { private val binding by viewBinding(FragmentHomeBinding::bind) - private val backupSAFLauncher = - registerForActivityResult(ActivityResultContracts.CreateDocument("application/json")) backup@{ uri -> - if (uri == null) return@backup - ConfigManager.configFile.inputStream().use { input -> - contentResolver.openOutputStream(uri).use { output -> - if (output == null) showToast(R.string.home_export_failed) - else input.copyTo(output) - } - } - showToast(R.string.home_exported) - } - - private val restoreSAFLauncher = - registerForActivityResult(ActivityResultContracts.GetContent()) restore@{ uri -> - if (uri == null) return@restore - runCatching { - val backup = contentResolver - .openInputStream(uri)?.reader().use { it?.readText() } - ?: throw IOException(getString(R.string.home_import_file_damaged)) - ConfigManager.importConfig(backup) - showToast(R.string.home_import_successful) - }.onFailure { - it.printStackTrace() - MaterialAlertDialogBuilder(requireContext()) - .setCancelable(false) - .setTitle(R.string.home_import_failed) - .setMessage(it.message) - .setPositiveButton(android.R.string.ok, null) - .setNegativeButton(R.string.show_crash_log) { _, _ -> - MaterialAlertDialogBuilder(requireActivity()) - .setCancelable(false) - .setTitle(R.string.home_import_failed) - .setMessage(it.stackTraceToString()) - .setPositiveButton(android.R.string.ok, null) - .show() - } - .show() - } - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { with(binding.toolbar) { setupToolbar( @@ -270,8 +230,10 @@ class HomeFragment : Fragment(R.layout.fragment_home) { if (PrefManager.systemWallpaper) background.alpha = 0xAA setOnClickListener { - val date = SimpleDateFormat("yyyy-MM-dd_HH.mm.ss", Locale.getDefault()).format(Date()) - backupSAFLauncher.launch("HMA-OSS_config_$date.json") + navigate( + R.id.nav_backup_restore, + BackupRestoreFragmentArgs(true).toBundle() + ) } } @@ -279,7 +241,10 @@ class HomeFragment : Fragment(R.layout.fragment_home) { if (PrefManager.systemWallpaper) background.alpha = 0xAA setOnClickListener { - restoreSAFLauncher.launch("application/json") + navigate( + R.id.nav_backup_restore, + BackupRestoreFragmentArgs(false).toBundle() + ) } } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/SettingsTemplateConfFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/SettingsTemplateConfFragment.kt index a0c872540..babb11cb1 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/SettingsTemplateConfFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/SettingsTemplateConfFragment.kt @@ -101,12 +101,12 @@ class SettingsTemplateConfFragment : Fragment(R.layout.fragment_template_setting lifecycleScope.launch { viewModel.targetSettingList.collect { - binding.targetApps.text = String.format(getString(R.string.template_setting_count), it.size) + binding.targetApps.text = getString(R.string.template_setting_count, it.size) } } lifecycleScope.launch { viewModel.appliedAppList.collect { - binding.appliedApps.text = String.format(getString(R.string.template_applied_count), it.size) + binding.appliedApps.text = getString(R.string.template_applied_count, it.size) } } diff --git a/app/src/main/res/layout/fragment_backup_restore.xml b/app/src/main/res/layout/fragment_backup_restore.xml new file mode 100644 index 000000000..ebf0ea8e7 --- /dev/null +++ b/app/src/main/res/layout/fragment_backup_restore.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_backup_restore.xml b/app/src/main/res/menu/menu_backup_restore.xml new file mode 100644 index 000000000..e710425c1 --- /dev/null +++ b/app/src/main/res/menu/menu_backup_restore.xml @@ -0,0 +1,9 @@ + +

+ + \ No newline at end of file diff --git a/app/src/main/res/navigation/home_nav_graph.xml b/app/src/main/res/navigation/home_nav_graph.xml index 9b695264d..460a5bdf6 100644 --- a/app/src/main/res/navigation/home_nav_graph.xml +++ b/app/src/main/res/navigation/home_nav_graph.xml @@ -199,4 +199,14 @@ + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c26058227..0b3e4d4fb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,6 +61,14 @@ New update available: %s Update: %s + + Backup settings + Restore settings + App configs + Templates + Settings templates + Append + Show system apps Sorting diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt index c245934b8..d7f4df87b 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Constants.kt @@ -30,6 +30,8 @@ object Constants { const val PARCEL_TYPE_LOG = 0 const val PARCEL_TYPE_CONFIG = 1 + const val CONFIG_VERSION_NO_SETTINGS = -100 + /** * Defines the GID for the group that allows write access to the internal media storage. */ diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index 2a6c7bc33..b660600fa 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -105,4 +105,13 @@ object Utils { inline fun MutableMap.removeIf(predicate: (K, V) -> Boolean) { this.filter { (key, value) -> predicate(key, value) }.forEach { this.remove(it.key) } } + + fun cleanRemnantsFromConfig(config: JsonConfig) { + for (app in config.scope.values) { + app.applyTemplates.removeIf { !config.templates.containsKey(it) } + app.applyPresets.removeIf { !AppPresets.instance.presetNames.contains(it) } + app.applySettingTemplates.removeIf { !config.settingsTemplates.containsKey(it) } + app.applySettingsPresets.removeIf { !SettingsPresets.instance.presetNames.contains(it) } + } + } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 5ce9c3838..6d9d3fd71 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -21,6 +21,7 @@ import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.RiskyPackageUtils.appHasGMSConnection import icu.nullptr.hidemyapplist.common.SettingsPresets import icu.nullptr.hidemyapplist.common.Utils.binderLocalScope +import icu.nullptr.hidemyapplist.common.Utils.cleanRemnantsFromConfig import icu.nullptr.hidemyapplist.common.Utils.generateRandomString import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat @@ -468,15 +469,6 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } } - private fun cleanRemnantsFromConfig(config: JsonConfig) { - for (app in config.scope.values) { - app.applyTemplates.removeIf { !config.templates.containsKey(it) } - app.applyPresets.removeIf { !AppPresets.instance.presetNames.contains(it) } - app.applySettingTemplates.removeIf { !config.settingsTemplates.containsKey(it) } - app.applySettingsPresets.removeIf { !SettingsPresets.instance.presetNames.contains(it) } - } - } - override fun getServiceVersion() = BuildConfig.SERVICE_VERSION override fun getFilterCount() = totalFilterCount From e3e6c7be3d5422d81ac3ac78b348c366c1dae59a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 7 May 2026 21:34:03 +0300 Subject: [PATCH 124/162] Fix number format --- .../hma_oss/ui/fragment/BackupRestoreFragment.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 8bd8740bd..de61fa34c 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -1,5 +1,7 @@ package org.frknkrc44.hma_oss.ui.fragment +import android.annotation.SuppressLint +import android.icu.text.NumberFormat import android.icu.text.SimpleDateFormat import android.os.Bundle import android.view.MenuItem @@ -10,6 +12,7 @@ import androidx.core.view.isVisible import androidx.navigation.fragment.navArgs import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.MyApp import icu.nullptr.hidemyapplist.common.Constants.CONFIG_VERSION_NO_SETTINGS import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.Utils.cleanRemnantsFromConfig @@ -133,10 +136,14 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { setEdge2EdgeFlags(binding.root) } + @SuppressLint("DefaultLocale") + @Suppress("deprecation") private fun reloadScreenContents() { - binding.manageApps.subText = markedForBackup[BRCategory.APP]!!.size.toString() - binding.templateList.subText = markedForBackup[BRCategory.TEMPLATE]!!.size.toString() - binding.settingsTemplateList.subText = markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.size.toString() + val numberFormat = NumberFormat.getInstance(MyApp.hmaApp.resources.configuration.locale) + + binding.manageApps.subText = numberFormat.format(markedForBackup[BRCategory.APP]!!.size) + binding.templateList.subText = numberFormat.format(markedForBackup[BRCategory.TEMPLATE]!!.size) + binding.settingsTemplateList.subText = numberFormat.format(markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.size) } private fun loadScreenContents() { From 615c522c8b44da94d479fe9d56d2192c21d861b7 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 15:42:33 +0300 Subject: [PATCH 125/162] Add more clean steps for cleanRemnantsFromConfig --- .../main/java/icu/nullptr/hidemyapplist/common/Utils.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index b660600fa..b8cb691ab 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -107,11 +107,16 @@ object Utils { } fun cleanRemnantsFromConfig(config: JsonConfig) { + // STEP 1: Remove empty app and settings templates + config.templates.removeIf { _, template -> template.appList.isEmpty() } + config.settingsTemplates.removeIf { _, template -> template.settingsList.isEmpty() } + + // STEP 2: Remove mismatching items for (app in config.scope.values) { app.applyTemplates.removeIf { !config.templates.containsKey(it) } - app.applyPresets.removeIf { !AppPresets.instance.presetNames.contains(it) } + app.applyPresets.removeIf { it !in AppPresets.instance.presetNames } app.applySettingTemplates.removeIf { !config.settingsTemplates.containsKey(it) } - app.applySettingsPresets.removeIf { !SettingsPresets.instance.presetNames.contains(it) } + app.applySettingsPresets.removeIf { it !in SettingsPresets.instance.presetNames } } } } From e730020df0fbec56deee5779b7377a1551ec80c6 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 15:57:06 +0300 Subject: [PATCH 126/162] Change random generator --- .../icu/nullptr/hidemyapplist/common/Utils.kt | 26 +++++++------------ .../hma_oss/zygote/service/HMAService.kt | 5 +++- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index b8cb691ab..447a3f26e 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -11,18 +11,17 @@ import java.util.zip.ZipFile object Utils { - fun generateRandomString(length: Int): String { - val leftLimit = 97 // letter 'a' - val rightLimit = 122 // letter 'z' - val random = Random() - val buffer = StringBuilder(length) - for (i in 0 until length) { - val randomLimitedInt = leftLimit + (random.nextFloat() * (rightLimit - leftLimit + 1)).toInt() - buffer.append(randomLimitedInt.toChar()) - } - return buffer.toString() + fun generateRandomString(length: Int, allowedChars: List): String { + return (0 until length) + .map { allowedChars.random() } + .joinToString("") } + fun generateRandomHex(length: Int) = generateRandomString( + length, + ('a' .. 'f') + ('0' .. '9'), + ) + fun binderLocalScope(block: () -> T): T { val identity = Binder.clearCallingIdentity() val result = block() @@ -72,13 +71,6 @@ object Utils { return targets.any { source.contains(it) } } - fun generateRandomHex(length: Int): String { - val allowedChars = ('a'..'f') + ('0'..'9') - return (1..length) - .map { allowedChars.random() } - .joinToString("") - } - fun getPackageNameFromResolveInfo(resolveInfo: ResolveInfo): String { return resolveInfo.resolvePackageName ?: resolveInfo.activityInfo?.packageName ?: diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 6d9d3fd71..d824a2480 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -126,7 +126,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } } if (!this::dataDir.isInitialized) { - dataDir = "/data/misc/hide_my_applist_" + generateRandomString(16) + dataDir = "/data/misc/hide_my_applist_" + generateRandomString( + 16, + ('a'..'z').toList() + ) } File("$dataDir/log").mkdirs() From e9ea923c1894f7070c1a043dad33fd13ebb679c4 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 17:25:16 +0300 Subject: [PATCH 127/162] Trim config on backup mode only --- .../frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index de61fa34c..86c005c5e 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -177,6 +177,10 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { isEnabled = isChecked } + with(binding.switchTrimConfig) { + isVisible = isBackupMode + } + with(binding.switchOverwriteApps) { isVisible = !isBackupMode isChecked = true @@ -339,7 +343,7 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { !markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.contains(template) } - if (trimConfig) { + if (trimConfig && isBackupMode) { cleanRemnantsFromConfig(config) } } From 3d47e52308adc7a4942b7c71c59bc21ba15503ac Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 17:39:01 +0300 Subject: [PATCH 128/162] Prevent showing empty screen on restore config --- .../frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 86c005c5e..70dfb70be 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -115,6 +115,8 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.root.isVisible = false + setupToolbar( binding.toolbar, title = getString(R.string.home_backup_and_restore), @@ -147,6 +149,8 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { } private fun loadScreenContents() { + binding.root.isVisible = true + markedForBackup[BRCategory.APP]!!.addAll(importedConfig!!.scope.keys) markedForBackup[BRCategory.TEMPLATE]!!.addAll(importedConfig!!.templates.keys) markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.addAll(importedConfig!!.settingsTemplates.keys) From c17fc7ef0c045298cc485a21220b9e8d2aa983f9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 17:50:52 +0300 Subject: [PATCH 129/162] Add item count indicator properly --- .../ui/fragment/BackupRestoreFragment.kt | 17 ++++++++++++----- app/src/main/res/values/strings.xml | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 70dfb70be..edde6692a 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -141,11 +141,18 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { @SuppressLint("DefaultLocale") @Suppress("deprecation") private fun reloadScreenContents() { - val numberFormat = NumberFormat.getInstance(MyApp.hmaApp.resources.configuration.locale) - - binding.manageApps.subText = numberFormat.format(markedForBackup[BRCategory.APP]!!.size) - binding.templateList.subText = numberFormat.format(markedForBackup[BRCategory.TEMPLATE]!!.size) - binding.settingsTemplateList.subText = numberFormat.format(markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.size) + binding.manageApps.subText = getString( + R.string.backup_restore_items_count, + markedForBackup[BRCategory.APP]!!.size, + ) + binding.templateList.subText = getString( + R.string.backup_restore_items_count, + markedForBackup[BRCategory.TEMPLATE]!!.size, + ) + binding.settingsTemplateList.subText = getString( + R.string.backup_restore_items_count, + markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.size, + ) } private fun loadScreenContents() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0b3e4d4fb..468cca1b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -68,6 +68,7 @@ Templates Settings templates Append + %d items Show system apps From 187d279ae0db151c1322a5daeff24bc8205e4a5b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 18:13:41 +0300 Subject: [PATCH 130/162] Optimize BackupRestoreFragment code --- .../hidemyapplist/service/ConfigManager.kt | 14 +-- .../ui/fragment/BackupRestoreFragment.kt | 104 ++++++++++-------- 2 files changed, 67 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 2690515e2..ca33e44c0 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -284,38 +284,38 @@ object ConfigManager { saveConfig() } - fun clearUninstalledAppConfigs(onFinish: (success: Boolean) -> Unit) { + fun clearUninstalledAppConfigs(inConfig: JsonConfig = config, onFinish: (success: Boolean) -> Unit) { PackageHelper.invalidateCache { throwable -> if (throwable == null) { // --- STEP 1: Clear uninstalled app configs --- val scopeMarkedToRemove = mutableListOf() - config.scope.keys.forEach { packageName -> + inConfig.scope.keys.forEach { packageName -> if (!PackageHelper.exists(packageName)) { scopeMarkedToRemove.add(packageName) } } if (scopeMarkedToRemove.isNotEmpty()) { - scopeMarkedToRemove.forEach { config.scope.remove(it) } + scopeMarkedToRemove.forEach { inConfig.scope.remove(it) } } // --- STEP 2: Clear uninstalled apps from templates --- var cleanedAppCount = 0 - config.templates.forEach { (key, value) -> + inConfig.templates.forEach { (key, value) -> val newList = value.appList.mapNotNull { if (PackageHelper.exists(it)) it else null }.toSet() val count = value.appList.size - newList.size if (count > 0) { cleanedAppCount += count - config.templates[key] = JsonConfig.Template( + inConfig.templates[key] = JsonConfig.Template( isWhitelist = value.isWhitelist, appList = newList ) } } - ServiceClient.log(Log.INFO, TAG, "Pruned ${scopeMarkedToRemove.size} app config(s) and $cleanedAppCount app(s) from template(s)") - if (scopeMarkedToRemove.isNotEmpty() || cleanedAppCount > 0) { + if ((scopeMarkedToRemove.isNotEmpty() || cleanedAppCount > 0) && inConfig == config) { + ServiceClient.log(Log.INFO, TAG, "Pruned ${scopeMarkedToRemove.size} app config(s) and $cleanedAppCount app(s) from template(s)") saveConfig() } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index edde6692a..86a1967f9 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -1,7 +1,6 @@ package org.frknkrc44.hma_oss.ui.fragment import android.annotation.SuppressLint -import android.icu.text.NumberFormat import android.icu.text.SimpleDateFormat import android.os.Bundle import android.view.MenuItem @@ -9,10 +8,10 @@ import androidx.fragment.app.Fragment import android.view.View import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding -import icu.nullptr.hidemyapplist.MyApp import icu.nullptr.hidemyapplist.common.Constants.CONFIG_VERSION_NO_SETTINGS import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.Utils.cleanRemnantsFromConfig @@ -24,6 +23,7 @@ import icu.nullptr.hidemyapplist.ui.util.setEdge2EdgeFlags import icu.nullptr.hidemyapplist.ui.util.setupToolbar import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper.loadAppLabel +import kotlinx.coroutines.launch import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.databinding.FragmentBackupRestoreBinding import org.frknkrc44.hma_oss.databinding.LayoutListEmptyBinding @@ -37,6 +37,8 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { private val args by lazy { navArgs() } + private lateinit var importedConfig: JsonConfig + private val isBackupMode by lazy { args.value.isBackupMode } private val includeSettings get() = binding.switchSettings.isChecked private val trimConfig get() = binding.switchTrimConfig.isChecked @@ -56,30 +58,26 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { registerForActivityResult(ActivityResultContracts.CreateDocument("application/json")) backup@{ uri -> if (uri == null) return@backup contentResolver.openOutputStream(uri).use { output -> - importedConfig?.let { config -> - clearNotImportedItems(config) - - if (!includeSettings) { - val newConfig = JsonConfig(CONFIG_VERSION_NO_SETTINGS) - newConfig.templates.putAll(config.templates) - newConfig.settingsTemplates.putAll(config.settingsTemplates) - newConfig.scope.putAll(config.scope) - importedConfig = newConfig - } - } - if (output == null) showToast(R.string.home_export_failed) else { - showToast(R.string.home_exported) - output.write(importedConfig.toString().toByteArray()) + clearNotImportedItems { + if (!includeSettings) { + val newConfig = JsonConfig(CONFIG_VERSION_NO_SETTINGS) + newConfig.templates.putAll(importedConfig.templates) + newConfig.settingsTemplates.putAll(importedConfig.settingsTemplates) + newConfig.scope.putAll(importedConfig.scope) + importedConfig = newConfig + } + + showToast(R.string.home_exported) + output.write(importedConfig.toString().toByteArray()) + + navController.navigateUp() + } } - - navController.navigateUp() } } - private var importedConfig: JsonConfig? = null - private val restoreSAFLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) restore@{ uri -> if (uri == null) { @@ -158,9 +156,9 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { private fun loadScreenContents() { binding.root.isVisible = true - markedForBackup[BRCategory.APP]!!.addAll(importedConfig!!.scope.keys) - markedForBackup[BRCategory.TEMPLATE]!!.addAll(importedConfig!!.templates.keys) - markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.addAll(importedConfig!!.settingsTemplates.keys) + markedForBackup[BRCategory.APP]!!.addAll(importedConfig.scope.keys) + markedForBackup[BRCategory.TEMPLATE]!!.addAll(importedConfig.templates.keys) + markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.addAll(importedConfig.settingsTemplates.keys) with(binding.manageApps) { text = getString(R.string.backup_restore_apps) @@ -184,7 +182,7 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { } with(binding.switchSettings) { - isChecked = importedConfig!!.configVersion != CONFIG_VERSION_NO_SETTINGS + isChecked = importedConfig.configVersion != CONFIG_VERSION_NO_SETTINGS isEnabled = isChecked } @@ -242,9 +240,9 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { private fun showDialogToSelect(category: BRCategory) { val items = when (category) { - BRCategory.APP -> importedConfig!!.scope.keys - BRCategory.TEMPLATE -> importedConfig!!.templates.keys - BRCategory.SETTINGS_TEMPLATE -> importedConfig!!.settingsTemplates.keys + BRCategory.APP -> importedConfig.scope.keys + BRCategory.TEMPLATE -> importedConfig.templates.keys + BRCategory.SETTINGS_TEMPLATE -> importedConfig.settingsTemplates.keys } val labels = when (category) { @@ -289,73 +287,91 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { dialog.show() } - private fun onRestore() { - clearNotImportedItems(importedConfig!!) - + private fun onRestore() = clearNotImportedItems { if (!overwriteApps || !overwriteTemplates) { val config = ConfigManager.getRawConfig(false) if (!overwriteApps) { config.scope.map { - importedConfig!!.scope.putIfAbsent(it.key, it.value) + importedConfig.scope.putIfAbsent(it.key, it.value) } } if (!overwriteTemplates) { config.templates.map { - importedConfig!!.templates.putIfAbsent(it.key, it.value) + importedConfig.templates.putIfAbsent(it.key, it.value) } } if (!overwriteSettingsTemplates) { config.settingsTemplates.map { - importedConfig!!.settingsTemplates.putIfAbsent(it.key, it.value) + importedConfig.settingsTemplates.putIfAbsent(it.key, it.value) } } } - if (!includeSettings || importedConfig!!.configVersion == CONFIG_VERSION_NO_SETTINGS) { + if (!includeSettings || importedConfig.configVersion == CONFIG_VERSION_NO_SETTINGS) { val currentConfig = ConfigManager.getRawConfig(true) with(currentConfig.scope) { clear() - putAll(importedConfig!!.scope) + putAll(importedConfig.scope) } with(currentConfig.templates) { clear() - putAll(importedConfig!!.templates) + putAll(importedConfig.templates) } with(currentConfig.settingsTemplates) { clear() - putAll(importedConfig!!.settingsTemplates) + putAll(importedConfig.settingsTemplates) } ConfigManager.importConfig(currentConfig.toString()) } else { - ConfigManager.importConfig(importedConfig!!.toString()) + ConfigManager.importConfig(importedConfig.toString()) } showToast(android.R.string.ok) navController.navigateUp() } - private fun clearNotImportedItems(config: JsonConfig) { - config.scope.removeIf { pkg, _ -> + private fun clearNotImportedItems(onFinish: () -> Unit) { + importedConfig.scope.removeIf { pkg, _ -> !markedForBackup[BRCategory.APP]!!.contains(pkg) } - config.templates.removeIf { template, _ -> + importedConfig.templates.removeIf { template, _ -> !markedForBackup[BRCategory.TEMPLATE]!!.contains(template) } - config.settingsTemplates.removeIf { template, _ -> + importedConfig.settingsTemplates.removeIf { template, _ -> !markedForBackup[BRCategory.SETTINGS_TEMPLATE]!!.contains(template) } - if (trimConfig && isBackupMode) { - cleanRemnantsFromConfig(config) + if (isBackupMode) { + cleanRemnantsFromConfig(importedConfig) + + if (trimConfig) { + val progressDialog = MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.settings_clear_uninstalled_app_configs) + .setView(R.layout.dialog_loading) + .setCancelable(false) + .create() + + ConfigManager.clearUninstalledAppConfigs(importedConfig) { + lifecycleScope.launch { + progressDialog.dismiss() + + onFinish() + } + } + } else { + onFinish() + } + } else { + onFinish() } } From b2be3a639bb2264f4593f6c284c143f70fd4ef27 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 18:22:38 +0300 Subject: [PATCH 131/162] Simplify clearUninstalledAppConfigs --- .../hidemyapplist/service/ConfigManager.kt | 17 ++++++----------- .../icu/nullptr/hidemyapplist/common/Utils.kt | 5 ++++- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index ca33e44c0..1a5b34478 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -6,6 +6,8 @@ import android.util.Log import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig +import icu.nullptr.hidemyapplist.common.Utils.removeIf +import icu.nullptr.hidemyapplist.common.Utils.removeIfWithCount import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper @@ -288,15 +290,8 @@ object ConfigManager { PackageHelper.invalidateCache { throwable -> if (throwable == null) { // --- STEP 1: Clear uninstalled app configs --- - val scopeMarkedToRemove = mutableListOf() - inConfig.scope.keys.forEach { packageName -> - if (!PackageHelper.exists(packageName)) { - scopeMarkedToRemove.add(packageName) - } - } - - if (scopeMarkedToRemove.isNotEmpty()) { - scopeMarkedToRemove.forEach { inConfig.scope.remove(it) } + val scopeRemoveCount = inConfig.scope.removeIfWithCount { pkg, _ -> + !PackageHelper.exists(pkg) } // --- STEP 2: Clear uninstalled apps from templates --- @@ -314,8 +309,8 @@ object ConfigManager { } } - if ((scopeMarkedToRemove.isNotEmpty() || cleanedAppCount > 0) && inConfig == config) { - ServiceClient.log(Log.INFO, TAG, "Pruned ${scopeMarkedToRemove.size} app config(s) and $cleanedAppCount app(s) from template(s)") + if ((scopeRemoveCount > 0 || cleanedAppCount > 0) && inConfig == config) { + ServiceClient.log(Log.INFO, TAG, "Pruned $scopeRemoveCount app config(s) and $cleanedAppCount app(s) from template(s)") saveConfig() } diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index 447a3f26e..eb0dad5e6 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -6,7 +6,6 @@ import android.content.pm.PackageInfo import android.content.pm.ResolveInfo import android.os.Binder import android.os.Build -import java.util.Random import java.util.zip.ZipFile object Utils { @@ -98,6 +97,10 @@ object Utils { this.filter { (key, value) -> predicate(key, value) }.forEach { this.remove(it.key) } } + inline fun MutableMap.removeIfWithCount(predicate: (K, V) -> Boolean): Int { + return this.filter { (key, value) -> predicate(key, value) }.count { this.remove(it.key) != null } + } + fun cleanRemnantsFromConfig(config: JsonConfig) { // STEP 1: Remove empty app and settings templates config.templates.removeIf { _, template -> template.appList.isEmpty() } From 881cbdb7775ebc29484feb00499e2fb0f2b89213 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 18:28:03 +0300 Subject: [PATCH 132/162] Try to avoid .use for output stream --- .../ui/fragment/BackupRestoreFragment.kt | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 86a1967f9..6cf55a0b4 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -57,23 +57,24 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { private val backupSAFLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("application/json")) backup@{ uri -> if (uri == null) return@backup - contentResolver.openOutputStream(uri).use { output -> - if (output == null) showToast(R.string.home_export_failed) - else { - clearNotImportedItems { - if (!includeSettings) { - val newConfig = JsonConfig(CONFIG_VERSION_NO_SETTINGS) - newConfig.templates.putAll(importedConfig.templates) - newConfig.settingsTemplates.putAll(importedConfig.settingsTemplates) - newConfig.scope.putAll(importedConfig.scope) - importedConfig = newConfig - } - - showToast(R.string.home_exported) - output.write(importedConfig.toString().toByteArray()) - - navController.navigateUp() + val output = contentResolver.openOutputStream(uri) + + if (output == null) showToast(R.string.home_export_failed) + else { + clearNotImportedItems { + if (!includeSettings) { + val newConfig = JsonConfig(CONFIG_VERSION_NO_SETTINGS) + newConfig.templates.putAll(importedConfig.templates) + newConfig.settingsTemplates.putAll(importedConfig.settingsTemplates) + newConfig.scope.putAll(importedConfig.scope) + importedConfig = newConfig } + + showToast(R.string.home_exported) + output.write(importedConfig.toString().toByteArray()) + output.close() + + navController.navigateUp() } } } From d3c6522af6ca842a360f56e58e64e0ab30041e79 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 18:33:36 +0300 Subject: [PATCH 133/162] Fix margins of Switch widgets --- app/src/main/res/layout/fragment_backup_restore.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/res/layout/fragment_backup_restore.xml b/app/src/main/res/layout/fragment_backup_restore.xml index ebf0ea8e7..6986059ef 100644 --- a/app/src/main/res/layout/fragment_backup_restore.xml +++ b/app/src/main/res/layout/fragment_backup_restore.xml @@ -61,7 +61,6 @@ Date: Fri, 8 May 2026 18:38:04 +0300 Subject: [PATCH 134/162] Optimize imports --- .../java/icu/nullptr/hidemyapplist/service/ConfigManager.kt | 2 -- .../frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt | 3 +-- .../java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt | 6 ------ 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 1a5b34478..05c20aff5 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -6,12 +6,10 @@ import android.util.Log import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig -import icu.nullptr.hidemyapplist.common.Utils.removeIf import icu.nullptr.hidemyapplist.common.Utils.removeIfWithCount import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper -import kotlinx.serialization.json.Json import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.common.BuildConfig import java.io.File diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 6cf55a0b4..40bdc40df 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -4,10 +4,10 @@ import android.annotation.SuppressLint import android.icu.text.SimpleDateFormat import android.os.Bundle import android.view.MenuItem -import androidx.fragment.app.Fragment import android.view.View import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible +import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -29,7 +29,6 @@ import org.frknkrc44.hma_oss.databinding.FragmentBackupRestoreBinding import org.frknkrc44.hma_oss.databinding.LayoutListEmptyBinding import java.util.Date import java.util.Locale -import kotlin.getValue class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt index 3777bc77c..eab1b3d9c 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/HomeFragment.kt @@ -9,7 +9,6 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView -import androidx.activity.result.contract.ActivityResultContracts import androidx.core.net.toUri import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -25,7 +24,6 @@ import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.attrDrawable import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.getColor import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.themeColor -import icu.nullptr.hidemyapplist.ui.util.contentResolver import icu.nullptr.hidemyapplist.ui.util.dp2Px import icu.nullptr.hidemyapplist.ui.util.isTestBuild import icu.nullptr.hidemyapplist.ui.util.navigate @@ -38,10 +36,6 @@ import kotlinx.coroutines.withContext import org.frknkrc44.hma_oss.BuildConfig import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.databinding.FragmentHomeBinding -import java.io.IOException -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale import kotlin.concurrent.thread /** From f93177d692664f1a169b774ce56285710e99e576 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 18:47:56 +0300 Subject: [PATCH 135/162] Trim config on both backup and restore --- .../ui/fragment/BackupRestoreFragment.kt | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 40bdc40df..2edd641c7 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -186,10 +186,6 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { isEnabled = isChecked } - with(binding.switchTrimConfig) { - isVisible = isBackupMode - } - with(binding.switchOverwriteApps) { isVisible = !isBackupMode isChecked = true @@ -352,23 +348,23 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { if (isBackupMode) { cleanRemnantsFromConfig(importedConfig) + } - if (trimConfig) { - val progressDialog = MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.settings_clear_uninstalled_app_configs) - .setView(R.layout.dialog_loading) - .setCancelable(false) - .create() + if (trimConfig) { + val progressDialog = MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.settings_clear_uninstalled_app_configs) + .setView(R.layout.dialog_loading) + .setCancelable(false) + .create() - ConfigManager.clearUninstalledAppConfigs(importedConfig) { - lifecycleScope.launch { - progressDialog.dismiss() + progressDialog.show() - onFinish() - } + ConfigManager.clearUninstalledAppConfigs(importedConfig) { + lifecycleScope.launch { + progressDialog.dismiss() + + onFinish() } - } else { - onFinish() } } else { onFinish() From 7d4ef8bd09ce438b1c3e44279b2e4890382e1a6b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 8 May 2026 18:52:27 +0300 Subject: [PATCH 136/162] Show toolbar on pre restore config --- .../frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt | 5 ++--- app/src/main/res/layout/fragment_backup_restore.xml | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 2edd641c7..a982dc40d 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -113,8 +113,6 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.root.isVisible = false - setupToolbar( binding.toolbar, title = getString(R.string.home_backup_and_restore), @@ -130,6 +128,7 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { importedConfig = ConfigManager.getRawConfig(true) loadScreenContents() } else { + binding.mainLayout.isVisible = false restoreSAFLauncher.launch("application/json") } @@ -154,7 +153,7 @@ class BackupRestoreFragment : Fragment(R.layout.fragment_backup_restore) { } private fun loadScreenContents() { - binding.root.isVisible = true + binding.mainLayout.isVisible = true markedForBackup[BRCategory.APP]!!.addAll(importedConfig.scope.keys) markedForBackup[BRCategory.TEMPLATE]!!.addAll(importedConfig.templates.keys) diff --git a/app/src/main/res/layout/fragment_backup_restore.xml b/app/src/main/res/layout/fragment_backup_restore.xml index 6986059ef..a1200695d 100644 --- a/app/src/main/res/layout/fragment_backup_restore.xml +++ b/app/src/main/res/layout/fragment_backup_restore.xml @@ -21,6 +21,7 @@ From 680e9f7cb4a3f053dbbd515e27bd1d437144e24b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 9 May 2026 14:24:18 +0300 Subject: [PATCH 137/162] Remove xposed code --- .gitignore | 1 + .../nullptr/hidemyapplist/xposed/Logcat.kt | 66 ---- .../hidemyapplist/xposed/Utils4Xposed.kt | 38 --- .../hidemyapplist/xposed/XposedEntry.kt | 71 ---- .../xposed/hook/AccessibilityHook.kt | 68 ---- .../hidemyapplist/xposed/hook/ActivityHook.kt | 156 --------- .../xposed/hook/AppDataIsolationHook.kt | 217 ------------ .../xposed/hook/ContentProviderHook.kt | 172 ---------- .../hidemyapplist/xposed/hook/ImmHook.kt | 190 ----------- .../xposed/hook/PmsHookTarget29.kt | 36 -- .../xposed/hook/PmsHookTarget30.kt | 81 ----- .../xposed/hook/PmsHookTarget31.kt | 95 ------ .../xposed/hook/PmsHookTarget33.kt | 78 ----- .../xposed/hook/PmsHookTarget34.kt | 100 ------ .../xposed/hook/PmsHookTargetBase.kt | 321 ------------------ .../xposed/hook/PmsPackageEventsHook.kt | 57 ---- .../hidemyapplist/xposed/hook/ZygoteHook.kt | 51 --- 17 files changed, 1 insertion(+), 1797 deletions(-) delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Logcat.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget33.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget34.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt delete mode 100644 xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt diff --git a/.gitignore b/.gitignore index 257b15f0c..208a0004e 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,4 @@ updates/ translators.json .kotlin/ +xposed/ diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Logcat.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Logcat.kt deleted file mode 100644 index ba3604550..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Logcat.kt +++ /dev/null @@ -1,66 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed - -import android.os.SystemProperties -import android.util.Log -import de.robv.android.xposed.XposedBridge -import org.frknkrc44.hma_oss.common.BuildConfig -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale - -@Suppress("SpellCheckingInspection") -object Logcat { - private var logdReady: Boolean? = null - - fun logV(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.VERBOSE, tag, cause, msg) - - fun logD(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.DEBUG, tag, cause, msg) - - fun logI(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.INFO, tag, cause, msg) - - fun logW(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.WARN, tag, cause, msg) - - fun logE(tag: String, cause: Throwable? = null, msg: () -> String) = logWithLevel(Log.ERROR, tag, cause, msg) - - fun logWithLevel(level: Int, tag: String, cause: Throwable? = null, msg: () -> String) { - if (level != Log.ERROR && HMAService.instance?.config?.errorOnlyLog == true) return - if (level <= Log.DEBUG && HMAService.instance?.config?.detailLog == false) return - if (level == Log.VERBOSE && !BuildConfig.DEBUG) return - - val parsedMsg = parseLog(level, tag, msg(), cause) - - HMAService.instance?.apply { - executor.execute { - addLog(parsedMsg) - println(parsedMsg) - } - } ?: println(parsedMsg) - } - - private fun parseLog(level: Int, tag: String, msg: String, cause: Throwable? = null) = buildString { - val levelStr = when (level) { - Log.VERBOSE -> "VERBS" - Log.DEBUG -> "DEBUG" - Log.INFO -> " INFO" - Log.WARN -> " WARN" - Log.ERROR -> "ERROR" - else -> "?WTF?" - } - val date = SimpleDateFormat("MM-dd HH:mm:ss", Locale.getDefault()).format(Date()) - append("[$levelStr] <$date> ($tag) $msg") - if (!endsWith('\n')) append('\n') - if (cause != null) append(Log.getStackTraceString(cause)) - if (!endsWith('\n')) append('\n') - } - - - private fun println(msg: String) { - if (logdReady == null) { - logdReady = SystemProperties.get("init.svc.logd") == "running" - } - - if (logdReady != true) return - - XposedBridge.log(msg) - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt deleted file mode 100644 index 34a4fc493..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/Utils4Xposed.kt +++ /dev/null @@ -1,38 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed - -import android.app.ActivityThread -import android.os.Binder -import android.os.Build -import com.github.kyuubiran.ezxhelper.utils.findField -import de.robv.android.xposed.XposedHelpers.callMethod -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils - -object Utils4Xposed { - fun getPackageNameFromPackageSettings(packageSettings: Any?): String? { - if (packageSettings == null) return null - - return try { - callMethod(packageSettings, "getPackageName") as String? - } catch (_: Throwable) { - runCatching { - findField(packageSettings::class.java, true) { - name == if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) "mName" else "name" - }.get(packageSettings) as? String - }.getOrNull() - } - } - - fun getPackageManager() = ActivityThread.currentActivityThread().application.packageManager!! - - fun getCallingApps(service: HMAService): Array { - return getCallingApps(service, Binder.getCallingUid()) - } - - fun getCallingApps(service: HMAService, callingUid: Int): Array { - if (callingUid == Constants.UID_SYSTEM) return arrayOf() - return Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: arrayOf() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt deleted file mode 100644 index cb8fab011..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt +++ /dev/null @@ -1,71 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed - -import android.content.pm.IPackageManager -import com.github.kyuubiran.ezxhelper.init.EzXHelperInit -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.IXposedHookLoadPackage -import de.robv.android.xposed.IXposedHookZygoteInit -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.callbacks.XC_LoadPackage -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Logcat.logE -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import kotlin.concurrent.thread - -private const val TAG = "HMA-XposedEntry" - -@Suppress("unused") -class XposedEntry : IXposedHookZygoteInit, IXposedHookLoadPackage { - var targetsLeft = mutableListOf("package", "package_native") - var targetStorage = mutableMapOf() - - override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { - EzXHelperInit.initZygote(startupParam) - } - - override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { - if (lpparam.packageName == Constants.ANDROID_PACKAGE_NAME) { - EzXHelperInit.initHandleLoadPackage(lpparam) - logI(TAG) { "Hook entry" } - - var serviceManagerHook: XC_MethodHook.Unhook? = null - serviceManagerHook = findMethod("android.os.ServiceManager") { - name == "addService" - }.hookBefore { param -> - val name = param.args[0] as String - if (targetsLeft.contains(name)) { - when (name) { - "package", "package_native" -> { - targetStorage[name] = param.args[1] - targetsLeft.remove(name) - } - else -> { - // skip if there is no package_native available - if (targetStorage.containsKey("package")) { - targetsLeft.remove("package_native") - } - } - } - } - - if (targetsLeft.isEmpty()) { - serviceManagerHook?.unhook() - val pms = targetStorage["package"] as IPackageManager - val pmn = targetStorage["package_native"] - logD(TAG) { "Got pms: $pms, $pmn" } - thread { - runCatching { - UserService.register(pms, pmn) - targetStorage.clear() - logI(TAG) { "User service started" } - }.onFailure { - logE(TAG, it) { "System service crashed" } - } - } - } - } - } - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt deleted file mode 100644 index cd169fa84..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AccessibilityHook.kt +++ /dev/null @@ -1,68 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.accessibilityservice.AccessibilityServiceInfo -import android.content.pm.ParceledListSlice -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACCESSIBILITY_SERVICE_CLASS -import java.lang.reflect.Method - -// Big credits: https://github.com/Nitsuya/DoNotTryAccessibility/blob/main/app/src/main/java/io/github/nitsuya/donottryaccessibility/hook/AndroidFrameworkHooker.kt -class AccessibilityHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "AccessibilityHook" - } - - private val hookList = mutableSetOf() - - override fun load() { - logI(TAG) { "Load hook" } - - hookList += findMethod(ACCESSIBILITY_SERVICE_CLASS) { - name == "getEnabledAccessibilityServiceList" - }.hookBefore { param -> - val callingApps = Utils4Xposed.getCallingApps(service) - if (callingApps.isEmpty()) return@hookBefore - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - val returnedList = java.util.ArrayList() - - logD(TAG) { "@${param.method.name} returned empty list for ${callingApps.contentToString()}" } - - val returnType = (param.method as Method).returnType - param.result = if ("Parcel" in returnType.javaClass.simpleName) { - ParceledListSlice(returnedList) - } else { - returnedList - } - } - } - - hookList += findMethod(ACCESSIBILITY_SERVICE_CLASS) { - name == "addClient" - }.hookBefore { param -> - val callingApps = Utils4Xposed.getCallingApps(service) - if (callingApps.isEmpty()) return@hookBefore - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - param.result = 0L - } - } - } - - private fun callerIsSpoofed(caller: String) = - service.getEnabledSettingsPresets(caller).contains(AccessibilityPreset.NAME) - - override fun unload() { - hookList.forEach(XC_MethodHook.Unhook::unhook) - hookList.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt deleted file mode 100644 index 04ca6af8d..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ActivityHook.kt +++ /dev/null @@ -1,156 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.Intent -import android.content.pm.ResolveInfo -import android.os.Build -import com.github.kyuubiran.ezxhelper.init.InitFields -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedHelpers.findClass -import de.robv.android.xposed.XposedHelpers.getObjectField -import de.robv.android.xposed.XposedHelpers.getStaticIntField -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.OSUtils -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Logcat.logE -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Logcat.logV -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACTIVITY_STACK_SUPERVISOR_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACTIVITY_STARTER_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ACTIVITY_TASK_SUPERVISOR_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.COMPUTER_ENGINE_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS - -class ActivityHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "ActivityHook" - private val fakeReturnCode by lazy { - getStaticIntField( - findClass( - "android.app.ActivityManager", - InitFields.ezXClassLoader - ), - "START_CLASS_NOT_FOUND" - ) - } - } - - private val hooks = mutableListOf() - - override fun load() { - logI(TAG) { "Load hook" } - - hooks += findMethod(ACTIVITY_STARTER_CLASS) { - name == "execute" - }.hookBefore { param -> - runCatching { - val request = getObjectField(param.thisObject, "mRequest") - val caller = getObjectField(request, "callingPackage") as String? - val intent = getObjectField(request, "intent") as Intent? - val targetApp = intent?.component?.packageName - - if (service.shouldHideActivityLaunch(caller, targetApp)) { - logD(TAG) { - "@executeRequest: insecure query from $caller, target: ${intent?.component}" - } - param.result = fakeReturnCode - service.increaseALFilterCount(caller) - } - }.onFailure { - logE(TAG, it) { "Fatal error occurred, ignore hook" } - // unload() - } - } - - findMethodOrNull(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - ACTIVITY_TASK_SUPERVISOR_CLASS - } else { - ACTIVITY_STACK_SUPERVISOR_CLASS - }) { - name == "checkStartAnyActivityPermission" - }?.hookAfter { param -> - var throwable = param.throwable - - while (throwable != null) { - val newTrace = throwable.stackTrace.filter { item -> - !Utils.containsMultiple( - item.className, - "HookBridge", - "LSPHooker", - "LSPosed", - ) - } - - if (newTrace.size != throwable.stackTrace.size) { - throwable.stackTrace = newTrace.toTypedArray() - - val callingUid = param.args.lastOrNull { it is Int } as Int? - - logD(TAG) { "@checkStartAnyActivityPermission: ${throwable.stackTrace.size - newTrace.size} remnants cleared for $callingUid!" } - - service.increaseALFilterCount(callingUid) - } - - throwable = throwable.cause - } - }?.let { - hooks += it - logD(TAG) { "Loaded ${it.hookedMethod.name} hook from ${it.hookedMethod.declaringClass}!" } - } - - if (!OSUtils.isSamsung()) { - hooks += findMethod( - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - COMPUTER_ENGINE_CLASS - } else { - PACKAGE_MANAGER_SERVICE_CLASS - }, - findSuper = Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU, - ) { - name == "applyPostResolutionFilter" - }.hookBefore { param -> - @Suppress("UNCHECKED_CAST") // I know what I do - val list = param.args.first() as List? - if (list.isNullOrEmpty()) return@hookBefore - - val callingUid = param.args.first { it is Int } as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = Utils4Xposed.getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller != null) { - logV(TAG) { "@${param.method.name}: $caller requested a resolve info" } - - val filteredList = list.filter { resolveInfo -> - val targetApp = Utils.getPackageNameFromResolveInfo(resolveInfo) - - logV(TAG) { "@${param.method.name}: Checking $targetApp for $caller" } - - (!service.shouldHideActivityLaunch(caller, targetApp)).apply { - if (!this) { - logD(TAG) { "@${param.method.name}: Filtered $targetApp from $caller" } - } - } - } - - if (filteredList.size != list.size) { - param.args[0] = filteredList.toList() - - service.increasePMFilterCount(caller) - } - } - } - } - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt deleted file mode 100644 index 95427e505..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/AppDataIsolationHook.kt +++ /dev/null @@ -1,217 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.os.Build -import android.os.SystemProperties -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedHelpers -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Logcat.logE -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.XposedConstants.STORAGE_MANAGER_SERVICE_CLASS -import org.frknkrc44.hma_oss.common.BuildConfig - -@RequiresApi(Build.VERSION_CODES.R) -class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { - - companion object { - private const val TAG = "AppDataIsolationHook" - private const val APPDATA_ISOLATION_ENABLED = "mAppDataIsolationEnabled" - private const val VOLD_APPDATA_ISOLATION_ENABLED = "mVoldAppDataIsolationEnabled" - private const val FUSE_PROP = "persist.sys.fuse" - } - - private val hooks = mutableListOf() - private var voldHookSkipped = false - - override fun load() { - if (!(service.config.altAppDataIsolation || service.config.altVoldAppDataIsolation)) return - logI(TAG) { "Load hook" } - - findMethodOrNull( - "com.android.server.am.ProcessList" - ) { - name == "startProcess" - }?.hookBefore { param -> - if (service.config.altAppDataIsolation) { - val isEnabled = XposedHelpers.getBooleanField( - param.thisObject, - APPDATA_ISOLATION_ENABLED - ) - - if (!isEnabled) { - XposedHelpers.setBooleanField( - param.thisObject, - APPDATA_ISOLATION_ENABLED, - true - ) - - logI(TAG) { "ProcessList - App data isolation is forced" } - } - } - - if (service.config.altVoldAppDataIsolation && !voldHookSkipped) { - val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) - - if (!fuseEnabled) { - voldHookSkipped = true - logE(TAG) { "ProcessList - FUSE storage is not enabled, skip vold hook" } - } else { - val isolationEnabled = XposedHelpers.getBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED - ) - - if (!isolationEnabled) { - XposedHelpers.setBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED, - true - ) - - logI(TAG) { "ProcessList - Vold app data isolation is forced" } - } - } - } - }?.let { - hooks += it - } - - findMethodOrNull( - "com.android.server.am.ProcessList" - ) { - name == "needsStorageDataIsolation" - }?.hookAfter { param -> - if (service.config.altVoldAppDataIsolation) { - val app = param.args.find { it.javaClass.simpleName == "ProcessRecord" } - val uid = XposedHelpers.getIntField(app, "uid") - val processName = runCatching { - XposedHelpers.getObjectField(app, "processName") - }.getOrDefault("") - val mountNode = runCatching { - XposedHelpers.getIntField(app, "mMountMode") - }.getOrDefault(0) - val isolated = runCatching { - XposedHelpers.getBooleanField(app, "isolated") - }.getOrDefault(false) - val appZygote = runCatching { - XposedHelpers.getBooleanField(app, "appZygote") - }.getOrDefault(false) - - val apps = Utils.binderLocalScope { - service.pms.getPackagesForUid(uid) - } ?: return@hookAfter - - logD(TAG) { - "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" - } - - // Do not isolate this module for safety - if (apps.contains(BuildConfig.APP_PACKAGE_NAME)) { - param.result = false - return@hookAfter - } - - if (apps.any { service.isAppDataIsolationExcluded(it) }) { - param.result = false - } - - if (service.config.skipSystemAppDataIsolation) { - val isSystemApp = service.systemApps.any { apps.contains(it) } - logD(TAG) { - "@needsStorageDataIsolation $uid and ${apps.contentToString()} - isSystemApp: $isSystemApp" - } - - if (isSystemApp) { - param.result = false - return@hookAfter - } - } - } - }?.let { - hooks += it - } - - findMethodOrNull(STORAGE_MANAGER_SERVICE_CLASS) { - name == "onVolumeStateChangedLocked" - }?.hookBefore { param -> - runCatching { - if (service.config.altVoldAppDataIsolation) { - val fuseEnabled = SystemProperties.getBoolean(FUSE_PROP, false) - - if (!fuseEnabled) { - logE(TAG) { "StorageManagerService - FUSE storage is not enabled, disable hooks" } - unload() - return@hookBefore - } - - val isolationEnabled = XposedHelpers.getBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED - ) - - if (!isolationEnabled) { - XposedHelpers.setBooleanField( - param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED, - true - ) - - logI(TAG) { "StorageManagerService - Vold app data isolation is forced" } - } - } - }.onFailure { - logE(TAG, it) { "Fatal error occurred, disable hooks" } - unload() - } - }?.let { - hooks += it - } - - findMethodOrNull(STORAGE_MANAGER_SERVICE_CLASS) { - name == "remountAppStorageDirs" - }?.hookBefore { param -> - if (service.config.altVoldAppDataIsolation && service.config.skipSystemAppDataIsolation) { - @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - val pidPkgMap = param.args[0] as java.util.Map<*, *> - val userId = param.args[1] as Int - - val keysToRemove = mutableSetOf() - - for (entry in pidPkgMap.entrySet()) { - val pid = entry.key - val packageName = entry.value as String - - val apps = Utils.binderLocalScope { - val uid = Utils.getPackageUidCompat(service.pms, packageName, 0L, userId) - service.pms.getPackagesForUid(uid) - } ?: continue - - for (app in apps) { - if (app in service.systemApps || app == BuildConfig.APP_PACKAGE_NAME) { - logD(TAG) { - "@remountAppStorageDirs SYSTEM $pid - $packageName is marked to remove" - } - keysToRemove += pid - break - } - } - } - - keysToRemove.forEach { pidPkgMap.remove(it) } - } - }?.let { - hooks += it - } - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt deleted file mode 100644 index 7368718c8..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ContentProviderHook.kt +++ /dev/null @@ -1,172 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.AttributionSource -import android.database.Cursor -import android.database.MatrixCursor -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.provider.Settings -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.CONTENT_PROVIDER_TRANSPORT_CLASS - -class ContentProviderHook(private val service: HMAService): IFrameworkHook { - companion object { - private const val TAG = "ContentProviderHook" - private val NV_PAIR = arrayOf("name", "value") - } - - private val hooks = mutableListOf() - - @Suppress("UNCHECKED_CAST") - override fun load() { - hooks += findMethod(CONTENT_PROVIDER_TRANSPORT_CLASS) { - name == "query" - }.hookAfter { param -> - val callingApps = getCallingPackages(param) - - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller == null) return@hookAfter - - val uri = param.args[1] as Uri? - val projection = param.args[2] as Array? - val args = param.args[3] as Bundle? - - if (uri?.authority != "settings") return@hookAfter - - val segments = uri.pathSegments - if (segments.isEmpty()) return@hookAfter - - logD(TAG) { "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args" } - - val database = segments[0] - - if (segments.size >= 2) { - val name = segments[1] - - logD(TAG) { "@spoofSettings QUERY received caller: $caller, database: $database, name: $name" } - - val replacement = service.getSpoofedSetting(caller, name, database) - if (replacement != null) { - logD(TAG) { "@spoofSettings QUERY $name in $database replaced for $caller" } - param.result = MatrixCursor(arrayOf("name", "value"), 1).apply { - addRow(arrayOf(replacement.name, replacement.value)) - } - - service.increaseSettingsFilterCount(caller) - } - } else { - logD(TAG) { "@spoofSettings LIST_QUERY received caller: $caller, database: $database" } - - val result = param.result as Cursor? ?: return@hookAfter - - val columns = mutableMapOf>().apply { - for (i in 0 ..< result.columnCount) { - put(result.getColumnName(i), mutableListOf()) - } - } - - logD(TAG) { "@spoofSetting LIST_QUERY columns: ${columns.keys}" } - - val keyColumn = columns["name"] - val valueColumn = columns["value"] - - if (keyColumn == null || valueColumn == null) { - logD(TAG) { "@spoofSettings LIST_QUERY invalid query: $caller ($keyColumn, $valueColumn)" } - return@hookAfter - } - - while (result.moveToNext()) { - val name = result.getString(columns.keys.indexOf("name")) - keyColumn.add(name) - - val replacement = service.getSpoofedSetting(caller, name, database) - val value = if (replacement != null) { - logD(TAG) { "@spoofSettings QUERY $name in $database replaced for $caller" } - - service.increaseSettingsFilterCount(caller) - - replacement.value - } else { - result.getString(columns.keys.indexOf("value")) - } - - valueColumn.add(value) - - if (columns.keys.size > 2) { - for (otherCol in columns.keys.filter { it !in NV_PAIR }) { - val other = result.getString(columns.keys.indexOf(otherCol)) - - columns[otherCol]!!.add(other) - } - } - } - - param.result = MatrixCursor(columns.keys.toTypedArray(), columns.size).apply { - val size = columns.values.first().size - for (i in 0 ..< size) { - val innerList = mutableListOf() - - columns.values.forEach { colVal -> - innerList.add(colVal[i]) - } - - addRow(innerList) - } - } - } - } - - // Credit: https://github.com/Nitsuya/DoNotTryAccessibility/blob/main/app/src/main/java/io/github/nitsuya/donottryaccessibility/hook/AndroidFrameworkHooker.kt - hooks += findMethod(CONTENT_PROVIDER_TRANSPORT_CLASS) { - name == "call" - }.hookBefore { param -> - val callingApps = getCallingPackages(param) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller == null) return@hookBefore - - val method = param.args[2] as String? - val name = param.args[3] as String? - - logD(TAG) { "@spoofSettings CALL received caller: ${callingApps.contentToString()}, method: $method, name: $name" } - - when (method) { - "GET_global", "GET_secure", "GET_system" -> { - val database = method.substring(method.indexOf('_') + 1) - val replacement = service.getSpoofedSetting(caller, name, database) - if (replacement != null) { - logD(TAG) { "@spoofSettings CALL $name in $database replaced for $caller" } - param.result = Bundle().apply { - putString(Settings.NameValueTable.VALUE, replacement.value) - putInt("_generation_index", -1) - } - - service.increaseSettingsFilterCount(caller) - } - } - } - } - } - - private fun getCallingPackages(param: XC_MethodHook.MethodHookParam) = try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val attrSource = param.args.first() as AttributionSource - arrayOf(attrSource.packageName) - } else { - arrayOf(param.args.first() as String) - } - } catch (_: Throwable) { - Utils4Xposed.getCallingApps(service) - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt deleted file mode 100644 index bb614aac3..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ImmHook.kt +++ /dev/null @@ -1,190 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.ComponentName -import android.os.Build -import android.provider.Settings -import android.view.inputmethod.InputMethodInfo -import android.view.inputmethod.InputMethodSubtype -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.common.settings_presets.InputMethodPreset -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Logcat.logE -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed -import icu.nullptr.hidemyapplist.xposed.XposedConstants.IMM_SERVICE_CLASS -import java.util.Collections - -class ImmHook(private val service: HMAService) : IFrameworkHook { - companion object { - private const val TAG = "ImmHook" - } - - private val hooks = mutableListOf() - - // TODO: Find a method to get settings activity - fun getFakeInputMethodInfo(packageName: String): InputMethodInfo { - val defaultInputMethod = service.getSpoofedSetting( - packageName, - Settings.Secure.DEFAULT_INPUT_METHOD, - Constants.SETTINGS_SECURE, - ) - - if (defaultInputMethod?.value != null) { - try { - val component = ComponentName.unflattenFromString(defaultInputMethod.value!!)!! - logD(TAG) { "Package component: \"$component\"" } - - val pkgManager = Utils4Xposed.getPackageManager() - val kbdPackage = Utils.binderLocalScope { - pkgManager.getApplicationInfo(component.packageName, 0) - } - - return InputMethodInfo( - component.packageName, - component.className, - kbdPackage.loadLabel(pkgManager), - null, - ) - } catch (e: Throwable) { - logE(TAG, e) { e.message ?: "" } - } - } - - return InputMethodInfo( - "com.google.android.inputmethod.latin", - "com.android.inputmethod.latin.LatinIME", - "Gboard", - null, - ) - } - - override fun load() { - logI(TAG) { "Load hook" } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getCurrentInputMethodInfoAsUser" - }?.hookBefore { param -> - val callingApps = Utils4Xposed.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG) { "@${param.method.name} spoofed input method for $caller" } - - param.result = getFakeInputMethodInfo(caller) - service.increaseSettingsFilterCount(caller) - } - }?.let { - logD(TAG) { "@${it.hookedMethod.name} is hooked!" } - hooks += it - } - } - - (findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getInputMethodListInternal" - } ?: findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getInputMethodList" && returnType.simpleName != "InputMethodInfoSafeList" - })?.hookBefore { param -> - listHook(param) - }?.let { - logD(TAG) { "@${it.hookedMethod.name} is hooked!" } - hooks += it - } - - (findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodListInternal" - } ?: findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodList" && returnType.simpleName != "InputMethodInfoSafeList" - })?.hookBefore { param -> - listHook(param) - }?.let { - logD(TAG) { "@${it.hookedMethod.name} is hooked!" } - hooks += it - } - - findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getCurrentInputMethodSubtype" - }?.hookBefore { param -> - subtypeHook(param) - }?.let { - logD(TAG) { "@${it.hookedMethod.name} is hooked!" } - hooks += it - } - - findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getLastInputMethodSubtype" - }?.hookBefore { param -> - subtypeHook(param) - }?.let { - logD(TAG) { "@${it.hookedMethod.name} is hooked!" } - hooks += it - } - - (findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodSubtypeListInternal" - } ?: findMethodOrNull(IMM_SERVICE_CLASS) { - name == "getEnabledInputMethodSubtypeList" - })?.hookBefore { param -> - subtypeListHook(param) - }?.let { - logD(TAG) { "@${it.hookedMethod.name} is hooked!" } - hooks += it - } - } - - private fun listHook(param: XC_MethodHook.MethodHookParam) { - val callingApps = if (param.method.name.endsWith("Internal")) { - val callingUid = param.args.last() as Int - Utils4Xposed.getCallingApps(service, callingUid) - } else { - Utils4Xposed.getCallingApps(service) - } - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG) { "@${param.method.name} spoofed input method for $caller" } - - param.result = listOf(getFakeInputMethodInfo(caller)) - service.increaseSettingsFilterCount(caller) - } - } - - private fun subtypeHook(param: XC_MethodHook.MethodHookParam) { - val callingApps = Utils4Xposed.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG) { "@${param.method.name} spoofed input method subtype for ${callingApps.contentToString()}" } - - // TODO: Find a method to get exact value for spoofed input method - param.result = null - service.increaseSettingsFilterCount(caller) - } - } - - private fun subtypeListHook(param: XC_MethodHook.MethodHookParam) { - val callingApps = Utils4Xposed.getCallingApps(service) - - val caller = callingApps.firstOrNull { callerIsSpoofed(it) } - if (caller != null) { - logD(TAG) { "@${param.method.name} spoofed input method subtype for ${callingApps.contentToString()}" } - - // TODO: Find a method to get exact list for spoofed input method - param.result = Collections.emptyList() - service.increaseSettingsFilterCount(caller) - } - } - - private fun callerIsSpoofed(caller: String) = - service.getEnabledSettingsPresets(caller).contains(InputMethodPreset.NAME) - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt deleted file mode 100644 index d4e459df3..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget29.kt +++ /dev/null @@ -1,36 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getCallingApps -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getPackageNameFromPackageSettings - -class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget29" - - // not required until SDK 30 - override val fakeSystemPackageInstallSourceInfo = null - override val fakeUserPackageInstallSourceInfo = null - - @Suppress("UNCHECKED_CAST") - override fun load() { - logI(TAG) { "Load hook" } - - hooks += findMethod(service.pms::class.java, findSuper = true) { - name == "filterAppAccessLPr" && parameterCount == 5 - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[1] as Int? }, - { getPackageNameFromPackageSettings(param.args[0]) }, - { getCallingApps(service, it) }, - { param.result = true }, - ) - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt deleted file mode 100644 index 9f71d67eb..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget30.kt +++ /dev/null @@ -1,81 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.os.Binder -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getCallingApps -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getPackageNameFromPackageSettings -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS - -@RequiresApi(Build.VERSION_CODES.R) -class PmsHookTarget30(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget30" - - override val fakeSystemPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - null, - null, - null, - null, - ) - } - - override val fakeUserPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - VENDING_PACKAGE_NAME, - psPackageInfo?.signingInfo, - VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, - ) - } - - override fun load() { - logI(TAG) { "Load hook" } - - findMethodOrNull(PACKAGE_MANAGER_SERVICE_CLASS, findSuper = true) { - name == "getPackageSetting" - }?.hookBefore { param -> - applyPackageHiding( - param.method.name, - { Binder.getCallingUid() }, - { param.args[0] as String? }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - }?.let { - hooks += it - } - - hooks += findMethod(APPS_FILTER_CLASS) { - name == "shouldFilterApplication" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[0] as Int }, - { getPackageNameFromPackageSettings(param.args[2]) }, - { getCallingApps(service, it) }, - { param.result = true }, - ) - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt deleted file mode 100644 index 14a0faa6b..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget31.kt +++ /dev/null @@ -1,95 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.os.Binder -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getCallingApps -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getPackageNameFromPackageSettings -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PMS_COMPUTER_TRACKER_CLASS - -@RequiresApi(Build.VERSION_CODES.S) -class PmsHookTarget31(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget31" - - override val fakeSystemPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - null, - null, - null, - null, - ) - } - - override val fakeUserPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 4 - }.newInstance( - VENDING_PACKAGE_NAME, - psPackageInfo?.signingInfo, - VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, - ) - } - - override fun load() { - logI(TAG) { "Load hook" } - - findMethodOrNull(PMS_COMPUTER_TRACKER_CLASS) { - name == "getPackageSetting" - }?.hookBefore { param -> - applyPackageHiding( - param.method.name, - { Binder.getCallingUid() }, - { param.args[0] as String? }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - }?.let { - hooks += it - } - - findMethodOrNull(PMS_COMPUTER_TRACKER_CLASS) { - name == "getPackageSettingInternal" - }?.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[1] as Int? }, - { param.args[0] as String? }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - }?.let { - hooks += it - } - - hooks += findMethod(APPS_FILTER_CLASS) { - name == "shouldFilterApplication" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[0] as Int? }, - { getPackageNameFromPackageSettings(param.args[2]) }, - { getCallingApps(service, it) }, - { param.result = true }, - ) - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget33.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget33.kt deleted file mode 100644 index 378b4cfa5..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget33.kt +++ /dev/null @@ -1,78 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.pm.PackageInstaller -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getPackageNameFromPackageSettings -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_IMPL_CLASS - -@RequiresApi(Build.VERSION_CODES.TIRAMISU) -class PmsHookTarget33(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget33" - - private val getPackagesForUidMethod by lazy { - findMethod("com.android.server.pm.Computer") { - name == "getPackagesForUid" - } - } - - override val fakeSystemPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 5 - }.newInstance( - null, - null, - null, - null, - PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, - ) - } - - override val fakeUserPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 5 - }.newInstance( - VENDING_PACKAGE_NAME, - psPackageInfo?.signingInfo, - VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, - PackageInstaller.PACKAGE_SOURCE_STORE, - ) - } - - @Suppress("UNCHECKED_CAST") - override fun load() { - logI(TAG) { "Load hook" } - - hooks += findMethod(APPS_FILTER_IMPL_CLASS, findSuper = true) { - name == "shouldFilterApplication" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[1] as Int? }, - { getPackageNameFromPackageSettings(param.args[3]) }, - { - Utils.binderLocalScope { - getPackagesForUidMethod.invoke(param.args[0], it) as Array? - } - }, - { param.result = true }, - ) - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget34.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget34.kt deleted file mode 100644 index effc38908..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTarget34.kt +++ /dev/null @@ -1,100 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.pm.PackageInstaller -import android.os.Binder -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.kyuubiran.ezxhelper.utils.findConstructor -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.paramCount -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getCallingApps -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getPackageNameFromPackageSettings -import icu.nullptr.hidemyapplist.xposed.XposedConstants.APPS_FILTER_IMPL_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS - -@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) -class PmsHookTarget34(service: HMAService) : PmsHookTargetBase(service) { - - override val TAG = "PmsHookTarget34" - - private val getPackagesForUidMethod by lazy { - findMethod("com.android.server.pm.Computer") { - name == "getPackagesForUid" - } - } - - override val fakeSystemPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 6 - }.newInstance( - null, - null, - null, - null, - null, - PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, - ) - } - - override val fakeUserPackageInstallSourceInfo: Any by lazy { - findConstructor( - "android.content.pm.InstallSourceInfo" - ) { - paramCount == 6 - }.newInstance( - VENDING_PACKAGE_NAME, - psPackageInfo?.signingInfo, - VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, - PackageInstaller.PACKAGE_SOURCE_STORE, - ) - } - - @Suppress("UNCHECKED_CAST") - override fun load() { - logI(TAG) { "Load hook" } - - hooks += findMethod(APPS_FILTER_IMPL_CLASS, findSuper = true) { - name == "shouldFilterApplication" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[1] as Int? }, - { getPackageNameFromPackageSettings(param.args[3]) }, - { - Utils.binderLocalScope { - getPackagesForUidMethod.invoke(param.args[0], it) as Array? - } - }, - { param.result = true }, - ) - } - - // AOSP exploit - https://github.com/aosp-mirror/platform_frameworks_base/commit/5bc482bd99ea18fe0b4064d486b29d5ae2d65139 - // Only 14 QPR2+ has this method - findMethodOrNull(PACKAGE_MANAGER_SERVICE_CLASS, findSuper = true) { - name == "getArchivedPackageInternal" - }?.hookBefore { param -> - applyPackageHiding( - param.method.name, - { Binder.getCallingUid() }, - { param.args[0].toString() }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - }?.let { - hooks.add(it) - } - - super.load() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt deleted file mode 100644 index a32f974bb..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt +++ /dev/null @@ -1,321 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.pm.PackageManager -import android.os.Binder -import android.os.Build -import android.os.UserHandle -import android.util.ArrayMap -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedHelpers -import de.robv.android.xposed.XposedHelpers.callMethod -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME -import icu.nullptr.hidemyapplist.common.OSUtils -import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Logcat.logI -import icu.nullptr.hidemyapplist.xposed.Logcat.logV -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getCallingApps -import icu.nullptr.hidemyapplist.xposed.Utils4Xposed.getPackageNameFromPackageSettings -import icu.nullptr.hidemyapplist.xposed.XposedConstants.COMPUTER_ENGINE_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PMS_COMPUTER_TRACKER_CLASS -import java.util.concurrent.atomic.AtomicReference - -abstract class PmsHookTargetBase(protected val service: HMAService) : IFrameworkHook { - - @Suppress("PropertyName") - abstract val TAG: String - - private val androidPkgClazzNames = arrayOf("AndroidPackage", "PackageImpl") - - protected val hooks = mutableListOf() - protected var lastFilteredApp: AtomicReference = AtomicReference(null) - - protected val psPackageInfo by lazy { - try { - Utils.getPackageInfoCompat( - service.pms, - VENDING_PACKAGE_NAME, - PackageManager.GET_SIGNING_CERTIFICATES.toLong(), - 0 - ) - } catch (_: Throwable) { - null - } - } - - abstract val fakeSystemPackageInstallSourceInfo: Any? - abstract val fakeUserPackageInstallSourceInfo: Any? - - override fun load() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "getPackageStates" - }.hookAfter { param -> - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookAfter - - val callingApps = getCallingApps(service, callingUid) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } - if (caller != null) { - logD(TAG) { "@getPackageStates: incoming query from $caller" } - - val result = param.result as ArrayMap<*, *> - val markedToRemove = mutableListOf() - - for (pair in result.entries) { - val value = pair.value - val packageName = XposedHelpers.callMethod(value, "getPackageName") as String - if (service.shouldHide(caller, packageName)) { - markedToRemove.add(pair.key) - } - } - - if (markedToRemove.isNotEmpty()) { - val copyResult = ArrayMap(result) - copyResult.removeAll(markedToRemove) - logD(TAG) { "@getPackageStates: removed ${markedToRemove.size} entries from $caller" } - param.result = copyResult - service.increasePMFilterCount(caller) - } - } - } - - // Samsung related fix - if (OSUtils.isSamsung()) { - findMethod(COMPUTER_ENGINE_CLASS) { - name == "generatePackageInfo" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { Binder.getCallingUid() }, - { getPackageNameFromPackageSettings(param.args[0]) }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - } - } - - // Samsung devices can fail to get this hook working, - // but it is okay due to generatePackageInfo hook - findMethodOrNull(COMPUTER_ENGINE_CLASS) { - name == "addPackageHoldingPermissions" - }?.hookBefore { param -> - applyPackageHiding( - param.method.name, - { Binder.getCallingUid() }, - { getPackageNameFromPackageSettings(param.args[1]) }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - }?.let { - logD(TAG) { "CE addPackageHoldingPermissions is hooked!" } - hooks += it - } - - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "isCallerInstallerOfRecord" - }.hookBefore { param -> - val callingUid = param.args.last() as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val pkg = param.args.lastOrNull { - it?.javaClass?.simpleName in androidPkgClazzNames - } ?: return@hookBefore - val query = callMethod( - pkg, - if (pkg.javaClass.simpleName == "PackageImpl") { - "getManifestPackageName" - } else { - "getPackageName" - }) as? String ?: return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = callingUid == psPackageInfo?.applicationInfo?.uid - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = false - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - } - - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "getPackageInfoInternal" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args.firstOrNull { it is Int } as? Int }, - { param.args.firstOrNull { it is String } as? String }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - } - - hooks += findMethod(COMPUTER_ENGINE_CLASS) { - name == "getApplicationInfoInternal" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args.firstOrNull { it is Int } as? Int }, - { param.args.firstOrNull { it is String } as? String }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - } - } else { - val clazzToHook = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PMS_COMPUTER_TRACKER_CLASS - } else { - PACKAGE_MANAGER_SERVICE_CLASS - } - - hooks += findMethod(clazzToHook) { - name == "getPackageInfoInternal" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[3] as Int? }, - { param.args[0] as String? }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - } - - hooks += findMethod(clazzToHook) { - name == "getApplicationInfoInternal" - }.hookBefore { param -> - applyPackageHiding( - param.method.name, - { param.args[2] as Int? }, - { param.args[0] as String? }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - } - } - - if (service.pmn != null) { - findMethodOrNull(service.pmn::class.java, findSuper = true) { - name == "getInstallerForPackage" - }?.hookBefore { param -> - val query = param.args[0] as String? - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = "preload" - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - }?.let { - logD(TAG) { "PMN getInstallerForPackage is hooked!" } - hooks.add(it) - } - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - findMethodOrNull(service.pms::class.java, findSuper = true) { - name == "getInstallSourceInfo" - }?.hookBefore { param -> - val query = param.args[0] as String? - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = fakeUserPackageInstallSourceInfo - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = fakeSystemPackageInstallSourceInfo - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - }?.let { - hooks.add(it) - } - } - - hooks += findMethod(service.pms::class.java, findSuper = true) { - name == "getInstallerPackageName" - }.hookBefore { param -> - val query = param.args[0] as String? - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - } - } - - fun applyPackageHiding( - methodName: String, - findCallingUid: () -> Int?, - findTargetApp: () -> String?, - findCallingApps: (Int) -> Array?, - applyReturnValue: () -> Unit, - ) { - val callingUid = findCallingUid() - if (callingUid == null || callingUid == Constants.UID_SYSTEM) return - val targetApp = findTargetApp() ?: return - logV(TAG) { "@$methodName incoming query: $callingUid => $targetApp" } - if (service.shouldHideFromUid(callingUid, targetApp) == true) { - applyReturnValue() - service.increasePMFilterCount(callingUid) - logD(TAG) { "@$methodName caller cache: $callingUid, target: $targetApp" } - return - } - val callingApps = findCallingApps(callingUid) - val caller = callingApps?.firstOrNull { service.shouldHide(it, targetApp) } - if (caller != null) { - logD(TAG) { "@$methodName caller: $callingUid $caller, target: $targetApp" } - applyReturnValue() - val last = lastFilteredApp.getAndSet(caller) - if (last != caller) logI(TAG) { "@${methodName}: query from $caller" } - service.putShouldHideUidCache(callingUid, caller, targetApp) - service.increasePMFilterCount(caller) - } - } - - final override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt deleted file mode 100644 index 312c3ad45..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsPackageEventsHook.kt +++ /dev/null @@ -1,57 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import android.content.Intent -import android.os.Build -import android.os.Bundle -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.XposedConstants.PACKAGE_MANAGER_SERVICE_CLASS - -class PmsPackageEventsHook(private val service: HMAService) : IFrameworkHook { - private var hook: XC_MethodHook.Unhook? = null - - override fun load() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - try { - hook = findMethod("com.android.server.pm.BroadcastHelper") { - name == "sendPackageBroadcastAndNotify" - }.hookBefore { param -> - service.handlePackageEvent( - param.args[0] as String?, - param.args[1] as String?, - param.args[2] as Bundle?, - ) - } - } catch (_: Throwable) { - hook = findMethod("com.android.internal.content.PackageMonitor") { - name == "onReceive" - }.hookBefore { param -> - val intent = param.args[1] as? Intent ?: return@hookBefore - - service.handlePackageEvent( - intent.action, - intent.data?.encodedSchemeSpecificPart, - intent.extras, - ) - } - } - } else { - hook = findMethod(PACKAGE_MANAGER_SERVICE_CLASS) { - name == "sendPackageBroadcast" - }.hookBefore { param -> - service.handlePackageEvent( - param.args[0] as String?, - param.args[1] as String?, - param.args[2] as Bundle?, - ) - } - } - } - - override fun unload() { - hook?.unhook() - hook = null - } -} diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt deleted file mode 100644 index 869a0a788..000000000 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/ZygoteHook.kt +++ /dev/null @@ -1,51 +0,0 @@ -package icu.nullptr.hidemyapplist.xposed.hook - -import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull -import com.github.kyuubiran.ezxhelper.utils.hookBefore -import de.robv.android.xposed.XC_MethodHook -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.xposed.HMAService -import icu.nullptr.hidemyapplist.xposed.Logcat.logD -import icu.nullptr.hidemyapplist.xposed.Logcat.logV -import icu.nullptr.hidemyapplist.xposed.XposedConstants.ZYGOTE_PROCESS_CLASS - -class ZygoteHook(private val service: HMAService): IFrameworkHook { - companion object { - private const val TAG = "ZygoteHook" - } - - private val hooks = mutableListOf() - - override fun load() { - findMethodOrNull(ZYGOTE_PROCESS_CLASS) { - name == "start" - }?.hookBefore { param -> - logV(TAG) { "@startZygoteProcess: Starting ${param.args.contentToString()}" } - - // ignore if the GIDs array is null - val gIDsIndex = param.args.indexOfFirst { it is IntArray } - if (gIDsIndex < 0) return@hookBefore - - val caller = param.args.lastOrNull { it is String } as String? ?: return@hookBefore - var perms = service.getRestrictedZygotePermissions(caller) ?: return@hookBefore - if (perms.isNotEmpty()) { - val gIDs = param.args[gIDsIndex] as IntArray - - // add more security, reject if not available in GID_PAIRS - perms = perms.filter { Constants.GID_PAIRS.containsValue(it) } - - logD(TAG) { "@startZygoteProcess: GIDs are ${gIDs.contentToString()}, removing $perms now" } - param.args[gIDsIndex] = gIDs.filter { it !in perms }.toIntArray() - service.increaseOthersFilterCount(caller) - } - }?.let { - logD(TAG) { "Loaded ZygoteProcess start hook!" } - hooks += it - } - } - - override fun unload() { - hooks.forEach(XC_MethodHook.Unhook::unhook) - hooks.clear() - } -} From 106f7f81a1bb31b36d659591e82357f41c997106 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 04:01:41 +0300 Subject: [PATCH 138/162] Try to support late-load mode --- .../zygote/service/SystemServerHook.kt | 43 ++++++++++++++----- .../hma_oss/zygote/util/Utils4Zygote.kt | 5 +++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 492542e41..de5d3c6b6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -2,6 +2,7 @@ package org.frknkrc44.hma_oss.zygote.service import android.annotation.SuppressLint import android.content.pm.IPackageManager +import android.os.Build import com.v7878.r8.annotations.DoNotShrink import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame @@ -12,6 +13,7 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.isSystemBootCompleted import kotlin.concurrent.thread @SuppressLint("PrivateApi") @@ -19,6 +21,7 @@ object SystemServerHook { private const val TAG = "SystemServerHook" private const val SYSTEM_SERVER: String = "com.android.server.SystemServer" private const val RUNTIME_INIT: String = "com.android.internal.os.RuntimeInit" + private const val ZYGOTE_INIT: String = "com.android.internal.os.ZygoteInit" var classLoader: ClassLoader? = null var initialized = false @@ -60,18 +63,36 @@ object SystemServerHook { @Throws(Throwable::class) @JvmStatic fun init() { - val method = getDeclaredMethod( - Class.forName(RUNTIME_INIT), "findStaticMain", - String::class.java, Array::class.java, ClassLoader::class.java - ) + // This module was loaded after boot or not + if (isSystemBootCompleted()) { + logI(TAG) { "Trying to invoke late-load mode" } - Hooks.hook(method, Hooks.EntryPointType.CURRENT, { original, frame -> - try { - checkSystemServer(frame) - } catch (th: Throwable) { - logE(TAG, th) { "An exception occurred while checkSystemServer" } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + throw UnsupportedOperationException("This Android version isn't support late-load") } - Transformers.invokeExact(original, frame) - }, Hooks.EntryPointType.DIRECT) + + val method = getDeclaredMethod( + Class.forName(ZYGOTE_INIT), + "getOrCreateSystemServerClassLoader" + ) + + onSystemServer(method.invoke(null) as? ClassLoader) + } else { + logI(TAG) { "Trying to invoke boot-load mode" } + + val method = getDeclaredMethod( + Class.forName(RUNTIME_INIT), "findStaticMain", + String::class.java, Array::class.java, ClassLoader::class.java + ) + + Hooks.hook(method, Hooks.EntryPointType.CURRENT, { original, frame -> + try { + checkSystemServer(frame) + } catch (th: Throwable) { + logE(TAG, th) { "An exception occurred while checkSystemServer" } + } + Transformers.invokeExact(original, frame) + }, Hooks.EntryPointType.DIRECT) + } } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index 8eec99dda..53f4fe6b8 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -5,6 +5,7 @@ import android.os.Binder import android.os.Build import android.os.IBinder import android.os.ServiceManager +import android.os.SystemProperties import com.android.apksig.ApkVerifier import com.v7878.unsafe.Reflection.getDeclaredField import com.v7878.unsafe.Reflection.getDeclaredMethod @@ -224,4 +225,8 @@ object Utils4Zygote { throwable = throwable.cause } } + + fun isSystemBootCompleted(): Boolean { + return SystemProperties.get("sys.boot_completed", "0") == "1" + } } From 9a1fcc86ef3102f88e1f1c961f79d86fd5849e9e Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 04:15:58 +0300 Subject: [PATCH 139/162] Use alternative method to find ClassLoader --- .../zygote/service/SystemServerHook.kt | 31 ++++++------------- .../hma_oss/zygote/util/Utils4Zygote.kt | 4 --- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index de5d3c6b6..5375ce2a9 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -5,7 +5,6 @@ import android.content.pm.IPackageManager import android.os.Build import com.v7878.r8.annotations.DoNotShrink import com.v7878.unsafe.Reflection.getDeclaredMethod -import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.Transformers import com.v7878.vmtools.Hooks import org.frknkrc44.hma_oss.zygote.util.Logcat.logD @@ -13,7 +12,6 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.isSystemBootCompleted import kotlin.concurrent.thread @SuppressLint("PrivateApi") @@ -50,35 +48,22 @@ object SystemServerHook { } } - @Throws(Throwable::class) - private fun checkSystemServer(frame: EmulatedStackFrame) { - val accessor = frame.accessor() - if (SYSTEM_SERVER == accessor.getReference(0)) { - val loader: ClassLoader? = accessor.getReference(2) - onSystemServer(loader) - } - } - @DoNotShrink @Throws(Throwable::class) @JvmStatic fun init() { - // This module was loaded after boot or not - if (isSystemBootCompleted()) { - logI(TAG) { "Trying to invoke late-load mode" } - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - throw UnsupportedOperationException("This Android version isn't support late-load") - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + logI(TAG) { "Trying to invoke 12+ mode" } val method = getDeclaredMethod( Class.forName(ZYGOTE_INIT), "getOrCreateSystemServerClassLoader" ) - onSystemServer(method.invoke(null) as? ClassLoader) + val loader = method.invoke(null) as? ClassLoader + onSystemServer(loader) } else { - logI(TAG) { "Trying to invoke boot-load mode" } + logI(TAG) { "Trying to invoke 11- mode" } val method = getDeclaredMethod( Class.forName(RUNTIME_INIT), "findStaticMain", @@ -87,7 +72,11 @@ object SystemServerHook { Hooks.hook(method, Hooks.EntryPointType.CURRENT, { original, frame -> try { - checkSystemServer(frame) + val accessor = frame.accessor() + if (SYSTEM_SERVER == accessor.getReference(0)) { + val loader: ClassLoader? = accessor.getReference(2) + onSystemServer(loader) + } } catch (th: Throwable) { logE(TAG, th) { "An exception occurred while checkSystemServer" } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index 53f4fe6b8..cc3b44668 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -225,8 +225,4 @@ object Utils4Zygote { throwable = throwable.cause } } - - fun isSystemBootCompleted(): Boolean { - return SystemProperties.get("sys.boot_completed", "0") == "1" - } } From 0d3407626d230e7a08fcd16c5162f80b40d38e68 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 15:31:15 +0300 Subject: [PATCH 140/162] Use 11- mode as fallback --- .../zygote/service/SystemServerHook.kt | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 5375ce2a9..29fe2a164 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -55,33 +55,40 @@ object SystemServerHook { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { logI(TAG) { "Trying to invoke 12+ mode" } - val method = getDeclaredMethod( - Class.forName(ZYGOTE_INIT), - "getOrCreateSystemServerClassLoader" - ) + runCatching { + val method = getDeclaredMethod( + Class.forName(ZYGOTE_INIT), + "getOrCreateSystemServerClassLoader" + ) - val loader = method.invoke(null) as? ClassLoader - onSystemServer(loader) - } else { - logI(TAG) { "Trying to invoke 11- mode" } + val loader = method.invoke(null) as? ClassLoader + onSystemServer(loader) + }.onSuccess { + return + }.onFailure { + logE(TAG, it) { "An exception occurred while trying 12+ mode" } + // falls back to 11- mode + } + } + + logI(TAG) { "Trying to invoke 11- mode" } - val method = getDeclaredMethod( - Class.forName(RUNTIME_INIT), "findStaticMain", - String::class.java, Array::class.java, ClassLoader::class.java - ) + val method = getDeclaredMethod( + Class.forName(RUNTIME_INIT), "findStaticMain", + String::class.java, Array::class.java, ClassLoader::class.java + ) - Hooks.hook(method, Hooks.EntryPointType.CURRENT, { original, frame -> - try { - val accessor = frame.accessor() - if (SYSTEM_SERVER == accessor.getReference(0)) { - val loader: ClassLoader? = accessor.getReference(2) - onSystemServer(loader) - } - } catch (th: Throwable) { - logE(TAG, th) { "An exception occurred while checkSystemServer" } + Hooks.hook(method, Hooks.EntryPointType.CURRENT, { original, frame -> + try { + val accessor = frame.accessor() + if (SYSTEM_SERVER == accessor.getReference(0)) { + val loader: ClassLoader? = accessor.getReference(2) + onSystemServer(loader) } - Transformers.invokeExact(original, frame) - }, Hooks.EntryPointType.DIRECT) - } + } catch (th: Throwable) { + logE(TAG, th) { "An exception occurred while checkSystemServer" } + } + Transformers.invokeExact(original, frame) + }, Hooks.EntryPointType.DIRECT) } } From 203702634ce57be9533752fdd713507756703ee6 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 15:51:06 +0300 Subject: [PATCH 141/162] Simplify 12+ mode --- .../hma_oss/zygote/service/SystemServerHook.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 29fe2a164..912bfcefb 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -11,7 +11,8 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callStaticMethod +import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.waitForService import kotlin.concurrent.thread @SuppressLint("PrivateApi") @@ -34,8 +35,8 @@ object SystemServerHook { initialized = true thread { - val pms = Utils4Zygote.waitForService("package") as IPackageManager - val pmn = Utils4Zygote.waitForService("package_native") + val pms = waitForService("package") as IPackageManager + val pmn = waitForService("package_native") logD(TAG) { "Got pms: $pms, $pmn" } runCatching { @@ -56,13 +57,12 @@ object SystemServerHook { logI(TAG) { "Trying to invoke 12+ mode" } runCatching { - val method = getDeclaredMethod( + val loader = callStaticMethod( Class.forName(ZYGOTE_INIT), "getOrCreateSystemServerClassLoader" ) - val loader = method.invoke(null) as? ClassLoader - onSystemServer(loader) + onSystemServer(loader as? ClassLoader) }.onSuccess { return }.onFailure { From 75cbe5276ff413ec6c5a3c2449c18365fa74297e Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 16:14:59 +0300 Subject: [PATCH 142/162] Upgrade dependencies --- gradle/libs.versions.toml | 10 +++++----- .../hma_oss/zygote/service/SystemServerHook.kt | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d2401fea4..e878ddc5c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,13 +1,13 @@ [versions] #noinspection GradleDependency,AndroidGradlePluginVersion agp = "8.13.2" -kotlin = "2.3.20" +kotlin = "2.3.21" material = "1.13.0" hidden-api = "4.4.0" -androidx-navigation = "2.9.7" +androidx-navigation = "2.9.8" vbpd = "2.0.4" r8_annotations = "v1.0.1" -androidvmtools = "22206a0" +androidvmtools = "86f3e1e" zygoteloader = "bf5078e182" coil = "3.4.0" @@ -24,7 +24,7 @@ com-github-aerathstuff-zygoteloader = { id = "com.github.aerath-stuff.ZygoteLoad [libraries] androidx-appcompat-appcompat = { group = "androidx.appcompat", name = "appcompat", version = "1.7.1" } -androidx-annotation-jvm = { group = "androidx.annotation", name = "annotation-jvm", version = "1.9.1" } +androidx-annotation-jvm = { group = "androidx.annotation", name = "annotation-jvm", version = "1.10.0" } androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" } androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" } androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version = "1.2.1" } @@ -35,7 +35,7 @@ dev-androidbroadcast-vbpd-reflection = { module = "dev.androidbroadcast.vbpd:vbp com-github-topjohnwu-libsu-core = { module = "com.github.topjohnwu.libsu:core", version = "6.0.0" } dev-rikka-hidden-compat = { module = "dev.rikka.hidden:compat", version.ref = "hidden-api" } dev-rikka-hidden-stub = { module = "dev.rikka.hidden:stub", version.ref = "hidden-api" } -kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.10.0" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.11.0" } material = { module = "com.google.android.material:material", version.ref = "material" } me-zhanghai-android-appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" } io-github-vova7878-androidvmtools = { module = "com.github.aerath-stuff:AndroidVMTools", version.ref = "androidvmtools" } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 912bfcefb..5d305b542 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -27,6 +27,8 @@ object SystemServerHook { @Throws(Throwable::class) fun onSystemServer(loader: ClassLoader?) { + assert(loader != null) { "Class loader is null, aborting!" } + logV(TAG) { "Class loader found: $loader" } classLoader = loader From 4e0116a3f43832100e9990a36a4be9f4e61dbcac Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 19:24:53 +0300 Subject: [PATCH 143/162] Try to fix AppDataIsolationHook --- .../zygote/hook/AppDataIsolationHook.kt | 31 ++++++++++++++++--- .../hma_oss/zygote/util/Utils4Zygote.kt | 8 ++--- .../hma_oss/zygote/util/ZygoteConstants.kt | 1 + 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 8caeda1da..e0580f74d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -1,11 +1,13 @@ package org.frknkrc44.hma_oss.zygote.hook +import android.annotation.SuppressLint import android.os.Build import android.os.SystemProperties import androidx.annotation.RequiresApi import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.service.SystemServerHook import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI @@ -15,9 +17,11 @@ import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getIntField import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.setBooleanField import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PROCESS_LIST_CLASS +import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PROCESS_RECORD_INTERNAL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.STORAGE_MANAGER_SERVICE_CLASS import java.util.Map +@SuppressLint("PrivateApi") @RequiresApi(Build.VERSION_CODES.R) class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { override val TAG = "AppDataIsolationHook" @@ -30,6 +34,15 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { private var voldHookSkipped = false + private val processRecordIntClass: Class<*> by lazy { + Class.forName( + PROCESS_RECORD_INTERNAL_CLASS, + true, + SystemServerHook.classLoader, + ) + } + + @SuppressLint("PrivateApi") override fun load() { if (!(service.config.altAppDataIsolation || service.config.altVoldAppDataIsolation)) return logI(TAG) { "Load hook" } @@ -87,19 +100,29 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { ) { param -> if (service.config.altVoldAppDataIsolation) { val app = param.args.find { it?.javaClass?.simpleName == "ProcessRecord" }!! - val uid = getIntField(app, "uid") + val uid = runCatching { + getIntField(app, "uid") + }.getOrElse { + getIntField(app, "uid", processRecordIntClass) + } val processName = runCatching { getObjectField(app, "processName") - }.getOrDefault("") + }.getOrElse { + getObjectField(app, "processName", processRecordIntClass) + } val mountNode = runCatching { getIntField(app, "mMountMode") }.getOrDefault(0) val isolated = runCatching { getBooleanField(app, "isolated") - }.getOrDefault(false) + }.getOrElse { + getBooleanField(app, "isolated", processRecordIntClass) + } val appZygote = runCatching { getBooleanField(app, "appZygote") - }.getOrDefault(false) + }.getOrElse { + getBooleanField(app, "appZygote", processRecordIntClass) + } val apps = Utils4Zygote.getCallingApps(service, uid) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index cc3b44668..9c0e1ee4d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -5,7 +5,6 @@ import android.os.Binder import android.os.Build import android.os.IBinder import android.os.ServiceManager -import android.os.SystemProperties import com.android.apksig.ApkVerifier import com.v7878.unsafe.Reflection.getDeclaredField import com.v7878.unsafe.Reflection.getDeclaredMethod @@ -17,6 +16,7 @@ import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.Magic import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.SystemServerHook +import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import java.io.File import java.lang.reflect.Constructor @@ -132,11 +132,11 @@ object Utils4Zygote { name, ).getInt(null) - fun getIntField(obj: Any, name: String) = getDeclaredField(obj.javaClass, name).getInt(obj) + fun getIntField(obj: Any, name: String, clazz: Class<*>? = null) = getDeclaredField(clazz ?: obj.javaClass, name).getInt(obj) - fun getBooleanField(obj: Any, name: String) = getDeclaredField(obj.javaClass, name).getBoolean(obj) + fun getBooleanField(obj: Any, name: String, clazz: Class<*>? = null) = getDeclaredField(clazz ?: obj.javaClass, name).getBoolean(obj) - fun getObjectField(obj: Any, name: String): Any? = getDeclaredField(obj.javaClass, name).get(obj) + fun getObjectField(obj: Any, name: String, clazz: Class<*>? = null): Any? = getDeclaredField(clazz ?: obj.javaClass, name).get(obj) fun setBooleanField(obj: Any, name: String, value: Boolean) { val field = getDeclaredField(obj.javaClass, name).apply { isAccessible = true } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZygoteConstants.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZygoteConstants.kt index 255216171..78faacce1 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZygoteConstants.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZygoteConstants.kt @@ -17,4 +17,5 @@ object ZygoteConstants { const val ACTIVITY_STACK_SUPERVISOR_CLASS = "com.android.server.wm.ActivityStackSupervisor" const val ZYGOTE_PROCESS_CLASS = "android.os.ZygoteProcess" const val PROCESS_LIST_CLASS = "com.android.server.am.ProcessList" + const val PROCESS_RECORD_INTERNAL_CLASS = "com.android.server.am.psc.ProcessRecordInternal" } From e6189abcf6d30601efd0ef9d5154fdd558252b20 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 20:40:12 +0300 Subject: [PATCH 144/162] Do not pull ProcessRecord details when detail log is not enabled --- .../zygote/hook/AppDataIsolationHook.kt | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index e0580f74d..b96a0fc21 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -105,28 +105,31 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { }.getOrElse { getIntField(app, "uid", processRecordIntClass) } - val processName = runCatching { - getObjectField(app, "processName") - }.getOrElse { - getObjectField(app, "processName", processRecordIntClass) - } - val mountNode = runCatching { - getIntField(app, "mMountMode") - }.getOrDefault(0) - val isolated = runCatching { - getBooleanField(app, "isolated") - }.getOrElse { - getBooleanField(app, "isolated", processRecordIntClass) - } - val appZygote = runCatching { - getBooleanField(app, "appZygote") - }.getOrElse { - getBooleanField(app, "appZygote", processRecordIntClass) - } val apps = Utils4Zygote.getCallingApps(service, uid) - logD(TAG) { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" } + if (HMAService.instance?.config?.detailLog == true) { + val processName = runCatching { + getObjectField(app, "processName") + }.getOrElse { + getObjectField(app, "processName", processRecordIntClass) + } + val mountNode = runCatching { + getIntField(app, "mMountMode") + }.getOrDefault(0) + val isolated = runCatching { + getBooleanField(app, "isolated") + }.getOrElse { + getBooleanField(app, "isolated", processRecordIntClass) + } + val appZygote = runCatching { + getBooleanField(app, "appZygote") + }.getOrElse { + getBooleanField(app, "appZygote", processRecordIntClass) + } + + logD(TAG) { "@needsStorageDataIsolation $uid and ${apps.contentToString()} - $processName value without override: ${param.result}, mount node: $mountNode, isolated: $isolated, appZygote: $appZygote" } + } // Do not isolate this module for safety if (apps.contains(BuildConfig.APP_PACKAGE_NAME)) { From 37738bc530a56209389ab4efac014186adcdb37e Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 20:49:29 +0300 Subject: [PATCH 145/162] Move query name getter to below --- .../org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index d67fb4622..f402591d0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -226,14 +226,14 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service.pms.javaClass.name, "getInstallerPackageName", ) { param -> - val query = param.getArgument(1) as? String ?: return@hookBefore - val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore val callingApps = getCallingApps(service, callingUid) val callingHandle = UserHandle.getUserHandleForUid(callingUid) + val query = param.getArgument(1) as? String ?: return@hookBefore + for (caller in callingApps) { when (service.shouldHideInstallationSource(caller, query, callingHandle)) { Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME From aefdd304df32810cc4e5698ddd0ed643062d9cc2 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 20:58:40 +0300 Subject: [PATCH 146/162] Change getInstallerPackageName hook for 13+ --- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 72 ++++++++++++------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index f402591d0..f72ee8f81 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -168,6 +168,54 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework { param.result = null }, ) } + + hookBefore( + COMPUTER_ENGINE_CLASS, + "getInstallerPackageName", + ) { param -> + val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + + val callingApps = getCallingApps(service, callingUid) + val callingHandle = UserHandle.getUserHandleForUid(callingUid) + + val query = param.args.firstOrNull { it is String } as? String ?: return@hookBefore + + for (caller in callingApps) { + when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME + Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null + else -> continue + } + + service.increaseInstallerFilterCount(caller) + break + } + } + } else { + hookBefore( + service.pms.javaClass.name, + "getInstallerPackageName", + ) { param -> + val callingUid = Binder.getCallingUid() + if (callingUid == Constants.UID_SYSTEM) return@hookBefore + + val callingApps = getCallingApps(service, callingUid) + val callingHandle = UserHandle.getUserHandleForUid(callingUid) + + val query = param.getArgument(1) as? String ?: return@hookBefore + + for (caller in callingApps) { + when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME + Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null + else -> continue + } + + service.increaseInstallerFilterCount(caller) + break + } + } } if (service.pmn != null) { @@ -221,30 +269,6 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework } } } - - hookBefore( - service.pms.javaClass.name, - "getInstallerPackageName", - ) { param -> - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - val query = param.getArgument(1) as? String ?: return@hookBefore - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { - Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME - Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null - else -> continue - } - - service.increaseInstallerFilterCount(caller) - break - } - } } } From ba32f2c003989a8d58e535d5edd2af3e2a2d8b5b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 21:42:41 +0300 Subject: [PATCH 147/162] Remove more repeating codes --- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 145 ++++++++---------- .../hma_oss/zygote/util/Utils4Zygote.kt | 1 - 2 files changed, 68 insertions(+), 78 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index f72ee8f81..214d13380 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -115,31 +115,27 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework "isCallerInstallerOfRecord", ) { param -> val callingUid = param.args.last { it is Int } as Int - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val pkg = param.args.lastOrNull { - it?.javaClass?.simpleName in androidPkgClazzNames - } ?: return@hookBefore - val query = callMethod( - pkg, - if (pkg.javaClass.simpleName == "PackageImpl") { - "getManifestPackageName" - } else { - "getPackageName" - }) as? String ?: return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + applyInstallerHiding( + param.methodName, + { callingUid }, + fta@{ + val pkg = param.args.lastOrNull { + it?.javaClass?.simpleName in androidPkgClazzNames + } ?: return@fta null + callMethod(pkg, + if (pkg.javaClass.simpleName == "PackageImpl") { + "getManifestPackageName" + } else { + "getPackageName" + } + ) as? String + } + ) { + when (it) { Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = callingUid == psPackageInfo?.applicationInfo?.uid Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = false - else -> continue } - - service.increaseInstallerFilterCount(caller) - break } } @@ -173,23 +169,15 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "getInstallerPackageName", ) { param -> - val callingUid = param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - val query = param.args.firstOrNull { it is String } as? String ?: return@hookBefore - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + applyInstallerHiding( + param.methodName, + { param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() }, + { param.args.firstOrNull { it is String } as? String }, + ) { + when (it) { Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null - else -> continue } - - service.increaseInstallerFilterCount(caller) - break } } } else { @@ -197,23 +185,15 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service.pms.javaClass.name, "getInstallerPackageName", ) { param -> - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - val query = param.getArgument(1) as? String ?: return@hookBefore - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + applyInstallerHiding( + param.methodName, + { Binder.getCallingUid() }, + { param.getArgument(1) as? String }, + ) { + when (it) { Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = null - else -> continue } - - service.increaseInstallerFilterCount(caller) - break } } } @@ -223,23 +203,15 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service.pmn.javaClass.name, "getInstallerForPackage", ) { param -> - val query = param.getArgument(1) as? String ?: return@hookBefore - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + applyInstallerHiding( + param.methodName, + { Binder.getCallingUid() }, + { param.getArgument(1) as? String }, + ) { + when (it) { Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = "preload" - else -> continue } - - service.increaseInstallerFilterCount(caller) - break } } } @@ -249,23 +221,15 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service.pms.javaClass.name, "getInstallSourceInfo", ) { param -> - val query = param.getArgument(1) as? String ?: return@hookBefore - - val callingUid = Binder.getCallingUid() - if (callingUid == Constants.UID_SYSTEM) return@hookBefore - - val callingApps = getCallingApps(service, callingUid) - val callingHandle = UserHandle.getUserHandleForUid(callingUid) - - for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, query, callingHandle)) { + applyInstallerHiding( + param.methodName, + { Binder.getCallingUid() }, + { param.getArgument(1) as? String } + ) { + when (it) { Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = fakeUserPackageInstallSourceInfo Constants.FAKE_INSTALLATION_SOURCE_SYSTEM -> param.result = fakeSystemPackageInstallSourceInfo - else -> continue } - - service.increaseInstallerFilterCount(caller) - break } } } @@ -300,4 +264,31 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework service.increasePMFilterCount(caller) } } + + fun applyInstallerHiding( + methodName: String, + findCallingUid: () -> Int?, + findTargetApp: () -> String?, + applyReturnValue: (Int) -> Unit, + ) { + val callingUid = findCallingUid() ?: return + if (callingUid == Constants.UID_SYSTEM) return + + val callingApps = getCallingApps(service, callingUid) + val callingHandle = UserHandle.getUserHandleForUid(callingUid) + + val query = findTargetApp() ?: return + + for (caller in callingApps) { + val isHide = service.shouldHideInstallationSource(caller, query, callingHandle) + if (isHide == Constants.FAKE_INSTALLATION_SOURCE_DISABLED) continue + + logD(TAG) { "@$methodName: Applied installer hiding for $caller - $callingUid => $isHide" } + + applyReturnValue(isHide) + + service.increaseInstallerFilterCount(caller) + break + } + } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt index 9c0e1ee4d..a9865b541 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt @@ -16,7 +16,6 @@ import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.Magic import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.SystemServerHook -import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import java.io.File import java.lang.reflect.Constructor From 36d3df0faabb79a1151b17b73ca465315816e003 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 11 May 2026 21:54:40 +0300 Subject: [PATCH 148/162] Separate ZL and service utils --- .../hma_oss/zygote/hook/AccessibilityHook.kt | 6 +- .../hma_oss/zygote/hook/ActivityHook.kt | 8 +- .../zygote/hook/AppDataIsolationHook.kt | 12 +- .../zygote/hook/ContentProviderHook.kt | 4 +- .../frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 17 +-- .../hma_oss/zygote/hook/PmsHookTarget29.kt | 4 +- .../hma_oss/zygote/hook/PmsHookTarget30.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget31.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget33.kt | 6 +- .../hma_oss/zygote/hook/PmsHookTarget34.kt | 8 +- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 6 +- .../hma_oss/zygote/service/BulkHooker.kt | 15 +-- .../hma_oss/zygote/service/BulkHookerData.kt | 10 +- .../hma_oss/zygote/service/HMAService.kt | 2 +- .../zygote/service/SystemServerHook.kt | 4 +- .../hma_oss/zygote/service/UserService.kt | 8 +- .../hma_oss/zygote/util/ServiceUtils.kt | 110 ++++++++++++++++++ .../util/{Utils4Zygote.kt => ZLUtils.kt} | 105 +---------------- 18 files changed, 173 insertions(+), 164 deletions(-) create mode 100644 zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt rename zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/{Utils4Zygote.kt => ZLUtils.kt} (58%) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt index d0a573a50..c8094cf0f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AccessibilityHook.kt @@ -6,7 +6,7 @@ import icu.nullptr.hidemyapplist.common.settings_presets.AccessibilityPreset import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACCESSIBILITY_SERVICE_CLASS class AccessibilityHook(private val service: HMAService) : IFrameworkHook { @@ -18,7 +18,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { ACCESSIBILITY_SERVICE_CLASS, "getEnabledAccessibilityServiceList", ) { param -> - val callingApps = Utils4Zygote.getCallingApps(service) + val callingApps = ServiceUtils.getCallingApps(service) if (callingApps.isEmpty()) return@hookBefore val caller = callingApps.firstOrNull { callerIsSpoofed(it) } @@ -38,7 +38,7 @@ class AccessibilityHook(private val service: HMAService) : IFrameworkHook { ACCESSIBILITY_SERVICE_CLASS, "addClient", ) { param -> - val callingApps = Utils4Zygote.getCallingApps(service) + val callingApps = ServiceUtils.getCallingApps(service) if (callingApps.isEmpty()) return@hookBefore val caller = callingApps.firstOrNull { callerIsSpoofed(it) } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index b03ca0f5f..06a4d6fbf 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -11,9 +11,9 @@ import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getObjectField +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getStaticIntField import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_STACK_SUPERVISOR_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_STARTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.ACTIVITY_TASK_SUPERVISOR_CLASS @@ -81,7 +81,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { val callingUid = param.args.first { it is Int } as Int if (callingUid == Constants.UID_SYSTEM) return@hookBefore - val callingApps = Utils4Zygote.getCallingApps(service, callingUid) + val callingApps = getCallingApps(service, callingUid) val caller = callingApps.firstOrNull { service.isHookEnabled(it) } if (caller != null) { logV(TAG) { "@${param.methodName}: $caller requested a resolve info" } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index b96a0fc21..2b736aff0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -11,11 +11,11 @@ import org.frknkrc44.hma_oss.zygote.service.SystemServerHook import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getBooleanField -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getIntField -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getObjectField -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.setBooleanField +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getBooleanField +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getIntField +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getObjectField +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.setBooleanField import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PROCESS_LIST_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PROCESS_RECORD_INTERNAL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.STORAGE_MANAGER_SERVICE_CLASS @@ -106,7 +106,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { getIntField(app, "uid", processRecordIntClass) } - val apps = Utils4Zygote.getCallingApps(service, uid) + val apps = getCallingApps(service, uid) if (HMAService.instance?.config?.detailLog == true) { val processName = runCatching { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index ff164586c..4bc27a265 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -11,7 +11,7 @@ import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam import org.frknkrc44.hma_oss.zygote.util.Logcat.logD -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.CONTENT_PROVIDER_TRANSPORT_CLASS class ContentProviderHook(private val service: HMAService): IFrameworkHook { @@ -164,6 +164,6 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { arrayOf(param.args.first { it is String } as String) } } catch (_: Throwable) { - Utils4Zygote.getCallingApps(service) + ServiceUtils.getCallingApps(service) } } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 5f8de0a96..226efd253 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -16,8 +16,9 @@ import org.frknkrc44.hma_oss.zygote.service.HookParam import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.Logcat.logW -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callStaticMethod +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getPackageManager +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.callStaticMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.IMM_SERVICE_CLASS import java.util.Collections @@ -38,7 +39,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val component = ComponentName.unflattenFromString(defaultInputMethod.value!!)!! logD(TAG) { "Package component: \"$component\"" } - val pkgManager = Utils4Zygote.getPackageManager() + val pkgManager = getPackageManager() val kbdPackage = Utils.binderLocalScope { pkgManager.getApplicationInfo(component.packageName, 0) } @@ -76,7 +77,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { method.declaringClass.name, method.name, ) { param -> - val callingApps = Utils4Zygote.getCallingApps(service) + val callingApps = getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { @@ -145,7 +146,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { method.declaringClass.name, method.name, ) { param -> - val callingApps = Utils4Zygote.getCallingApps(service) + val callingApps = getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { @@ -210,7 +211,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun subtypeHook(param: HookParam) { - val callingApps = Utils4Zygote.getCallingApps(service) + val callingApps = getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { @@ -223,7 +224,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { } private fun subtypeListHook(param: HookParam) { - val callingApps = Utils4Zygote.getCallingApps(service) + val callingApps = getCallingApps(service) val caller = callingApps.firstOrNull { callerIsSpoofed(it) } if (caller != null) { @@ -247,7 +248,7 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { fun calculateReturnedInputMethodList(callingUid: Int, inList: List): List { logV(TAG) { "@getInputMethodList*calculator: $callingUid - Current: ${inList.map { it.component }}" } - val caller = Utils4Zygote.getCallingApps(service, callingUid) + val caller = getCallingApps(service, callingUid) .firstOrNull { callerIsSpoofed(it) } ?: return inList logD(TAG) { "@getInputMethodList: spoofed input method for $caller" } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt index 820797513..33e29e0ab 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget29.kt @@ -3,8 +3,8 @@ package org.frknkrc44.hma_oss.zygote.hook import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getPackageNameFromPackageSettings import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS class PmsHookTarget29(service: HMAService) : PmsHookTargetBase(service) { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt index 542520928..9d7354c69 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget30.kt @@ -7,9 +7,9 @@ import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findConstructor import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt index ecf287b2d..3cf1886da 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget31.kt @@ -7,9 +7,9 @@ import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findConstructor import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PMS_COMPUTER_TRACKER_CLASS diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt index 6035c0a8a..1af055914 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget33.kt @@ -8,9 +8,9 @@ import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findConstructor +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS @RequiresApi(Build.VERSION_CODES.TIRAMISU) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt index 35fa7b056..7b2f344c3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTarget34.kt @@ -9,10 +9,10 @@ import icu.nullptr.hidemyapplist.common.Utils import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findConstructor -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.findMethod -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findConstructor +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.APPS_FILTER_IMPL_CLASS import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.PACKAGE_MANAGER_SERVICE_CLASS diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 214d13380..f9d709ae0 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -15,9 +15,9 @@ import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callMethod -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getCallingApps -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getCallingApps +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.getPackageNameFromPackageSettings +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.callMethod import org.frknkrc44.hma_oss.zygote.util.ZygoteConstants.COMPUTER_ENGINE_CLASS import java.util.concurrent.atomic.AtomicReference diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt index 6d5377c11..67fa61e0a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHooker.kt @@ -13,7 +13,8 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils +import org.frknkrc44.hma_oss.zygote.util.ZLUtils import java.lang.invoke.MethodHandle import java.lang.reflect.Executable import java.lang.reflect.Method @@ -82,13 +83,13 @@ class BulkHooker private constructor() { } value.throwable?.let { - Utils4Zygote.clearStackTraces(it) + ServiceUtils.clearStackTraces(it) throw it } if (value.replace) { - Utils4Zygote.setReturnValue(frame, value.result) + ZLUtils.setReturnValue(frame, value.result) } } } @@ -121,12 +122,12 @@ class BulkHooker private constructor() { } value.throwable?.let { - Utils4Zygote.clearStackTraces(it) + ServiceUtils.clearStackTraces(it) throw it } - Utils4Zygote.setReturnValue(frame, value.result) + ZLUtils.setReturnValue(frame, value.result) } } @@ -202,8 +203,8 @@ class BulkHooker private constructor() { element.memoryAddresses?.second!! ) - val thisObject = Utils4Zygote.getArgument(frame, 0) - val args = Utils4Zygote.dumpArgs(frame, true) + val thisObject = ZLUtils.getArgument(frame, 0) + val args = ZLUtils.dumpArgs(frame, true) value.result = (element.method as Method).invoke(thisObject, *args) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt index 7ab82f179..47b25f7e3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/BulkHookerData.kt @@ -3,7 +3,7 @@ package org.frknkrc44.hma_oss.zygote.service import android.util.Pair import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.vmtools.HookTransformer -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote +import org.frknkrc44.hma_oss.zygote.util.ZLUtils import java.lang.invoke.MethodHandle import java.lang.reflect.Executable @@ -39,17 +39,17 @@ data class HookParam( /** * Returns the first argument */ - val thisObject by lazy { Utils4Zygote.getArgument(frame, 0) } + val thisObject by lazy { ZLUtils.getArgument(frame, 0) } - fun getArgument(index: Int) = Utils4Zygote.getArgument(frame, index) + fun getArgument(index: Int) = ZLUtils.getArgument(frame, index) - fun setArgument(index: Int, value: Any) = Utils4Zygote.setArgument(frame, index, value) + fun setArgument(index: Int, value: Any) = ZLUtils.setArgument(frame, index, value) /** * - `args[0] == thisObject` * - `args[1:] == function args` */ - val args by lazy { Utils4Zygote.dumpArgs(frame) } + val args by lazy { ZLUtils.dumpArgs(frame) } var throwable: Throwable? get() = returnValue.throwable diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index d824a2480..4acdf36fb 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -49,7 +49,7 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logW import org.frknkrc44.hma_oss.zygote.util.Logcat.logWithLevel -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.verifyAppSignature import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.UserManagerApis import java.io.File diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt index 5d305b542..db695f53a 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/SystemServerHook.kt @@ -11,8 +11,8 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logV -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.callStaticMethod -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.waitForService +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.waitForService +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.callStaticMethod import kotlin.concurrent.thread @SuppressLint("PrivateApi") diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index b7e94ba0f..11ff29962 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -10,9 +10,9 @@ import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.getStaticIntField -import org.frknkrc44.hma_oss.zygote.util.Utils4Zygote.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getStaticIntField import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.adapter.UidObserverAdapter @@ -80,7 +80,7 @@ object UserService { logE(TAG, e) { "Fatal: Cannot get package details\nCompile this app from source with your changes" } } - Utils4Zygote.waitForService("activity") + ServiceUtils.waitForService("activity") ActivityManagerApis.registerUidObserver( uidObserver, getActMgrField("UID_OBSERVER_ACTIVE"), diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt new file mode 100644 index 000000000..0cc096114 --- /dev/null +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt @@ -0,0 +1,110 @@ +package org.frknkrc44.hma_oss.zygote.util + +import android.app.ActivityThread +import android.os.Binder +import android.os.Build +import android.os.IBinder +import android.os.ServiceManager +import com.android.apksig.ApkVerifier +import com.v7878.unsafe.Reflection.getDeclaredMethod +import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.Utils +import org.frknkrc44.hma_oss.common.BuildConfig +import org.frknkrc44.hma_oss.zygote.Magic +import org.frknkrc44.hma_oss.zygote.service.HMAService +import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.callMethod +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findField +import java.io.File + + +object ServiceUtils { + const val TAG = "ServiceUtils" + + @Throws(InterruptedException::class) + fun waitForService(name: String?): IBinder? { + try { + return getDeclaredMethod( + ServiceManager::class.java, + "waitForService", + String::class.java, + ).invoke(null, name) as IBinder? + } catch (e: Throwable) { + logE(TAG, e) { "An error occurred on waitForService" } + } + + var service: IBinder? = null + + do { + Thread.sleep(250) + } while ((ServiceManager.getService(name).also { service = it }) == null) + + return service + } + + fun getPackageNameFromPackageSettings(packageSettings: Any?): String? { + if (packageSettings == null) return null + + return try { + callMethod(packageSettings, "getPackageName") as String? + } catch (_: Throwable) { + runCatching { + findField( + packageSettings::class.java, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) "mName" else "name" + )?.apply { isAccessible = true }?.get(packageSettings) as? String + }.getOrNull() + } + } + + fun getPackageManager() = ActivityThread.currentActivityThread().application.packageManager!! + + fun getCallingApps(service: HMAService): Array { + return getCallingApps(service, Binder.getCallingUid()) + } + + fun getCallingApps(service: HMAService, callingUid: Int): Array { + if (callingUid == Constants.UID_SYSTEM) return arrayOf() + return Utils.binderLocalScope { + service.pms.getPackagesForUid(callingUid) + } ?: arrayOf() + } + + fun verifyAppSignature(path: String?): Boolean { + if (path == null) return false + + val verifier = ApkVerifier.Builder(File(path)) + .setMinCheckedPlatformVersion(24) + .build() + val result = verifier.verify() + if (!result.isVerified) return false + val mainCert = result.signerCertificates[0] + return mainCert.encoded.contentEquals(Magic.magicNumbers) + } + + fun clearStackTraces(throwableIn: Throwable) { + var throwable: Throwable? = throwableIn + + while (throwable != null) { + val newTrace = throwable.stackTrace.filter { item -> + !Utils.containsMultiple( + item.className, + "BulkHooker", + "com.v7878", + "MethodHandle", + BuildConfig.APP_PACKAGE_NAME, + ) && !Utils.containsMultiple( + item.fileName, + "r8-map-id-", + "dex-id-", + ) + } + + if (newTrace.size != throwable.stackTrace.size) { + throwable.stackTrace = newTrace.toTypedArray() + } + + throwable = throwable.cause + } + } +} diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt similarity index 58% rename from zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt rename to zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt index a9865b541..8ae48254f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/Utils4Zygote.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt @@ -1,31 +1,15 @@ package org.frknkrc44.hma_oss.zygote.util -import android.app.ActivityThread -import android.os.Binder -import android.os.Build -import android.os.IBinder -import android.os.ServiceManager -import com.android.apksig.ApkVerifier import com.v7878.unsafe.Reflection.getDeclaredField import com.v7878.unsafe.Reflection.getDeclaredMethod import com.v7878.unsafe.invoke.EmulatedStackFrame import com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX -import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils -import org.frknkrc44.hma_oss.common.BuildConfig -import org.frknkrc44.hma_oss.zygote.Magic -import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.SystemServerHook -import org.frknkrc44.hma_oss.zygote.util.Logcat.logE -import java.io.File import java.lang.reflect.Constructor import java.lang.reflect.Field import java.lang.reflect.Method - -object Utils4Zygote { - const val TAG = "Utils4Zygote" - +object ZLUtils { fun dumpArgs(frame: EmulatedStackFrame, skipFirst: Boolean = false): Array { return mutableListOf().let { val begin = if (skipFirst) 1 else 0 @@ -77,55 +61,6 @@ object Utils4Zygote { } } - @Throws(InterruptedException::class) - fun waitForService(name: String?): IBinder? { - try { - return getDeclaredMethod( - ServiceManager::class.java, - "waitForService", - String::class.java, - ).invoke(null, name) as IBinder? - } catch (e: Throwable) { - logE(TAG, e) { "An error occurred on waitForService" } - } - - var service: IBinder? = null - - do { - Thread.sleep(250) - } while ((ServiceManager.getService(name).also { service = it }) == null) - - return service - } - - fun getPackageNameFromPackageSettings(packageSettings: Any?): String? { - if (packageSettings == null) return null - - return try { - callMethod(packageSettings, "getPackageName") as String? - } catch (_: Throwable) { - runCatching { - findField( - packageSettings::class.java, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) "mName" else "name" - )?.apply { isAccessible = true }?.get(packageSettings) as? String - }.getOrNull() - } - } - - fun getPackageManager() = ActivityThread.currentActivityThread().application.packageManager!! - - fun getCallingApps(service: HMAService): Array { - return getCallingApps(service, Binder.getCallingUid()) - } - - fun getCallingApps(service: HMAService, callingUid: Int): Array { - if (callingUid == Constants.UID_SYSTEM) return arrayOf() - return Utils.binderLocalScope { - service.pms.getPackagesForUid(callingUid) - } ?: arrayOf() - } - fun getStaticIntField(className: String, name: String) = getDeclaredField( Class.forName(className), name, @@ -186,42 +121,4 @@ object Utils4Zygote { return field } - - fun verifyAppSignature(path: String?): Boolean { - if (path == null) return false - - val verifier = ApkVerifier.Builder(File(path)) - .setMinCheckedPlatformVersion(24) - .build() - val result = verifier.verify() - if (!result.isVerified) return false - val mainCert = result.signerCertificates[0] - return mainCert.encoded.contentEquals(Magic.magicNumbers) - } - - fun clearStackTraces(throwableIn: Throwable) { - var throwable: Throwable? = throwableIn - - while (throwable != null) { - val newTrace = throwable.stackTrace.filter { item -> - !Utils.containsMultiple( - item.className, - "BulkHooker", - "com.v7878", - "MethodHandle", - BuildConfig.APP_PACKAGE_NAME, - ) && !Utils.containsMultiple( - item.fileName, - "r8-map-id-", - "dex-id-", - ) - } - - if (newTrace.size != throwable.stackTrace.size) { - throwable.stackTrace = newTrace.toTypedArray() - } - - throwable = throwable.cause - } - } } From 94a5f5df12bc18690dbaf31750b23214653c5589 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 12 May 2026 13:49:16 +0300 Subject: [PATCH 149/162] Move isCallerInstallerOfRecord --- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index f9d709ae0..fe52ecaed 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -110,6 +110,32 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework ) } + hookBefore( + COMPUTER_ENGINE_CLASS, + "getPackageInfoInternal", + ) { param -> + applyPackageHiding( + param.methodName, + { param.args.firstOrNull { it is Int } as? Int }, + { param.args.firstOrNull { it is String } as? String }, + { getCallingApps(service, it) }, + { param.result = null }, + ) + } + + hookBefore( + COMPUTER_ENGINE_CLASS, + "getApplicationInfoInternal", + ) { param -> + applyPackageHiding( + param.methodName, + { param.args.firstOrNull { it is Int } as? Int }, + { param.args.firstOrNull { it is String } as? String }, + { getCallingApps(service, it) }, + { param.result = null }, + ) + } + hookBefore( COMPUTER_ENGINE_CLASS, "isCallerInstallerOfRecord", @@ -139,32 +165,6 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework } } - hookBefore( - COMPUTER_ENGINE_CLASS, - "getPackageInfoInternal", - ) { param -> - applyPackageHiding( - param.methodName, - { param.args.firstOrNull { it is Int } as? Int }, - { param.args.firstOrNull { it is String } as? String }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - } - - hookBefore( - COMPUTER_ENGINE_CLASS, - "getApplicationInfoInternal", - ) { param -> - applyPackageHiding( - param.methodName, - { param.args.firstOrNull { it is Int } as? Int }, - { param.args.firstOrNull { it is String } as? String }, - { getCallingApps(service, it) }, - { param.result = null }, - ) - } - hookBefore( COMPUTER_ENGINE_CLASS, "getInstallerPackageName", From 24c2f0349e2adc3269e815d314cbec39439fb0e6 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 19 May 2026 21:37:54 +0300 Subject: [PATCH 150/162] Remove repeated codes a bit --- .../main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt index 226efd253..c3f00bb3c 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ImmHook.kt @@ -261,12 +261,13 @@ class ImmHook(private val service: HMAService) : IFrameworkHook { val fakeIMInfo = getFakeInputMethodInfo(caller) val imExists = isIMExists(fakeIMInfo.packageName) - if (!(imExists && calculatedList.any { it.packageName == fakeIMInfo.packageName })) { + val calcListHasIM = calculatedList.any { it.packageName == fakeIMInfo.packageName } + if (!(imExists && calcListHasIM)) { if (!imExists) { warnNotInstalledKeyboard("getInputMethodList*calculator", fakeIMInfo.packageName) } - if (!calculatedList.any { it.packageName == fakeIMInfo.packageName }) { + if (!calcListHasIM) { return (calculatedList + fakeIMInfo).sortedWith { info1, info2 -> info1.packageName.compareTo(info2.packageName) } From 9a1cf29a1823c2f41d90a5e2b1a912ee440d9ae9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Thu, 21 May 2026 19:13:10 +0300 Subject: [PATCH 151/162] Improve code readability a bit --- .../hidemyapplist/service/ConfigManager.kt | 2 +- .../ui/fragment/BackupRestoreFragment.kt | 2 +- .../hidemyapplist/common/CollectionUtils.kt | 27 +++++++++++++++++++ .../icu/nullptr/hidemyapplist/common/Utils.kt | 9 +------ .../hma_oss/zygote/hook/ActivityHook.kt | 3 ++- .../zygote/hook/ContentProviderHook.kt | 9 ++++--- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 16 ++++++----- .../hma_oss/zygote/hook/ZygoteHook.kt | 3 ++- .../hma_oss/zygote/service/HMAService.kt | 2 +- 9 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 common/src/main/java/icu/nullptr/hidemyapplist/common/CollectionUtils.kt diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 05c20aff5..5da432f34 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -6,7 +6,7 @@ import android.util.Log import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig -import icu.nullptr.hidemyapplist.common.Utils.removeIfWithCount +import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIfWithCount import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index a982dc40d..586517d52 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -15,7 +15,7 @@ import dev.androidbroadcast.vbpd.viewBinding import icu.nullptr.hidemyapplist.common.Constants.CONFIG_VERSION_NO_SETTINGS import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.Utils.cleanRemnantsFromConfig -import icu.nullptr.hidemyapplist.common.Utils.removeIf +import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIf import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.ui.util.contentResolver import icu.nullptr.hidemyapplist.ui.util.navController diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/CollectionUtils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/CollectionUtils.kt new file mode 100644 index 000000000..d84532d56 --- /dev/null +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/CollectionUtils.kt @@ -0,0 +1,27 @@ +package icu.nullptr.hidemyapplist.common + +object CollectionUtils { + inline fun MutableMap.removeIf(predicate: (K, V) -> Boolean) { + this.filter { (key, value) -> predicate(key, value) }.forEach { this.remove(it.key) } + } + + inline fun MutableMap.removeIfWithCount(predicate: (K, V) -> Boolean): Int { + return this.filter { (key, value) -> predicate(key, value) }.count { this.remove(it.key) != null } + } + + inline fun Array<*>.firstWithType(): T { + return this.first { it is T } as T + } + + inline fun Array<*>.firstOrNullWithType(): T? { + return this.firstOrNull { it is T } as? T + } + + inline fun Array<*>.lastWithType(): T { + return this.last { it is T } as T + } + + inline fun Array<*>.lastOrNullWithType(): T? { + return this.lastOrNull { it is T } as? T + } +} diff --git a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt index eb0dad5e6..b77b0541c 100644 --- a/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt +++ b/common/src/main/java/icu/nullptr/hidemyapplist/common/Utils.kt @@ -6,6 +6,7 @@ import android.content.pm.PackageInfo import android.content.pm.ResolveInfo import android.os.Binder import android.os.Build +import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIf import java.util.zip.ZipFile object Utils { @@ -93,14 +94,6 @@ object Utils { } } - inline fun MutableMap.removeIf(predicate: (K, V) -> Boolean) { - this.filter { (key, value) -> predicate(key, value) }.forEach { this.remove(it.key) } - } - - inline fun MutableMap.removeIfWithCount(predicate: (K, V) -> Boolean): Int { - return this.filter { (key, value) -> predicate(key, value) }.count { this.remove(it.key) != null } - } - fun cleanRemnantsFromConfig(config: JsonConfig) { // STEP 1: Remove empty app and settings templates config.templates.removeIf { _, template -> template.appList.isEmpty() } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index 06a4d6fbf..10ec92aca 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -6,6 +6,7 @@ import android.os.Build import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils +import icu.nullptr.hidemyapplist.common.CollectionUtils.firstWithType import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logD @@ -78,7 +79,7 @@ class ActivityHook(private val service: HMAService) : IFrameworkHook { val list = param.args[1] as List? if (list.isNullOrEmpty()) return@hookBefore - val callingUid = param.args.first { it is Int } as Int + val callingUid = param.args.firstWithType() if (callingUid == Constants.UID_SYSTEM) return@hookBefore val callingApps = getCallingApps(service, callingUid) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 4bc27a265..504b6ed8b 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -7,6 +7,7 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.provider.Settings +import icu.nullptr.hidemyapplist.common.CollectionUtils.firstWithType import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HookParam @@ -156,12 +157,12 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { } } - private fun getCallingPackages(param: HookParam) = try { + private fun getCallingPackages(param: HookParam): Array = try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val attrSource = param.args.first { it is AttributionSource } as AttributionSource - arrayOf(attrSource.packageName) + val attrSource = param.args.firstWithType() + arrayOf(attrSource.packageName!!) } else { - arrayOf(param.args.first { it is String } as String) + arrayOf(param.args.firstWithType()) } } catch (_: Throwable) { ServiceUtils.getCallingApps(service) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index fe52ecaed..682750a7d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -9,6 +9,8 @@ import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils +import icu.nullptr.hidemyapplist.common.CollectionUtils.firstOrNullWithType +import icu.nullptr.hidemyapplist.common.CollectionUtils.lastWithType import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache @@ -116,8 +118,8 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework ) { param -> applyPackageHiding( param.methodName, - { param.args.firstOrNull { it is Int } as? Int }, - { param.args.firstOrNull { it is String } as? String }, + { param.args.firstOrNullWithType() }, + { param.args.firstOrNullWithType() }, { getCallingApps(service, it) }, { param.result = null }, ) @@ -129,8 +131,8 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework ) { param -> applyPackageHiding( param.methodName, - { param.args.firstOrNull { it is Int } as? Int }, - { param.args.firstOrNull { it is String } as? String }, + { param.args.firstOrNullWithType() }, + { param.args.firstOrNullWithType() }, { getCallingApps(service, it) }, { param.result = null }, ) @@ -140,7 +142,7 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework COMPUTER_ENGINE_CLASS, "isCallerInstallerOfRecord", ) { param -> - val callingUid = param.args.last { it is Int } as Int + val callingUid = param.args.lastWithType() applyInstallerHiding( param.methodName, @@ -171,8 +173,8 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework ) { param -> applyInstallerHiding( param.methodName, - { param.args.firstOrNull { it is Int } as? Int ?: Binder.getCallingUid() }, - { param.args.firstOrNull { it is String } as? String }, + { param.args.firstOrNullWithType() ?: Binder.getCallingUid() }, + { param.args.firstOrNullWithType() }, ) { when (it) { Constants.FAKE_INSTALLATION_SOURCE_USER -> param.result = VENDING_PACKAGE_NAME diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index 97dd1a101..b2be9c2ad 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -1,6 +1,7 @@ package org.frknkrc44.hma_oss.zygote.hook import icu.nullptr.hidemyapplist.common.Constants +import icu.nullptr.hidemyapplist.common.CollectionUtils.lastOrNullWithType import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logD @@ -20,7 +21,7 @@ class ZygoteHook(private val service: HMAService) : IFrameworkHook { val gIDsIndex = param.args.indexOfFirst { it is IntArray } if (gIDsIndex < 0) return@hookBefore - val caller = param.args.lastOrNull { it is String } as? String? ?: return@hookBefore + val caller = param.args.lastOrNullWithType() ?: return@hookBefore var perms = service.getRestrictedZygotePermissions(caller) ?: return@hookBefore if (perms.isNotEmpty()) { val gIDs = param.args[gIDsIndex] as IntArray diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 4acdf36fb..577d038e3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -26,7 +26,7 @@ import icu.nullptr.hidemyapplist.common.Utils.generateRandomString import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageUidCompat -import icu.nullptr.hidemyapplist.common.Utils.removeIf +import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIf import icu.nullptr.hidemyapplist.common.app_presets.DetectorAppsPreset import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import org.frknkrc44.hma_oss.common.BuildConfig From 4345f145c16a1330cde02190612ae2cb6c276c1c Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 05:00:04 +0300 Subject: [PATCH 152/162] Remove user 0 requirement from manager app --- .../java/icu/nullptr/hidemyapplist/MyApp.kt | 6 -- .../hidemyapplist/service/ConfigManager.kt | 2 +- .../ui/fragment/BackupRestoreFragment.kt | 2 +- .../hma_oss/zygote/hook/ActivityHook.kt | 2 +- .../hma_oss/zygote/hook/PmsHookTargetBase.kt | 4 +- .../hma_oss/zygote/hook/ZygoteHook.kt | 2 +- .../hma_oss/zygote/service/HMAService.kt | 18 ++---- .../hma_oss/zygote/service/UserService.kt | 33 +++------- .../hma_oss/zygote/util/ServiceUtils.kt | 64 ++++++++++++++++++- .../frknkrc44/hma_oss/zygote/util/ZLUtils.kt | 8 +++ 10 files changed, 92 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt b/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt index 8710625e0..da7cfdd71 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/MyApp.kt @@ -8,13 +8,11 @@ import icu.nullptr.hidemyapplist.receiver.AppChangeReceiver import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager import icu.nullptr.hidemyapplist.service.ServiceClient -import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.ConfigUtils.Companion.getLocale import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import me.zhanghai.android.appiconloader.AppIconLoader import org.frknkrc44.hma_oss.R -import kotlin.system.exitProcess class MyApp : Application() { companion object { @@ -33,10 +31,6 @@ class MyApp : Application() { override fun onCreate() { super.onCreate() hmaApp = this - if (!filesDir.absolutePath.startsWith("/data/user/0/")) { - showToast(R.string.do_not_dual) - exitProcess(0) - } AppChangeReceiver.register(this) ConfigManager.init() diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt index 5da432f34..e17dcacef 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/service/ConfigManager.kt @@ -4,9 +4,9 @@ import android.os.Build import android.os.ParcelFileDescriptor import android.util.Log import icu.nullptr.hidemyapplist.MyApp.Companion.hmaApp +import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIfWithCount import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.JsonConfig -import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIfWithCount import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.util.PackageHelper diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt index 586517d52..1b2d3a7ed 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/BackupRestoreFragment.kt @@ -12,10 +12,10 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import com.google.android.material.dialog.MaterialAlertDialogBuilder import dev.androidbroadcast.vbpd.viewBinding +import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIf import icu.nullptr.hidemyapplist.common.Constants.CONFIG_VERSION_NO_SETTINGS import icu.nullptr.hidemyapplist.common.JsonConfig import icu.nullptr.hidemyapplist.common.Utils.cleanRemnantsFromConfig -import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIf import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.ui.util.contentResolver import icu.nullptr.hidemyapplist.ui.util.navController diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt index 10ec92aca..3e8d917b8 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ActivityHook.kt @@ -3,10 +3,10 @@ package org.frknkrc44.hma_oss.zygote.hook import android.content.Intent import android.content.pm.ResolveInfo import android.os.Build +import icu.nullptr.hidemyapplist.common.CollectionUtils.firstWithType import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.common.CollectionUtils.firstWithType import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logD diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt index 682750a7d..f3f4e41b2 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/PmsHookTargetBase.kt @@ -5,12 +5,12 @@ import android.os.Binder import android.os.Build import android.os.UserHandle import android.util.ArrayMap +import icu.nullptr.hidemyapplist.common.CollectionUtils.firstOrNullWithType +import icu.nullptr.hidemyapplist.common.CollectionUtils.lastWithType import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.VENDING_PACKAGE_NAME import icu.nullptr.hidemyapplist.common.OSUtils import icu.nullptr.hidemyapplist.common.Utils -import icu.nullptr.hidemyapplist.common.CollectionUtils.firstOrNullWithType -import icu.nullptr.hidemyapplist.common.CollectionUtils.lastWithType import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.service.HMAServiceCache diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt index b2be9c2ad..3a9759827 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ZygoteHook.kt @@ -1,7 +1,7 @@ package org.frknkrc44.hma_oss.zygote.hook -import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.CollectionUtils.lastOrNullWithType +import icu.nullptr.hidemyapplist.common.Constants import org.frknkrc44.hma_oss.zygote.service.BulkHooker import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logD diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 577d038e3..414284b7d 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -12,6 +12,7 @@ import android.os.UserHandle import android.provider.Settings import android.util.Log import icu.nullptr.hidemyapplist.common.AppPresets +import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIf import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Constants.PARCEL_TYPE_CONFIG import icu.nullptr.hidemyapplist.common.Constants.PARCEL_TYPE_LOG @@ -26,7 +27,6 @@ import icu.nullptr.hidemyapplist.common.Utils.generateRandomString import icu.nullptr.hidemyapplist.common.Utils.getInstalledApplicationsCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import icu.nullptr.hidemyapplist.common.Utils.getPackageUidCompat -import icu.nullptr.hidemyapplist.common.CollectionUtils.removeIf import icu.nullptr.hidemyapplist.common.app_presets.DetectorAppsPreset import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem import org.frknkrc44.hma_oss.common.BuildConfig @@ -49,7 +49,7 @@ import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI import org.frknkrc44.hma_oss.zygote.util.Logcat.logW import org.frknkrc44.hma_oss.zygote.util.Logcat.logWithLevel -import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.findAndVerifyAppSignature import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.UserManagerApis import java.io.File @@ -495,14 +495,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { when (eventType) { Intent.ACTION_PACKAGE_ADDED -> { if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid < 0) { - val pkgInfo = getPackageInfoCompat(pms, packageName, 0L, 0) - if (verifyAppSignature(pkgInfo?.applicationInfo?.sourceDir)) { - logI(TAG) { "The manager app signature is verified successfully" } - appUid = pkgInfo!!.applicationInfo!!.uid - } else { - logE(TAG) { "The manager app itself is modified, skipping" } - appUid = -1 - } + appUid = findAndVerifyAppSignature(pms) } handlePackageAdded(pms, packageName) @@ -514,8 +507,9 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } if (packageName == BuildConfig.APP_PACKAGE_NAME && appUid >= 0) { - logI(TAG) { "The manager app is uninstalled" } - appUid = -1 + logI(TAG) { "The manager app is uninstalled, looking for alternatives" } + + appUid = findAndVerifyAppSignature(pms) } handlePackageRemoved(packageName) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index 11ff29962..34c6f20e6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -5,13 +5,12 @@ import android.content.pm.IPackageManager import android.os.Build import android.os.Bundle import icu.nullptr.hidemyapplist.common.Constants -import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.ServiceUtils -import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.verifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.findAndVerifyAppSignature +import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.waitForService import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getStaticIntField import rikka.hidden.compat.ActivityManagerApis import rikka.hidden.compat.adapter.UidObserverAdapter @@ -32,7 +31,11 @@ object UserService { } try { - val provider = ActivityManagerApis.getContentProviderExternal(Constants.PROVIDER_AUTHORITY, 0, null, null) + val userId = uid / 100000 + + logD(TAG) { "Calculated user id: $userId" } + + val provider = ActivityManagerApis.getContentProviderExternal(Constants.PROVIDER_AUTHORITY, userId, null, null) assert (provider != null) { "Failed to get provider" } @@ -60,27 +63,9 @@ object UserService { fun register(pms: IPackageManager, pmn: Any?) { logI(TAG) { "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}" } - var appUid = -1 - - try { - val pkgInfo = getPackageInfoCompat(pms, BuildConfig.APP_PACKAGE_NAME, 0L, 0) - if (pkgInfo != null) { - if (verifyAppSignature(pkgInfo.applicationInfo?.sourceDir)) { - logI(TAG) { "The manager app signature is verified successfully" } - appUid = pkgInfo.applicationInfo!!.uid - } else { - throw AssertionError("The manager app is modified, skipping") - } - } - assert(appUid >= 0) { - "App UID cannot be -1 or lower" - } - logD(TAG) { "Client uid: $appUid" } - } catch (e: Throwable) { - logE(TAG, e) { "Fatal: Cannot get package details\nCompile this app from source with your changes" } - } + val appUid = findAndVerifyAppSignature(pms) - ServiceUtils.waitForService("activity") + waitForService("activity") ActivityManagerApis.registerUidObserver( uidObserver, getActMgrField("UID_OBSERVER_ACTIVE"), diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt index 0cc096114..95c57fe28 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ServiceUtils.kt @@ -1,20 +1,28 @@ package org.frknkrc44.hma_oss.zygote.util import android.app.ActivityThread +import android.content.Context.USER_SERVICE +import android.content.pm.IPackageManager import android.os.Binder import android.os.Build import android.os.IBinder +import android.os.IUserManager import android.os.ServiceManager import com.android.apksig.ApkVerifier import com.v7878.unsafe.Reflection.getDeclaredMethod import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.Utils +import icu.nullptr.hidemyapplist.common.Utils.getPackageInfoCompat import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.Magic import org.frknkrc44.hma_oss.zygote.service.HMAService import org.frknkrc44.hma_oss.zygote.util.Logcat.logE +import org.frknkrc44.hma_oss.zygote.util.Logcat.logI +import org.frknkrc44.hma_oss.zygote.util.Logcat.logV import org.frknkrc44.hma_oss.zygote.util.ZLUtils.callMethod +import org.frknkrc44.hma_oss.zygote.util.ZLUtils.callMethodWithTypes import org.frknkrc44.hma_oss.zygote.util.ZLUtils.findField +import rikka.hidden.compat.UserManagerApis import java.io.File @@ -70,7 +78,61 @@ object ServiceUtils { } ?: arrayOf() } - fun verifyAppSignature(path: String?): Boolean { + fun findAndVerifyAppSignature(pms: IPackageManager): Int { + val userService = waitForService(USER_SERVICE) + + try { + val userManager = IUserManager.Stub.asInterface(userService) + val profiles = mutableSetOf().also { set -> + val userIds = UserManagerApis.getUserIdsNoThrow() + + runCatching { + userIds.forEach { + val profiles = callMethodWithTypes( + userManager, + "getProfileIds", + arrayOf(Int::class.javaPrimitiveType!!, Boolean::class.javaPrimitiveType!!), + arrayOf(it, false), + ) ?: return@forEach + + (profiles as IntArray).forEach { pId -> set.add(pId) } + } + }.onFailure { + set.addAll(userIds) + } + } + + for (uid in profiles) { + logV(TAG) { "@findAndVerifyAppSignature: checking for uid $uid" } + + val pkgInfo = runCatching { + getPackageInfoCompat(pms, BuildConfig.APP_PACKAGE_NAME, 0L, uid) + }.getOrNull() + + if (pkgInfo != null) { + if (verifyAppSignature(pkgInfo.applicationInfo?.sourceDir)) { + val appUid = pkgInfo.applicationInfo!!.uid + + logI(TAG) { "The manager app signature is verified successfully, uid: $appUid" } + + return appUid + } else { + throw AssertionError("The manager app is modified, skipping") + } + } + } + } catch (e: Throwable) { + logE(TAG, e) { "Fatal: Cannot get package details\nCompile this app from source with your changes" } + + return -1 + } + + logE(TAG) { "The manager app is not found, skipping" } + + return -1 + } + + private fun verifyAppSignature(path: String?): Boolean { if (path == null) return false val verifier = ApkVerifier.Builder(File(path)) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt index 8ae48254f..96ce5c267 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt @@ -77,6 +77,14 @@ object ZLUtils { field.setBoolean(obj, value) } + fun callMethodWithTypes(obj: Any, name: String, types: Array>, args: Array): Any? { + return getDeclaredMethod( + obj.javaClass, + name, + *types, + ).apply { isAccessible = true }.invoke(obj, *args) + } + fun callMethod(obj: Any, name: String, vararg args: Any): Any? { return getDeclaredMethod( obj.javaClass, From 2f88d4ff3f1a916f4b40a6e3fe1fc65a5f62eafb Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 18:20:47 +0300 Subject: [PATCH 153/162] Move unnecessary variables to logD message --- .../frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 504b6ed8b..7c82b3560 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -36,15 +36,18 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val uriIdx = param.args.indexOfFirst { it is Uri } val uri = param.args[uriIdx] as Uri - val projection = param.args[uriIdx + 1] as Array? - val args = param.args[uriIdx + 2] as Bundle? if (uri.authority != "settings") return@hookAfter val segments = uri.pathSegments if (segments.isEmpty()) return@hookAfter - logD(TAG) { "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args" } + logD(TAG) { + val projection = param.args[uriIdx + 1] as Array? + val args = param.args[uriIdx + 2] as Bundle? + + "@spoofSettings QUERY in ${callingApps.contentToString()}: $uri, ${projection?.contentToString()}, $args" + } val database = segments[0] From 2b0f0ef067d7ecc4b4f361066e7d7bbfda7541c1 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 18:29:03 +0300 Subject: [PATCH 154/162] Make app signature check less prioritized --- .../org/frknkrc44/hma_oss/zygote/service/HMAService.kt | 3 +++ .../org/frknkrc44/hma_oss/zygote/service/UserService.kt | 7 ++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 414284b7d..4b0bc27e7 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -81,6 +81,7 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { private val frameworkHooks = mutableSetOf() val executor: ExecutorService = Executors.newSingleThreadExecutor() internal var appUid = 0 + private set var config = JsonConfig().apply { detailLog = true } private set @@ -102,6 +103,8 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { logWithLevel(level, "AppPresets") { msg } } reloadPresetsFromScratch() + + appUid = findAndVerifyAppSignature(pms) } private fun searchDataDir() { diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index 34c6f20e6..3eecece9f 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -9,7 +9,6 @@ import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.zygote.util.Logcat.logD import org.frknkrc44.hma_oss.zygote.util.Logcat.logE import org.frknkrc44.hma_oss.zygote.util.Logcat.logI -import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.findAndVerifyAppSignature import org.frknkrc44.hma_oss.zygote.util.ServiceUtils.waitForService import org.frknkrc44.hma_oss.zygote.util.ZLUtils.getStaticIntField import rikka.hidden.compat.ActivityManagerApis @@ -63,8 +62,6 @@ object UserService { fun register(pms: IPackageManager, pmn: Any?) { logI(TAG) { "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}" } - val appUid = findAndVerifyAppSignature(pms) - waitForService("activity") ActivityManagerApis.registerUidObserver( uidObserver, @@ -75,8 +72,8 @@ object UserService { logI(TAG) { "Registered observer" } - val service = HMAService(pms, pmn) - service.appUid = appUid + // no need to put in a variable + HMAService(pms, pmn) } private fun getActMgrField(name: String) = getStaticIntField( From 9dec4dbb7eec022d3667f9fe483e492fb3ad80f9 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 18:43:28 +0300 Subject: [PATCH 155/162] Simplify appUid checks --- .../org/frknkrc44/hma_oss/zygote/service/UserService.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt index 3eecece9f..4acf531b7 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/UserService.kt @@ -18,14 +18,11 @@ object UserService { private const val TAG = "HMA-UserService" + private val managerAppUid get() = HMAService.instance?.appUid ?: -1 + private val uidObserver = object : UidObserverAdapter() { override fun onUidActive(uid: Int) { - if (HMAService.instance == null) { - logE(TAG) { "HMAService instance is not available, maybe stopped" } - return - } - - if (HMAService.instance!!.appUid < 0 || uid != HMAService.instance?.appUid) { + if (managerAppUid < 0 || uid != managerAppUid) { return } From 07ed44c017f66913ba80201d60a8b43decb3420a Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 19:30:01 +0300 Subject: [PATCH 156/162] Make settings replacement checks more reliable --- .../hma_oss/zygote/hook/ContentProviderHook.kt | 10 +++++++--- .../org/frknkrc44/hma_oss/zygote/service/HMAService.kt | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt index 7c82b3560..271e85213 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/ContentProviderHook.kt @@ -31,7 +31,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { ) { param -> val callingApps = getCallingPackages(param) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } + val caller = callingApps.firstOrNull { service.isAnySettingsReplacementsEnabled(it) } if (caller == null) return@hookAfter val uriIdx = param.args.indexOfFirst { it is Uri } @@ -86,6 +86,8 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { return@hookAfter } + var filteredEntryCount = 0 + while (result.moveToNext()) { val name = result.getString(columns.keys.indexOf("name")) keyColumn.add(name) @@ -94,7 +96,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { val value = if (replacement != null) { logD(TAG) { "@spoofSettings QUERY $name in $database replaced for $caller" } - service.increaseSettingsFilterCount(caller) + filteredEntryCount++ replacement.value } else { @@ -112,6 +114,8 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { } } + service.increaseSettingsFilterCount(caller, filteredEntryCount) + param.result = MatrixCursor(columns.keys.toTypedArray(), columns.size).apply { val size = columns.values.first().size for (i in 0 ..< size) { @@ -132,7 +136,7 @@ class ContentProviderHook(private val service: HMAService): IFrameworkHook { "call", ) { param -> val callingApps = getCallingPackages(param) - val caller = callingApps.firstOrNull { service.isHookEnabled(it) } + val caller = callingApps.firstOrNull { service.isAnySettingsReplacementsEnabled(it) } if (caller == null) return@hookBefore val nameIdx = param.args.indexOfLast { it is String } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index 4b0bc27e7..af92720d3 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -295,6 +295,12 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { fun isHookEnabled(packageName: String?) = config.scope.containsKey(packageName) + fun isAnySettingsReplacementsEnabled(packageName: String?): Boolean { + return config.scope[packageName]?.let { + it.applySettingsPresets.isNotEmpty() || it.applySettingTemplates.isNotEmpty() + } ?: false + } + fun isAppDataIsolationExcluded(packageName: String?): Boolean { if (packageName.isNullOrBlank()) return false From 4b6667bacb8bc152fd35d4e46ed599c7dc67a7f7 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 20:56:30 +0300 Subject: [PATCH 157/162] Return early when a package is excluded --- .../org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 2b736aff0..580a05508 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -139,6 +139,7 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { if (apps.any { service.isAppDataIsolationExcluded(it) }) { param.result = false + return@hookAfter } if (service.config.skipSystemAppDataIsolation) { From 8a785560e793b6a5eeeedf699263a0b719f4d2e8 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 21:43:40 +0300 Subject: [PATCH 158/162] Remove some probably unnecessary checks --- .../hma_oss/zygote/service/HMAService.kt | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt index af92720d3..85a5da4cd 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/service/HMAService.kt @@ -295,17 +295,12 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { fun isHookEnabled(packageName: String?) = config.scope.containsKey(packageName) - fun isAnySettingsReplacementsEnabled(packageName: String?): Boolean { - return config.scope[packageName]?.let { - it.applySettingsPresets.isNotEmpty() || it.applySettingTemplates.isNotEmpty() - } ?: false - } - - fun isAppDataIsolationExcluded(packageName: String?): Boolean { - if (packageName.isNullOrBlank()) return false + fun isAnySettingsReplacementsEnabled(packageName: String?) = config.scope[packageName]?.let { + it.applySettingsPresets.isNotEmpty() || it.applySettingTemplates.isNotEmpty() + } ?: false - return config.scope[packageName]?.excludeVoldIsolation ?: false - } + fun isAppDataIsolationExcluded(packageName: String?) = + config.scope[packageName]?.excludeVoldIsolation ?: false fun getSpoofedSetting(caller: String?, name: String?, database: String): ReplacementItem? { if (caller == null || name == null) return null @@ -329,12 +324,10 @@ class HMAService(val pms: IPackageManager, val pmn: Any?) : IHMAService.Stub() { } fun getEnabledSettingsTemplates(caller: String?): Set { - if (caller == null) return setOf() return config.scope[caller]?.applySettingTemplates ?: return setOf() } fun getEnabledSettingsPresets(caller: String?): Set { - if (caller == null) return setOf() return config.scope[caller]?.applySettingsPresets ?: return setOf() } From 9471ed36528a06c232c92ea6a03bb94392d9ef40 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Fri, 22 May 2026 22:33:47 +0300 Subject: [PATCH 159/162] Change versioning --- .../nullptr/hidemyapplist/ui/util/Common.kt | 3 ++- build.gradle.kts | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt index 7f6d930e5..b7d843491 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt @@ -20,4 +20,5 @@ fun MutableSharedFlow.get() = replayCache.first() fun dp2Px(res: Resources, dp: Int) = res.displayMetrics.density * dp -val isTestBuild get() = BuildConfig.VERSION_NAME.count { it == '-' } != 1 +val isTestBuild get() = BuildConfig.VERSION_NAME.count { it == '-' } != 1 || + BuildConfig.VERSION_NAME.split('-').last().length == 8 diff --git a/build.gradle.kts b/build.gradle.kts index a336d024f..f472861f7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,9 +32,11 @@ val crowdinApiKey: String by extra(localProperties.getProperty("crowdinApiKey", fun getUncommittedSuffix(): String { if (officialBuild) return "" + val shortRef = "git rev-parse --short HEAD".execute() + if (ciBuild) { val headRefVal = providers.environmentVariable("GITHUB_HEAD_REF").orElse("HEAD").get() - return "-$headRefVal" + return "$headRefVal-$shortRef" } var returnedVal = "" @@ -42,20 +44,28 @@ fun getUncommittedSuffix(): String { try { val branch = "git rev-parse --abbrev-ref HEAD".execute().split("/").last() if (branch != "master") { - returnedVal += "-$branch" - returnedVal += "-${System.currentTimeMillis() / 1000}" + returnedVal += "$branch-" } } catch (_: Throwable) {} + returnedVal += shortRef + val result = "git status -s".execute() if (result.isEmpty()) { return returnedVal } - return "$returnedVal-dirty+${result.count { it == '\n' } + 1}" + return "$returnedVal+${result.count { it == '\n' } + 1}" +} + +val gitVersionName: String get() { + val suffix = getUncommittedSuffix() + + return suffix.ifEmpty { + "oss-$gitCommitCountAfterOss" + } } -val gitHasUncommittedSuffix = getUncommittedSuffix() val gitCommitCount = "git rev-list refs/remotes/origin/master --count".execute().toInt() // 432 is the count of commits before license changed @@ -65,7 +75,7 @@ val minSdkVer by extra(29) val targetSdkVer by extra(36) val appVerCode by extra(gitCommitCount + 0x6f7373) // commit count + 0xOSS -val appVerName by extra("oss-${gitCommitCountAfterOss}${gitHasUncommittedSuffix}") +val appVerName by extra(gitVersionName) /* * configVerCode, serviceVerCode and minBackupVerCode is used by other build.gradle.kts files From 2dd356408b68006b0695789de0bc7435b620559b Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Sat, 23 May 2026 15:09:09 +0300 Subject: [PATCH 160/162] Remove rikka autoresconfig --- app/build.gradle.kts | 38 ++++++++++++++++--- .../ui/fragment/SettingsFragment.kt | 6 +-- .../nullptr/hidemyapplist/ui/util/Common.kt | 7 +++- gradle/libs.versions.toml | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8f3c40db5..2f1146f06 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,7 +6,6 @@ import java.net.URL plugins { alias(libs.plugins.agp.app) - alias(libs.plugins.autoresconfig) alias(libs.plugins.refine) alias(libs.plugins.kotlin) alias(libs.plugins.kotlin.serialization) @@ -116,6 +115,10 @@ afterEvaluate { android { namespace = appPackageName + defaultConfig { + buildConfigField("String[]", "SUPPORTED_LOCALES", generateSupportedLocales()) + } + buildFeatures { buildConfig = true viewBinding = true @@ -142,11 +145,34 @@ kotlin { jvmToolchain(21) } -autoResConfig { - generateClass.set(true) - generateRes.set(false) - generatedClassFullName.set("icu.nullptr.hidemyapplist.util.LangList") - generatedArrayFirstItem.set("SYSTEM") +// Inspired from https://github.com/XayahSuSuSu/Android-DataBackup/pull/260 +fun generateSupportedLocales(): String { + val foundLocales = StringBuilder() + foundLocales.append("new String[]{") + + fun appendLangCode(code: String) { + foundLocales.append("\"").append(code).append("\"").append(",") + } + + appendLangCode("SYSTEM") + + fileTree(android.sourceSets["main"].res.srcDirs.first()).files.mapNotNull { + if (it.name == "strings.xml") { + val baseName = it.parent.substringAfterLast(File.separator) + if (baseName == "values") { + "en" + } else { + baseName.substringAfter('-') + .replace("-r", "-") + } + } else { + null + } + }.sortedWith { file1, file2 -> + file1.compareTo(file2) + }.forEach { appendLangCode(it) } + + return "${foundLocales.removeSuffix(",")}}" } dependencies { diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt index 17dd89851..74ab006e2 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt @@ -35,11 +35,11 @@ import icu.nullptr.hidemyapplist.ui.util.setupToolbar import icu.nullptr.hidemyapplist.ui.util.showToast import icu.nullptr.hidemyapplist.ui.util.withAnimations import icu.nullptr.hidemyapplist.util.ConfigUtils.Companion.getLocale -import icu.nullptr.hidemyapplist.util.LangList import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent import icu.nullptr.hidemyapplist.util.SuUtils import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.frknkrc44.hma_oss.BuildConfig import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.databinding.FragmentSettingsBinding import org.frknkrc44.hma_oss.ui.activity.MainActivity @@ -257,7 +257,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen findPreference("language")?.let { val userLocale = getLocale() val entries = buildList { - for (lang in LangList.LOCALES) { + for (lang in BuildConfig.SUPPORTED_LOCALES) { if (lang == "SYSTEM") add(getString(R.string.follow_system)) else { val locale = Locale.forLanguageTag(lang) @@ -266,7 +266,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen } } it.entries = entries.toTypedArray() - it.entryValues = LangList.LOCALES + it.entryValues = BuildConfig.SUPPORTED_LOCALES if (it.value == "SYSTEM") { it.summary = getString(R.string.follow_system) } else { diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt index b7d843491..08845b338 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/Common.kt @@ -20,5 +20,8 @@ fun MutableSharedFlow.get() = replayCache.first() fun dp2Px(res: Resources, dp: Int) = res.displayMetrics.density * dp -val isTestBuild get() = BuildConfig.VERSION_NAME.count { it == '-' } != 1 || - BuildConfig.VERSION_NAME.split('-').last().length == 8 +val isTestBuild get() = BuildConfig.VERSION_NAME.let { name -> + name.count { it == '-' } != 1 || + name.count { it == '+' } > 0 || + name.split('-').last().length == 8 +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e878ddc5c..4b334485c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ #noinspection GradleDependency,AndroidGradlePluginVersion agp = "8.13.2" kotlin = "2.3.21" -material = "1.13.0" +material = "1.14.0" hidden-api = "4.4.0" androidx-navigation = "2.9.8" vbpd = "2.0.4" @@ -17,8 +17,8 @@ agp-lib = { id = "com.android.library", version.ref = "agp" } kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } nav-safeargs-kotlin = { id = "androidx.navigation.safeargs.kotlin", version.ref = "androidx-navigation" } -autoresconfig = { id = "dev.rikka.tools.autoresconfig", version = "1.2.2" } refine = { id = "dev.rikka.tools.refine", version = "4.4.0" } +# do not update until https://github.com/RikkaApps/MaterialThemeBuilder/pull/13 merged materialthemebuilder = { id = "dev.rikka.tools.materialthemebuilder", version = "1.5.1" } com-github-aerathstuff-zygoteloader = { id = "com.github.aerath-stuff.ZygoteLoader", version.ref = "zygoteloader" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b1c..37f78a6af 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From e36eeaaafd838965e49a1ce469208323c0416645 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 25 May 2026 04:35:32 +0300 Subject: [PATCH 161/162] Try to fix unisoc processlist crash --- .../zygote/hook/AppDataIsolationHook.kt | 18 +++++++++++++----- .../frknkrc44/hma_oss/zygote/util/ZLUtils.kt | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt index 580a05508..229f280d6 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/hook/AppDataIsolationHook.kt @@ -52,17 +52,23 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { PROCESS_LIST_CLASS, "startProcess", ) { param -> + val processListClazz = runCatching { + Class.forName(PROCESS_LIST_CLASS, true, SystemServerHook.classLoader) + }.getOrNull() + if (service.config.altAppDataIsolation) { val isEnabled = getBooleanField( param.thisObject, APPDATA_ISOLATION_ENABLED, + processListClazz, ) if (!isEnabled) { setBooleanField( param.thisObject, APPDATA_ISOLATION_ENABLED, - true + true, + processListClazz, ) logI(TAG) { "ProcessList - App data isolation is forced" } @@ -78,14 +84,16 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { } else { val isolationEnabled = getBooleanField( param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED + VOLD_APPDATA_ISOLATION_ENABLED, + processListClazz, ) if (!isolationEnabled) { setBooleanField( param.thisObject, VOLD_APPDATA_ISOLATION_ENABLED, - true + true, + processListClazz, ) logI(TAG) { "ProcessList - Vold app data isolation is forced" } @@ -169,14 +177,14 @@ class AppDataIsolationHook(private val service: HMAService): IFrameworkHook { val isolationEnabled = getBooleanField( param.thisObject, - VOLD_APPDATA_ISOLATION_ENABLED + VOLD_APPDATA_ISOLATION_ENABLED, ) if (!isolationEnabled) { setBooleanField( param.thisObject, VOLD_APPDATA_ISOLATION_ENABLED, - true + true, ) logI(TAG) { "StorageManagerService - Vold app data isolation is forced" } diff --git a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt index 96ce5c267..4ce532abb 100644 --- a/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt +++ b/zygote/src/main/java/org/frknkrc44/hma_oss/zygote/util/ZLUtils.kt @@ -72,8 +72,8 @@ object ZLUtils { fun getObjectField(obj: Any, name: String, clazz: Class<*>? = null): Any? = getDeclaredField(clazz ?: obj.javaClass, name).get(obj) - fun setBooleanField(obj: Any, name: String, value: Boolean) { - val field = getDeclaredField(obj.javaClass, name).apply { isAccessible = true } + fun setBooleanField(obj: Any, name: String, value: Boolean, clazz: Class<*>? = null) { + val field = getDeclaredField(clazz ?: obj.javaClass, name).apply { isAccessible = true } field.setBoolean(obj, value) } From 027e42058398ffd163d8a860ff7ab66300f1cf46 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Mon, 25 May 2026 05:05:29 +0300 Subject: [PATCH 162/162] Fix package query and activity launch when installed to other profiles --- .../java/icu/nullptr/hidemyapplist/util/PackageHelper.kt | 5 ++++- .../frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt index de0e7e3eb..426036abd 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/util/PackageHelper.kt @@ -6,6 +6,7 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.graphics.drawable.Drawable +import android.os.Binder import android.os.UserHandle import android.os.UserManager import android.util.Log @@ -222,11 +223,13 @@ object PackageHelper { } fun getInstalledPackagesAsUser(pm: PackageManager, userId: Int): List { - return if (userId == 0) { + return if (userId == currentUserID) { pm.getInstalledPackages(0) } else { val packages = ServiceClient.getPackageNames(userId) ?: arrayOf() packages.mapNotNull { ServiceClient.getPackageInfo(it, userId) } } } + + val currentUserID by lazy { Binder.getCallingUid() / 100000 } } diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt index 48cc0443d..35a94c249 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/fragment/AppSettingsV2Fragment.kt @@ -177,7 +177,7 @@ class AppSettingsV2Fragment : Fragment(R.layout.fragment_settings) { private val pack get() = parent.viewModel.pack private fun launchMainActivity(packageName: String, userId: Int) { - if (userId != 0) { + if (userId != PackageHelper.currentUserID) { // TODO: Try to find a method to launch apps across user profiles return }