Some optimizations and fixes

- Avoid HMA wake up at background due to uid listener
- Add appUid checker for register to detect mismatching package name changes
- Remove signature verifier codes
- Other fixes and improvements
This commit is contained in:
frknkrc44 2025-09-26 21:50:31 +03:00
commit 62677a7bd8
No known key found for this signature in database
GPG key ID: 784AE1CC0DCFD34F
12 changed files with 44 additions and 88 deletions

View file

@ -10,8 +10,11 @@ plugins {
alias(libs.plugins.nav.safeargs.kotlin)
}
val appPackageName: String by rootProject.extra
android {
namespace = "org.frknkrc44.hma_oss"
namespace = appPackageName
buildFeatures {
buildConfig = true

View file

@ -40,7 +40,7 @@
<provider
android:name="icu.nullptr.hidemyapplist.service.ServiceProvider"
android:authorities="org.frknkrc44.hma_oss.ServiceProvider"
android:authorities="${applicationId}.ServiceProvider"
android:exported="true"
tools:ignore="ExportedContentProvider" />

View file

@ -59,6 +59,9 @@ val serviceVerCode by extra(98)
@Suppress("unused")
val minBackupVerCode by extra(65)
@Suppress("unused")
val appPackageName by extra("org.frknkrc44.hma_oss")
val androidSourceCompatibility = JavaVersion.VERSION_21
val androidTargetCompatibility = JavaVersion.VERSION_21

View file

@ -8,9 +8,11 @@ plugins {
val configVerCode: Int by rootProject.extra
val serviceVerCode: Int by rootProject.extra
val minBackupVerCode: Int by rootProject.extra
val appPackageName: String by rootProject.extra
val appVerName: String by rootProject.extra
android {
namespace = "org.frknkrc44.hma_oss.common"
namespace = "$appPackageName.common"
buildFeatures {
aidl = true
@ -21,6 +23,8 @@ android {
buildConfigField("int", "CONFIG_VERSION", configVerCode.toString())
buildConfigField("int", "SERVICE_VERSION", serviceVerCode.toString())
buildConfigField("int", "MIN_BACKUP_VERSION", minBackupVerCode.toString())
buildConfigField("String", "APP_PACKAGE_NAME", "\"$appPackageName\"")
buildConfigField("String", "APP_VERSION_NAME", "\"$appVerName\"")
}
}

View file

@ -12,7 +12,6 @@ import icu.nullptr.hidemyapplist.common.app_presets.RootAppsPreset
import icu.nullptr.hidemyapplist.common.app_presets.SuspiciousAppsPreset
import icu.nullptr.hidemyapplist.common.app_presets.XposedModulesPreset
// TODO: Update presets when package added/removed
class AppPresets private constructor() {
private val presetList = mutableListOf<BasePreset>()

View file

@ -1,12 +1,12 @@
package icu.nullptr.hidemyapplist.common;
import org.frknkrc44.hma_oss.common.BuildConfig;
import java.util.Set;
public class Constants {
public static final String APP_PACKAGE_NAME = "org.frknkrc44.hma_oss";
public static final String PROVIDER_AUTHORITY = APP_PACKAGE_NAME + ".ServiceProvider";
public static final String PROVIDER_AUTHORITY = BuildConfig.APP_PACKAGE_NAME + ".ServiceProvider";
public static final String GMS_PACKAGE_NAME = "com.google.android.gms";
public static final String GSF_PACKAGE_NAME = "com.google.android.gsf";
public static final String VENDING_PACKAGE_NAME = "com.android.vending";

View file

@ -21,19 +21,6 @@ object Utils {
return buffer.toString()
}
fun verifyAppSignature(path: String): Boolean {
/*
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)
*/
return true
}
fun <T> binderLocalScope(block: () -> T): T {
val identity = Binder.clearCallingIdentity()
val result = block()

View file

@ -1,7 +1,6 @@
package icu.nullptr.hidemyapplist.common.app_presets
import android.content.pm.ApplicationInfo
import icu.nullptr.hidemyapplist.common.CommonUtils
import java.util.zip.ZipFile
class XposedModulesPreset() : BasePreset("xposed") {

View file

@ -22,7 +22,6 @@ androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fr
androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version = "2.8.8" }
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" }
com-drakeet-multitype = { module = "com.drakeet.multitype:multitype", version = "4.3.0" }
com-github-kirich1409-viewbindingpropertydelegate = { module = "com.github.kirich1409:viewbindingpropertydelegate", version = "1.5.9" }

View file

@ -1,16 +1,13 @@
import com.android.ide.common.signing.KeystoreHelper
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.PrintStream
import java.util.Locale
plugins {
alias(libs.plugins.agp.lib)
alias(libs.plugins.refine)
alias(libs.plugins.kotlin)
}
val appPackageName: String by rootProject.extra
android {
namespace = "org.frknkrc44.hma_oss.xposed"
namespace = "$appPackageName.xposed"
buildFeatures {
buildConfig = false
@ -21,51 +18,10 @@ kotlin {
jvmToolchain(21)
}
afterEvaluate {
//noinspection WrongGradleMethod
android.libraryVariants.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("icu/nullptr/hidemyapplist/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 icu.nullptr.hidemyapplist;")
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)
}
}
dependencies {
implementation(projects.common)
implementation(libs.androidx.annotation.jvm)
implementation(libs.com.android.tools.build.apksig)
implementation(libs.com.github.kyuubiran.ezxhelper)
implementation(libs.dev.rikka.hidden.compat)
compileOnly(libs.de.robv.android.xposed.api)

View file

@ -28,19 +28,18 @@ object UserService {
if (uid != appUid) return
try {
val provider = ActivityManagerApis.getContentProviderExternal(Constants.PROVIDER_AUTHORITY, 0, null, null)
if (provider == null) {
logE(TAG, "Failed to get provider")
return
assert (provider != null) {
"Failed to get provider"
}
val extras = Bundle()
extras.putBinder("binder", HMAService.instance)
val reply = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val attr = AttributionSource.Builder(1000).setPackageName("android").build()
provider.call(attr, Constants.PROVIDER_AUTHORITY, "", null, extras)
provider?.call(attr, Constants.PROVIDER_AUTHORITY, "", null, extras)
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
provider.call("android", null, Constants.PROVIDER_AUTHORITY, "", null, extras)
provider?.call("android", null, Constants.PROVIDER_AUTHORITY, "", null, extras)
} else {
provider.call("android", Constants.PROVIDER_AUTHORITY, "", null, extras)
provider?.call("android", Constants.PROVIDER_AUTHORITY, "", null, extras)
}
if (reply == null) {
logE(TAG, "Failed to send binder to app")
@ -54,14 +53,19 @@ object UserService {
}
fun register(pms: IPackageManager) {
logI(TAG, "Initialize HMAService - Version ${BuildConfig.SERVICE_VERSION}")
logI(TAG, "Initialize HMAService - Version ${BuildConfig.APP_VERSION_NAME}")
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.toString())) {
logE(TAG, "Fatal: App signature mismatch")
try {
appUid = Utils.getPackageUidCompat(service.pms, BuildConfig.APP_PACKAGE_NAME, 0, 0)
assert(appUid >= 0) {
"App UID cannot be -1 or lower"
}
} 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")
logI(TAG, "Register observer")
@ -69,7 +73,7 @@ object UserService {
ActivityManagerApis.registerUidObserver(
uidObserver,
ActivityManagerHidden.UID_OBSERVER_ACTIVE,
ActivityManagerHidden.PROCESS_STATE_UNKNOWN,
ActivityManagerHidden.PROCESS_STATE_TOP,
null
)
}

View file

@ -16,13 +16,15 @@ import icu.nullptr.hidemyapplist.xposed.logI
class ActivityHook(private val service: HMAService) : IFrameworkHook {
companion object {
private const val TAG = "ActivityHook"
private val fakeReturnCode = getStaticIntField(
findClass(
"android.app.ActivityManager",
InitFields.ezXClassLoader
),
"START_INTENT_NOT_RESOLVED"
)
private val fakeReturnCode by lazy {
getStaticIntField(
findClass(
"android.app.ActivityManager",
InitFields.ezXClassLoader
),
"START_INTENT_NOT_RESOLVED"
)
}
}
private var hook: XC_MethodHook.Unhook? = null