Fix inner Hook not invoking and fix maybe created duplicate hook

This commit is contained in:
2022-05-16 03:57:46 +08:00
parent 144111115e
commit 3a1f6e6cb7
5 changed files with 70 additions and 11 deletions

View File

@@ -386,6 +386,20 @@ inline fun HookParam.constructor(initiate: ConstructorFinder.() -> Unit): Constr
> 使用当前 `hookClass` 查找并得到构造方法。
#### injectMember [method]
```kotlin
inline fun HookParam.injectMember(priority: Int, tag: String, initiate: MemberHookCreater.() -> Unit): MemberHookCreater.Result
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 注入要 Hook 的方法、构造类 (嵌套 Hook)。
#### beforeHook [method]
```kotlin

View File

@@ -42,6 +42,7 @@ import com.highcapable.yukihookapi.hook.param.HookParam
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
import com.highcapable.yukihookapi.hook.param.wrapper.HookParamWrapper
import com.highcapable.yukihookapi.hook.utils.putIfAbsentCompat
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import java.lang.reflect.Field
import java.lang.reflect.Member
@@ -79,7 +80,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
/** 设置要 Hook 的方法、构造类 */
@PublishedApi
internal var preHookMembers = HashSet<MemberHookCreater>()
internal var preHookMembers = HashMap<String, MemberHookCreater>()
/**
* 得到当前被 Hook 的 [Class]
@@ -99,7 +100,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
* @return [MemberHookCreater.Result]
*/
inline fun injectMember(priority: Int = PRIORITY_DEFAULT, tag: String = "Default", initiate: MemberHookCreater.() -> Unit) =
MemberHookCreater(priority, tag, packageParam.exhibitName).apply(initiate).apply { preHookMembers.add(this) }.build()
MemberHookCreater(priority, tag, packageParam.exhibitName)
.apply(initiate).apply { preHookMembers.putIfAbsentCompat(toString(), this) }.build()
/**
* Hook 执行入口
@@ -109,8 +111,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
@PublishedApi
internal fun hook(): Result {
if (YukiHookBridge.hasXposedBridge.not()) return Result()
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.PACKAGE] */
if (packageParam.wrapper?.type == HookEntryType.RESOURCES) return Result()
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.PACKAGE] 或 [PackageParam.isHookParamCallback] 已被执行 */
if (packageParam.wrapper?.type == HookEntryType.RESOURCES && packageParam.isHookParamCallback.not()) return Result()
return if (preHookMembers.isEmpty()) error("Hook Members is empty, hook aborted")
else Result().also {
Thread {
@@ -119,7 +121,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
when {
isDisableCreaterRunHook.not() && hookClass.instance != null -> {
it.onPrepareHook?.invoke()
preHookMembers.forEach { m -> m.hook() }
preHookMembers.forEach { (_, m) -> m.hook() }
}
isDisableCreaterRunHook.not() && hookClass.instance == null ->
if (onHookClassNotFoundFailureCallback == null)
@@ -140,6 +142,9 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
*/
inner class MemberHookCreater(private val priority: Int, internal val tag: String, internal val packageName: String) {
/** 是否已经执行 Hook */
private var isHooked = false
/** [beforeHook] 回调 */
private var beforeHookCallback: (HookParam.() -> Unit)? = null
@@ -301,6 +306,19 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
if (hookClass.instance == null) ConstructorFinder(hookInstance = this@MemberHookCreater).failure(hookClass.throwable)
else ConstructorFinder(hookInstance = this@MemberHookCreater, hookClass.instance).apply(initiate).build()
/**
* 注入要 Hook 的方法、构造类 (嵌套 Hook)
* @param priority Hook 优先级 - 默认 [PRIORITY_DEFAULT]
* @param tag 可设置标签 - 在发生错误时方便进行调试
* @param initiate 方法体
* @return [MemberHookCreater.Result]
*/
inline fun HookParam.injectMember(
priority: Int = PRIORITY_DEFAULT,
tag: String = "InnerDefault",
initiate: MemberHookCreater.() -> Unit
) = this@YukiMemberHookCreater.injectMember(priority, tag, initiate).also { this@YukiMemberHookCreater.hook() }
/**
* 在方法执行完成前 Hook
*
@@ -408,7 +426,8 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
/** Hook 执行入口 */
@PublishedApi
internal fun hook() {
if (YukiHookBridge.hasXposedBridge.not() || isDisableMemberRunHook) return
if (YukiHookBridge.hasXposedBridge.not() || isHooked || isDisableMemberRunHook) return
isHooked = true
finder?.printLogIfExist()
if (hookClass.instance == null) {
(hookClass.throwable ?: Throwable("HookClass [${hookClass.name}] not found")).also {
@@ -453,6 +472,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
beforeHookCallback?.invoke(param)
if (beforeHookCallback != null)
onHookLogMsg(msg = "Before Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
packageParam.isHookParamCallback = true
}.onFailure {
onConductFailureCallback?.invoke(param, it)
onAllFailureCallback?.invoke(it)
@@ -467,6 +487,7 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
afterHookCallback?.invoke(param)
if (afterHookCallback != null)
onHookLogMsg(msg = "After Hook Member [${member ?: "All of \"$allMethodsName\""}] done [$tag]")
packageParam.isHookParamCallback = true
}.onFailure {
onConductFailureCallback?.invoke(param, it)
onAllFailureCallback?.invoke(it)
@@ -479,11 +500,11 @@ class YukiMemberHookCreater(@PublishedApi internal val packageParam: PackagePara
if (member != null)
member.also { member ->
runCatching {
if (isReplaceHookMode)
(if (isReplaceHookMode)
YukiHookBridge.Hooker.hookMethod(member, replaceMent)?.also { onHookedCallback?.invoke(it) }
?: error("Hook Member [$member] failed")
else YukiHookBridge.Hooker.hookMethod(member, beforeAfterHook)?.also { onHookedCallback?.invoke(it) }
?: error("Hook Member [$member] failed")
?: error("Hook Member [$member] failed")).run { packageParam.isHookParamCallback = true }
}.onFailure {
onHookingFailureCallback?.invoke(it)
onAllFailureCallback?.invoke(it)

View File

@@ -36,6 +36,7 @@ import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerI
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.param.type.HookEntryType
import com.highcapable.yukihookapi.hook.utils.putIfAbsentCompat
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import com.highcapable.yukihookapi.hook.xposed.bridge.dummy.YukiResources
@@ -49,7 +50,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
/** 设置要 Hook 的 Resources */
@PublishedApi
internal var preHookResources = HashSet<ResourcesHookCreater>()
internal var preHookResources = HashMap<String, ResourcesHookCreater>()
/**
* 注入要 Hook 的 Resources
@@ -58,7 +59,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.add(this) }.build()
ResourcesHookCreater(tag).apply(initiate).apply { preHookResources.putIfAbsentCompat(toString(), this) }.build()
/**
* Hook 执行入口
@@ -70,7 +71,7 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.RESOURCES] */
if (packageParam.wrapper?.type == HookEntryType.PACKAGE) return
if (preHookResources.isEmpty()) error("Hook Resources is empty, hook aborted")
preHookResources.forEach { it.hook() }
preHookResources.forEach { (_, r) -> r.hook() }
}
/**
@@ -81,6 +82,9 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
*/
inner class ResourcesHookCreater(private val tag: String) {
/** 是否已经执行 Hook */
private var isHooked = false
/**
* 模块 APP Resources 替换实例
* @param resId Resources Id
@@ -174,6 +178,8 @@ class YukiResourcesHookCreater(private val packageParam: PackageParam, @Publishe
/** Hook 执行入口 */
@PublishedApi
internal fun hook() {
if (isHooked) return
isHooked = true
if (isDisableCreaterRunHook.not()) runCatching {
when {
conditions == null -> yLoggerE(msg = "You must set the conditions before hook a Resources [$tag]")

View File

@@ -56,6 +56,9 @@ import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
*/
open class PackageParam(@PublishedApi internal var wrapper: PackageParamWrapper? = null) {
/** [HookParam] 是否已经执行回调事件 */
internal var isHookParamCallback = false
/**
* 用于展示的 APP 包名
* @return [String]

View File

@@ -27,8 +27,23 @@
*/
package com.highcapable.yukihookapi.hook.utils
import android.os.Build
import com.highcapable.yukihookapi.annotation.YukiPrivateApi
/**
* 不重复写入 [HashMap]
*
* 兼容旧版本 Android
* @param key Key
* @param value Value
*/
@YukiPrivateApi
inline fun <reified K, V> HashMap<K, V>.putIfAbsentCompat(key: K, value: V) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
putIfAbsent(key, value)
else get(key) ?: put(key, value)
}
/**
* 计算方法执行耗时
* @param block 方法块