diff --git a/build.gradle.kts b/build.gradle.kts index e9a7670..031ade2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,7 +37,7 @@ val buildToolsVer by extra("33.0.1") val appVerName by extra("3.1.0-beta") val configVerCode by extra(90) -val serviceVerCode by extra(94) +val serviceVerCode by extra(95) val minBackupVerCode by extra(65) val androidSourceCompatibility = JavaVersion.VERSION_11 diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/BridgeService.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/BridgeService.kt index d4fbd83..68aae3f 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/BridgeService.kt +++ b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/BridgeService.kt @@ -2,12 +2,9 @@ package icu.nullptr.hidemyapplist.xposed import android.content.pm.IPackageManager import android.os.Binder -import android.os.IBinder import android.os.Parcel -import com.github.kyuubiran.ezxhelper.utils.argTypes +import com.github.kyuubiran.ezxhelper.utils.findMethod import com.github.kyuubiran.ezxhelper.utils.hookBefore -import com.github.kyuubiran.ezxhelper.utils.method -import com.github.kyuubiran.ezxhelper.utils.staticMethod import icu.nullptr.hidemyapplist.common.BuildConfig import icu.nullptr.hidemyapplist.common.Constants @@ -17,7 +14,7 @@ object BridgeService { private var appUid = 0 - fun start(pms: IPackageManager) { + fun register(pms: IPackageManager) { logI(TAG, "Initialize HMAService - Version ${BuildConfig.SERVICE_VERSION}") val service = HMAService(pms) appUid = Utils.getPackageUidCompat(service.pms, Constants.APP_PACKAGE_NAME, 0, 0) @@ -27,69 +24,40 @@ object BridgeService { return } logD(TAG, "Client uid: $appUid") - doHooks() - logI(TAG, "Bridge service initialized") - } - - private fun doHooks() { - logD(TAG, "Hook binder transact") - Binder::class.java.method( - "execTransact", - argTypes = argTypes(Int::class.java, Long::class.java, Long::class.java, Int::class.java) - ).hookBefore { param -> + logI(TAG, "Initialize service proxy") + pms.javaClass.findMethod(true) { + name == "onTransact" + }.hookBefore { param -> val code = param.args[0] as Int - val dataObj = param.args[1] as Long - val replyObj = param.args[2] as Long - val flags = param.args[3] as Int - if (code == Constants.TRANSACTION) { - param.result = execTransact(code, dataObj, replyObj, flags) - } + val data = param.args[1] as Parcel + val reply = param.args[2] as Parcel? + if (myTransact(code, data, reply)) param.result = true } } - private val fromNativePointerMethod by lazy { - Parcel::class.java.staticMethod("obtain", argTypes = argTypes(Long::class.java)) - } - - private fun execTransact(code: Int, dataObj: Long, replyObj: Long, flags: Int): Boolean { - val data = fromNativePointerMethod.invoke(null, dataObj) as Parcel? ?: return false - val reply = fromNativePointerMethod.invoke(null, replyObj) as Parcel? - - val res = try { - onTransact(code, data, reply, flags) - } catch (e: Exception) { - if (flags and IBinder.FLAG_ONEWAY != 0) { - logW(TAG, "Caught an exception from the binder stub implementation.") - } else if (reply != null) { - reply.setDataPosition(0) - reply.writeException(e) + private fun myTransact(code: Int, data: Parcel, reply: Parcel?): Boolean { + if (code == Constants.TRANSACTION) { + if (Binder.getCallingUid() == appUid) { + logD(TAG, "Transaction from client") + runCatching { + data.enforceInterface(Constants.DESCRIPTOR) + when (data.readInt()) { + Constants.ACTION_GET_BINDER -> { + reply?.writeNoException() + reply?.writeStrongBinder(HMAService.instance) + return true + } + else -> logW(TAG, "Unknown action") + } + }.onFailure { + logE(TAG, "Transaction error", it) + } + } else { + logW(TAG, "Someone else trying to get my binder?") } - false - } finally { data.setDataPosition(0) reply?.setDataPosition(0) } - if (res) { - data.recycle() - reply?.recycle() - } - return res - } - - private fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean { - data.enforceInterface(Constants.DESCRIPTOR) - return when (data.readInt()) { - Constants.ACTION_GET_BINDER -> { - if (Binder.getCallingUid() == appUid && HMAService.instance != null) { - reply?.writeNoException() - reply?.writeStrongBinder(HMAService.instance!!.asBinder()) - true - } else { - logW(TAG, "Invalid connection") - false - } - } - else -> false - } + return false } } diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt index d85deed..553dfa7 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt +++ b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/XposedEntry.kt @@ -1,33 +1,16 @@ package icu.nullptr.hidemyapplist.xposed import android.content.pm.IPackageManager -import android.os.ServiceManager -import android.util.Log import com.github.kyuubiran.ezxhelper.init.EzXHelperInit -import com.github.kyuubiran.ezxhelper.utils.findMethod -import com.github.kyuubiran.ezxhelper.utils.getFieldByDesc -import com.github.kyuubiran.ezxhelper.utils.hookAfter -import com.github.kyuubiran.ezxhelper.utils.hookAllConstructorAfter +import com.github.kyuubiran.ezxhelper.utils.* 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" -private fun waitSystemService(name: String) { - while (ServiceManager.getService(name) == null) { - try { - logD(TAG, "service $name is not started, wait 1s") - Thread.sleep(1000) - } catch (e: InterruptedException) { - logE(TAG, Log.getStackTraceString(e)) - } - } -} - class XposedEntry : IXposedHookZygoteInit, IXposedHookLoadPackage { override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { @@ -44,30 +27,20 @@ class XposedEntry : IXposedHookZygoteInit, IXposedHookLoadPackage { EzXHelperInit.initHandleLoadPackage(lpparam) logI(TAG, "Hook entry") - var pms: IPackageManager? = null var serviceManagerHook: XC_MethodHook.Unhook? = null serviceManagerHook = findMethod("android.os.ServiceManager") { name == "addService" - }.hookAfter { param -> + }.hookBefore { param -> if (param.args[0] == "package") { - pms = param.args[1] as IPackageManager - logI(TAG, "Got pms: $pms") serviceManagerHook?.unhook() - } - } - - logD(TAG, "ServiceManager hook installed") - thread { - runCatching { - waitSystemService("package") - logI(TAG, "PackageManagerService ready, load bridge service") - if (pms != null) { - BridgeService.start(pms!!) - } else { - logE(TAG, "Package service started, but instance is not captured") + val pms = param.args[1] as IPackageManager + logD(TAG, "Got pms: $pms") + runCatching { + BridgeService.register(pms) + logI(TAG, "Bridge service injected") + }.onFailure { + logE(TAG, "System service crashed", it) } - }.onFailure { - logE(TAG, "System service crashed", it) } } }