From 484846396942e26ca800666ca658361f78eb943e Mon Sep 17 00:00:00 2001 From: fankesyooni Date: Sun, 31 Jul 2022 22:35:56 +0800 Subject: [PATCH] Added support multi-user apps debug info and add appUserId function in PackageParam --- docs/api/public/PackageParam.md | 16 ++++++++++++++++ docs/api/public/YukiResourcesHookCreater.md | 18 ++++++++++++++++-- .../hook/core/YukiMemberHookCreater.kt | 14 ++++++++++---- .../hook/core/YukiResourcesHookCreater.kt | 15 +++++++++++---- .../hook/core/finder/base/BaseFinder.kt | 4 ++-- .../yukihookapi/hook/param/PackageParam.kt | 8 ++++++++ .../hook/xposed/bridge/YukiHookBridge.kt | 13 +++++++++++++ 7 files changed, 76 insertions(+), 12 deletions(-) diff --git a/docs/api/public/PackageParam.md b/docs/api/public/PackageParam.md index 67ee0cc7..d0918ba4 100644 --- a/docs/api/public/PackageParam.md +++ b/docs/api/public/PackageParam.md @@ -40,6 +40,22 @@ val appInfo: ApplicationInfo > 获取当前 Hook APP 的 `ApplicationInfo`。 +### appUserId [field] + +```kotlin +val appUserId: Int +``` + +**变更记录** + +`v1.0.93` `新增` + +**功能描述** + +> 获取当前 Hook APP 的用户 ID。 + +机主为 `0`,应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同。 + ### appContext [field] ```kotlin diff --git a/docs/api/public/YukiResourcesHookCreater.md b/docs/api/public/YukiResourcesHookCreater.md index 6c47c502..dbdd033c 100644 --- a/docs/api/public/YukiResourcesHookCreater.md +++ b/docs/api/public/YukiResourcesHookCreater.md @@ -1,7 +1,7 @@ ## YukiResourcesHookCreater [class] ```kotlin -class YukiResourcesHookCreater(private val packageParam: PackageParam, internal val hookResources: HookResources) +class YukiResourcesHookCreater(internal val packageParam: PackageParam, internal val hookResources: HookResources) ``` **变更记录** @@ -51,7 +51,7 @@ injectResource(tag = "KuriharaYuki") { ### ResourcesHookCreater [class] ```kotlin -inner class ResourcesHookCreater internal constructor(private val tag: String) +inner class ResourcesHookCreater internal constructor(private val tag: String, private val packageName: String) ``` **变更记录** @@ -498,6 +498,20 @@ fun mipmap() > 设置 Resources 类型为位图(Mipmap)。 +##### array [method] + +```kotlin +fun array() +``` + +**变更记录** + +`v1.0.93` `新增` + +**功能描述** + +> 设置 Resources 类型为数组(Array)。 + #### Result [class] ```kotlin diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreater.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreater.kt index 70b82b8f..3a020a7a 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreater.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiMemberHookCreater.kt @@ -543,7 +543,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara onHookingFailureCallback?.invoke(it) onAllFailureCallback?.invoke(it) if (isNotIgnoredNoSuchMemberFailure) yLoggerE( - msg = "[$packageName] " + (if (isHookMemberSetup) + msg = "$hostTagName " + (if (isHookMemberSetup) "Hooked Member with a finding error by $hookClass [$tag]" else "Hooked Member cannot be non-null by $hookClass [$tag]"), e = findingThrowable ?: it @@ -583,7 +583,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara if (isMemberNotFound) onNoSuchMemberFailureCallback?.invoke(it) onAllFailureCallback?.invoke(it) if ((isNotIgnoredHookingFailure && isMemberNotFound.not()) || (isNotIgnoredNoSuchMemberFailure && isMemberNotFound)) - yLoggerE(msg = "[$packageName] Hooked All Members with an error in $hookClass [$tag]", e = it) + yLoggerE(msg = "$hostTagName Hooked All Members with an error in $hookClass [$tag]", e = it) } } @@ -592,7 +592,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara * @param msg 调试日志内容 */ private fun onHookLogMsg(msg: String) { - if (YukiHookAPI.Configs.isDebug) yLoggerI(msg = "[$packageName] $msg") + if (YukiHookAPI.Configs.isDebug) yLoggerI(msg = "$hostTagName $msg") } /** @@ -600,7 +600,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara * @param throwable 异常信息 */ private fun onHookFailureMsg(throwable: Throwable) = - yLoggerE(msg = "[$packageName] Try to hook ${hookClass.instance ?: hookClass.name}[$member] got an Exception [$tag]", e = throwable) + yLoggerE(msg = "$hostTagName Try to hook ${hookClass.instance ?: hookClass.name}[$member] got an Exception [$tag]", e = throwable) /** * 判断是否没有设置 Hook 过程中的任何异常拦截 @@ -614,6 +614,12 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara */ internal val isNotIgnoredNoSuchMemberFailure get() = onNoSuchMemberFailureCallback == null && isNotIgnoredHookingFailure + /** + * 获取 Hook APP (宿主) 标签 + * @return [String] + */ + internal val hostTagName get() = if (packageParam.appUserId != 0) "[$packageName][${packageParam.appUserId}]" else "[$packageName]" + override fun toString() = "[tag] $tag [priority] $priority [class] $hookClass [member] $member $allMethodsName [mode] $hookMemberMode" /** diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreater.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreater.kt index 72893515..045a7c3c 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreater.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/YukiResourcesHookCreater.kt @@ -45,7 +45,7 @@ import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources * @param packageParam 需要传入 [PackageParam] 实现方法调用 * @param hookResources 要 Hook 的 [HookResources] 实例 */ -class YukiResourcesHookCreater(private val packageParam: PackageParam, @PublishedApi internal val hookResources: HookResources) { +class YukiResourcesHookCreater(@PublishedApi internal val packageParam: PackageParam, @PublishedApi internal val hookResources: HookResources) { /** 设置要 Hook 的 Resources */ @PublishedApi @@ -58,7 +58,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe * @return [ResourcesHookCreater.Result] */ inline fun injectResource(tag: String = "Default", initiate: ResourcesHookCreater.() -> Unit) = - ResourcesHookCreater(tag).apply(initiate).apply { preHookResources[toString()] = this }.build() + ResourcesHookCreater(tag, packageParam.exhibitName).apply(initiate).apply { preHookResources[toString()] = this }.build() /** * Hook 执行入口 @@ -78,8 +78,9 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe * * 查找和处理需要 Hook 的 Resources * @param tag 当前设置的标签 + * @param packageName 当前 Hook 的 APP 包名 */ - inner class ResourcesHookCreater @PublishedApi internal constructor(private val tag: String) { + inner class ResourcesHookCreater @PublishedApi internal constructor(private val tag: String, private val packageName: String) { /** 是否已经执行 Hook */ private var isHooked = false @@ -231,9 +232,15 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe * @param msg 调试日志内容 */ private fun onHookLogMsg(msg: String) { - if (YukiHookAPI.Configs.isDebug) yLoggerI(msg = "[${packageParam.exhibitName}] $msg") + if (YukiHookAPI.Configs.isDebug) yLoggerI(msg = "$hostTagName $msg") } + /** + * 获取 Hook APP (宿主) 标签 + * @return [String] + */ + private val hostTagName get() = if (packageParam.appUserId != 0) "[$packageName][${packageParam.appUserId}]" else "[$packageName]" + /** * Resources 查找条件实现类 */ diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt index 6e19638f..1753379b 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/core/finder/base/BaseFinder.kt @@ -187,7 +187,7 @@ abstract class BaseFinder( /** 存在日志时输出日志 */ internal fun printLogIfExist() { if (loggingContent != null) yLoggerE( - msg = "${hookInstance?.packageName?.let { "[$it] " } ?: ""}NoSuch$tag happend in [$classSet] ${loggingContent?.first} [${hookTag}]", + msg = "${hookInstance?.hostTagName?.let { "$it " } ?: ""}NoSuch$tag happend in [$classSet] ${loggingContent?.first} [${hookTag}]", e = loggingContent?.second ) /** 仅输出一次 - 然后清掉日志 */ @@ -200,7 +200,7 @@ abstract class BaseFinder( */ internal fun onHookLogMsg(msg: String) { if (YukiHookAPI.Configs.isDebug && YukiHookBridge.hasXposedBridge) - hookInstance?.also { yLoggerI(msg = "[${it.packageName}] $msg") } ?: yLoggerI(msg = msg) + hookInstance?.also { yLoggerI(msg = "${it.hostTagName} $msg") } ?: yLoggerI(msg = msg) } /** diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt index 5be06073..8fa13cf0 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/param/PackageParam.kt @@ -84,6 +84,14 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: */ val appInfo get() = wrapper?.appInfo ?: YukiHookAppHelper.currentApplicationInfo() ?: ApplicationInfo() + /** + * 获取当前 Hook APP 的用户 ID + * + * 机主为 0 - 应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同 + * @return [Int] + */ + val appUserId get() = YukiHookBridge.findUserId(packageName) + /** * 获取当前 Hook APP 的 [Application] 实例 * diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt index d90688e8..ab859421 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt @@ -35,6 +35,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager import android.content.res.Configuration import android.content.res.Resources import com.highcapable.yukihookapi.YukiHookAPI @@ -174,6 +175,18 @@ object YukiHookBridge { */ internal val hasXposedBridge get() = executorVersion >= 0 + /** + * 获取指定 [packageName] 的用户 ID + * + * 机主为 0 - 应用双开 (分身) 或工作资料因系统环境不同 ID 也各不相同 + * @param packageName 当前包名 + * @return [Int] + */ + internal fun findUserId(packageName: String) = runCatching { + YukiHookHelper.findMethod(UserHandleClass, name = "getUserId", IntType) + .invoke(null, systemContext.packageManager.getApplicationInfo(packageName, PackageManager.GET_ACTIVITIES).uid) as? Int ?: 0 + }.getOrNull() ?: 0 + /** * 自动忽略 MIUI 系统可能出现的日志收集注入实例 * @param packageName 当前包名