Rewrite hook for force mount data (#297)

* Update dependencies

* Rewrite hook for force mount data

The previous hook point is for startViaZygote(), but the logic in
ProcessList.java to determine whether a process is safe to apply
force mount is complex, and current implementation has already
caused issues. Change the hook point to PlatformCompat and force
return true for all sdk level, then we can let system server apply
the correct logic.

Vold app data isolation does not have sdk level check, so don't
touch it, unlink current code.
This commit is contained in:
Wang Han 2024-10-01 16:35:16 +08:00 • committed by GitHub
commit 88f82c9d25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 52 additions and 48 deletions

View file

@ -28,11 +28,11 @@ jobs:
- name: Gradle wrapper validation
uses: gradle/wrapper-validation-action@v1
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
java-version: '21'
- name: Write key
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master'

View file

@ -22,10 +22,10 @@ jobs:
- name: Gradle wrapper validation
uses: gradle/wrapper-validation-action@v1
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
- name: Write properties

View file

@ -27,7 +27,7 @@ android {
}
kotlin {
jvmToolchain(17)
jvmToolchain(21)
}
autoResConfig {

View file

@ -16,6 +16,11 @@
android:label="@string/app_name"
android:theme="@style/AppTheme">
<property
android:name="android.adservices.AD_SERVICES_CONFIG"
android:resource="@xml/gma_ad_services_config"
tools:replace="android:resource" />
<activity
android:name="icu.nullptr.hidemyapplist.ui.activity.AboutActivity"
android:theme="@style/AppTheme.About" />

View file

@ -73,9 +73,11 @@ object PackageHelper {
mutableMapOf<String, PackageCache>().also {
for (packageInfo in packages) {
if (packageInfo.packageName in Constants.packagesShouldNotHide) continue
val label = pm.getApplicationLabel(packageInfo.applicationInfo).toString()
val icon = hmaApp.appIconLoader.loadIcon(packageInfo.applicationInfo)
it[packageInfo.packageName] = PackageCache(packageInfo, label, icon)
packageInfo.applicationInfo?.let { appInfo ->
val label = pm.getApplicationLabel(appInfo).toString()
val icon = hmaApp.appIconLoader.loadIcon(appInfo)
it[packageInfo.packageName] = PackageCache(packageInfo, label, icon)
}
}
}
}
@ -110,6 +112,6 @@ object PackageHelper {
}
fun isSystem(packageName: String): Boolean = runBlocking {
packageCache.first()[packageName]!!.info.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0
packageCache.first()[packageName]?.info?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM) != 0
}
}

View file

@ -24,16 +24,16 @@ val gitCommitCount = "git rev-list HEAD --count".execute().toInt()
val gitCommitHash = "git rev-parse --verify --short HEAD".execute()
val minSdkVer by extra(24)
val targetSdkVer by extra(34)
val buildToolsVer by extra("34.0.0")
val targetSdkVer by extra(35)
val buildToolsVer by extra("35.0.0")
val appVerName by extra("3.2")
val configVerCode by extra(90)
val serviceVerCode by extra(96)
val minBackupVerCode by extra(65)
val androidSourceCompatibility = JavaVersion.VERSION_17
val androidTargetCompatibility = JavaVersion.VERSION_17
val androidSourceCompatibility = JavaVersion.VERSION_21
val androidTargetCompatibility = JavaVersion.VERSION_21
val localProperties = Properties()
localProperties.load(file("local.properties").inputStream())

View file

@ -25,7 +25,7 @@ android {
}
kotlin {
jvmToolchain(17)
jvmToolchain(21)
}
dependencies {

View file

@ -1,25 +1,25 @@
[versions]
agp = "8.3.2"
kotlin = "1.9.0"
rxhttp = "3.0.6"
hidden-api = "4.2.0"
agp = "8.6.1"
kotlin = "2.0.20"
rxhttp = "3.3.0"
hidden-api = "4.3.3"
[plugins]
agp-app = { id = "com.android.application", version.ref = "agp" }
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" }
ksp = { id = "com.google.devtools.ksp", version = "1.9.0-1.0.11" }
gms = { id = "com.google.gms.google-services", version = "4.3.15" }
nav-safeargs-kotlin = { id = "androidx.navigation.safeargs.kotlin", version = "2.6.0" }
ksp = { id = "com.google.devtools.ksp", version = "2.0.20-1.0.25" }
gms = { id = "com.google.gms.google-services", version = "4.4.2" }
nav-safeargs-kotlin = { id = "androidx.navigation.safeargs.kotlin", version = "2.8.1" }
autoresconfig = { id = "dev.rikka.tools.autoresconfig", version = "1.2.2" }
materialthemebuilder = { id = "dev.rikka.tools.materialthemebuilder", version = "1.3.3" }
refine = { id = "dev.rikka.tools.refine", version = "4.3.0" }
[libraries]
androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version = "2.5.3" }
androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version = "2.5.3" }
androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version = "1.2.0" }
androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version = "2.8.1" }
androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version = "2.8.1" }
androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version = "1.2.1" }
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version = "1.1.0" }
com-android-tools-build-apksig = { module = "com.android.tools.build:apksig", version.ref = "agp" }
com-drakeet-about = { module = "com.drakeet.about:about", version = "2.5.2" }
@ -29,17 +29,16 @@ com-github-kyuubiran-ezxhelper = { module = "com.github.kyuubiran:EzXHelper", ve
com-github-liujingxing-rxhttp = { module = "com.github.liujingxing.rxhttp:rxhttp", version.ref = "rxhttp" }
com-github-liujingxing-rxhttp-compiler = { module = "com.github.liujingxing.rxhttp:rxhttp-compiler", version.ref = "rxhttp" }
com-github-liujingxing-rxhttp-converter-serialization = { module = "com.github.liujingxing.rxhttp:converter-serialization", version.ref = "rxhttp" }
com-github-topjohnwu-libsu-core = { module = "com.github.topjohnwu.libsu:core", version = "5.0.3" }
com-google-android-material = { module = "com.google.android.material:material", version = "1.7.0" }
com-google-android-gms-play-services-ads = { module = "com.google.android.gms:play-services-ads", version = "22.2.0" }
com-google-firebase-firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics-ktx", version = "21.2.0" }
com-google-firebase-bom = { module = "com.google.firebase:firebase-bom", version = "32.1.1" }
com-github-topjohnwu-libsu-core = { module = "com.github.topjohnwu.libsu:core", version = "6.0.0" }
com-google-android-material = { module = "com.google.android.material:material", version = "1.12.0" }
com-google-android-gms-play-services-ads = { module = "com.google.android.gms:play-services-ads", version = "23.4.0" }
com-google-firebase-bom = { module = "com.google.firebase:firebase-bom", version = "33.3.0" }
com-google-firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics-ktx" }
com-squareup-okhttp3 = { module = "com.squareup.okhttp3:okhttp", version = "4.10.0" }
com-squareup-okhttp3 = { module = "com.squareup.okhttp3:okhttp", version = "4.12.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" }
dev-rikka-rikkax-material = { module = "dev.rikka.rikkax.material:material", version = "2.7.0" }
dev-rikka-rikkax-material-preference = { module = "dev.rikka.rikkax.material:material-preference", version = "2.0.0" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.5.1" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.7.1" }
me-zhanghai-android-appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" }

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View file

@ -18,7 +18,7 @@ android {
}
kotlin {
jvmToolchain(17)
jvmToolchain(21)
}
afterEvaluate {

View file

@ -116,7 +116,7 @@ class HMAService(val pms: IPackageManager) : IHMAService.Stub() {
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
frameworkHooks.add(ZygoteArgsHook(this))
frameworkHooks.add(PlatformCompatHook(this))
}
frameworkHooks.forEach(IFrameworkHook::load)

View file

@ -54,7 +54,7 @@ object UserService {
val service = HMAService(pms)
appUid = Utils.getPackageUidCompat(service.pms, Constants.APP_PACKAGE_NAME, 0, 0)
val appPackage = Utils.getPackageInfoCompat(service.pms, Constants.APP_PACKAGE_NAME, 0, 0)
if (!Utils.verifyAppSignature(appPackage.applicationInfo.sourceDir)) {
if (!Utils.verifyAppSignature(appPackage.applicationInfo?.sourceDir.toString())) {
logE(TAG, "Fatal: App signature mismatch")
return
}

View file

@ -0,0 +1,62 @@
package icu.nullptr.hidemyapplist.xposed.hook
import android.annotation.TargetApi
import android.content.pm.ApplicationInfo
import android.os.Build
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.CommonUtils
import icu.nullptr.hidemyapplist.xposed.HMAService
import icu.nullptr.hidemyapplist.xposed.logE
import icu.nullptr.hidemyapplist.xposed.logI
@TargetApi(Build.VERSION_CODES.S)
class PlatformCompatHook(private val service: HMAService) : IFrameworkHook {
companion object {
private const val TAG = "PlatformCompatHook"
private val sAppDataIsolationEnabled = CommonUtils.isAppDataIsolationEnabled
}
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("com.android.server.compat.PlatformCompat") {
name == "isChangeEnabled"
}.hookBefore { param ->
runCatching {
val changeId = param.args[0] as Long
val appInfo = param.args[1] as ApplicationInfo
if (changeId.toInt() != 143937733) return@hookBefore
val apps = service.pms.getPackagesForUid(appInfo.uid) ?: return@hookBefore
for (app in apps) {
if (service.isHookEnabled(app)) {
if (sAppDataIsolationEnabled) param.result = true
logI(TAG, "@startViaZygote force mount data: ${appInfo.uid} $app")
return@hookBefore
}
}
}.onFailure {
logE(TAG, "Fatal error occurred, disable hooks", it)
unload()
}
}
}
override fun unload() {
hook?.unhook()
hook = null
}
override fun onConfigChanged() {
if (service.config.forceMountData) {
if (hook == null) load()
} else {
if (hook != null) unload()
}
}
}