From f6096721b732106743a1008196b16e45e5e3f521 Mon Sep 17 00:00:00 2001 From: fankesyooni Date: Tue, 25 Apr 2023 05:03:20 +0800 Subject: [PATCH] Modify remove Members cache function and remove LruCache function, optimizing performance of finder --- .../highcapable/yukihookapi/YukiHookAPI.md | 23 +-- .../highcapable/yukihookapi/YukiHookAPI.md | 23 +-- .../highcapable/yukihookapi/YukiHookAPI.kt | 24 +-- .../core/finder/base/data/BaseRulesData.kt | 7 +- .../finder/classes/data/ClassRulesData.kt | 4 +- .../members/data/ConstructorRulesData.kt | 4 +- .../finder/members/data/FieldRulesData.kt | 4 +- .../finder/members/data/MemberRulesData.kt | 4 +- .../finder/members/data/MethodRulesData.kt | 4 +- .../core/finder/store/ReflectsCacheStore.kt | 164 ------------------ .../hook/core/finder/tools/ReflectionTool.kt | 126 ++++++++------ .../hook/utils/memory/LruCacheMemory.kt | 45 ----- .../utils/memory/factory/LruCacheFactory.kt | 64 ------- 13 files changed, 88 insertions(+), 408 deletions(-) delete mode 100644 yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/store/ReflectsCacheStore.kt delete mode 100644 yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/LruCacheMemory.kt delete mode 100644 yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/factory/LruCacheFactory.kt diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md index 8ec63842..1ba20531 100644 --- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md +++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md @@ -512,29 +512,15 @@ var isEnableDataChannel: Boolean 此功能默认启用,关闭后将不会在功能初始化的时候装载 `YukiHookDataChannel`。 -### isEnableMemberCache - field - -```kotlin:no-line-numbers -var isEnableMemberCache: Boolean -``` +

isEnableMemberCache - field

**Change Records** `v1.0.68` `added` -**Function Illustrate** +`v1.1.11` `deprecated` -> 是否启用 `Member` 缓存功能。 - -为防止 `Member` 复用过高造成的系统 GC 问题,此功能默认启用。 - -启用后会缓存已经找到的 `Method`、`Constructor`、`Field`。 - -缓存的 `Member` 都将处于 `ReflectsCacheStore` 的全局静态实例中。 - -推荐使用 `MethodFinder`、`ConstructorFinder`、`FieldFinder` 来获取 `Member`。 - -除非缓存的 `Member` 发生了混淆的问题,例如使用 R8 混淆后的 APP 的目标 `Member`,否则建议启用。 +`Member` 的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题 ## configs - method @@ -578,7 +564,6 @@ object HookEntry : IYukiHookXposedInit { isEnableHookModuleStatus = true isEnableHookSharedPreferences = false isEnableDataChannel = true - isEnableMemberCache = true } } @@ -607,7 +592,6 @@ object HookEntry : IYukiHookXposedInit { isEnableHookModuleStatus = true isEnableHookSharedPreferences = false isEnableDataChannel = true - isEnableMemberCache = true } override fun onHook() { @@ -638,7 +622,6 @@ object HookEntry : IYukiHookXposedInit { YukiHookAPI.Configs.isEnableHookModuleStatus = true YukiHookAPI.Configs.isEnableHookSharedPreferences = false YukiHookAPI.Configs.isEnableDataChannel = true - YukiHookAPI.Configs.isEnableMemberCache = true } override fun onHook() { diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md index 820e596a..ef140b7d 100644 --- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md +++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md @@ -504,29 +504,15 @@ var isEnableDataChannel: Boolean 此功能默认启用,关闭后将不会在功能初始化的时候装载 `YukiHookDataChannel`。 -### isEnableMemberCache - field - -```kotlin:no-line-numbers -var isEnableMemberCache: Boolean -``` +

isEnableMemberCache - field

**变更记录** `v1.0.68` `新增` -**功能描述** +`v1.1.11` `作废` -> 是否启用 `Member` 缓存功能。 - -为防止 `Member` 复用过高造成的系统 GC 问题,此功能默认启用。 - -启用后会缓存已经找到的 `Method`、`Constructor`、`Field`。 - -缓存的 `Member` 都将处于 `ReflectsCacheStore` 的全局静态实例中。 - -推荐使用 `MethodFinder`、`ConstructorFinder`、`FieldFinder` 来获取 `Member`。 - -除非缓存的 `Member` 发生了混淆的问题,例如使用 R8 混淆后的 APP 的目标 `Member`,否则建议启用。 +`Member` 的直接缓存功能已被移除,因为其存在内存溢出 (OOM) 问题 ## configs - method @@ -570,7 +556,6 @@ object HookEntry : IYukiHookXposedInit { isEnableHookModuleStatus = true isEnableHookSharedPreferences = false isEnableDataChannel = true - isEnableMemberCache = true } } @@ -599,7 +584,6 @@ object HookEntry : IYukiHookXposedInit { isEnableHookModuleStatus = true isEnableHookSharedPreferences = false isEnableDataChannel = true - isEnableMemberCache = true } override fun onHook() { @@ -630,7 +614,6 @@ object HookEntry : IYukiHookXposedInit { YukiHookAPI.Configs.isEnableHookModuleStatus = true YukiHookAPI.Configs.isEnableHookSharedPreferences = false YukiHookAPI.Configs.isEnableDataChannel = true - YukiHookAPI.Configs.isEnableMemberCache = true } override fun onHook() { diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt index c33d7f12..dba73525 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt @@ -40,10 +40,6 @@ import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper import com.highcapable.yukihookapi.hook.core.api.compat.HookApiProperty import com.highcapable.yukihookapi.hook.core.api.compat.type.ExecutorType -import com.highcapable.yukihookapi.hook.core.finder.members.ConstructorFinder -import com.highcapable.yukihookapi.hook.core.finder.members.FieldFinder -import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder -import com.highcapable.yukihookapi.hook.core.finder.store.ReflectsCacheStore import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.factory.isTaiChiModuleActive import com.highcapable.yukihookapi.hook.factory.processName @@ -58,10 +54,7 @@ import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiXposedModuleSta import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge -import java.lang.reflect.Constructor -import java.lang.reflect.Field import java.lang.reflect.Member -import java.lang.reflect.Method /** * [YukiHookAPI] 的装载调用类 @@ -343,21 +336,12 @@ object YukiHookAPI { /** * 是否启用 [Member] 缓存功能 * - * - 为防止 [Member] 复用过高造成的系统 GC 问题 - 此功能默认启用 + * - ❗此方法及功能已被移除 - 在之后的版本中将直接被删除 * - * 启用后会缓存已经找到的 [Method]、[Constructor]、[Field] - * - * 缓存的 [Member] 都将处于 [ReflectsCacheStore] 的全局静态实例中 - * - * 推荐使用 [MethodFinder]、[ConstructorFinder]、[FieldFinder] 来获取 [Member] - * - * 详情请参考 [API 文档](https://fankes.github.io/YukiHookAPI/zh-cn/api/home) - * - * For English version, see [API Document](https://fankes.github.io/YukiHookAPI/en/api/home) - * - * 除非缓存的 [Member] 发生了混淆的问题 - 例如使用 R8 混淆后的 APP 的目标 [Member] - 否则建议启用 + * - ❗[Member] 的直接缓存功能已被移除 - 因为其存在内存溢出 (OOM) 问题 */ - var isEnableMemberCache = true + @Deprecated(message = "此方法及功能已被移除,请删除此方法") + var isEnableMemberCache = false } /** diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/base/data/BaseRulesData.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/base/data/BaseRulesData.kt index 57d9d156..e6a61c98 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/base/data/BaseRulesData.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/base/data/BaseRulesData.kt @@ -139,10 +139,5 @@ internal abstract class BaseRulesData internal constructor( */ internal open val isInitialize get() = modifiers != null || orderIndex != null || matchIndex != null - /** - * 通过规则数据 [toString] 来得到一个 [Any.hashCode] - * @param other 额外的数据 - 可选 - * @return [Int] - */ - internal open fun hashCode(other: Any? = null) = "[$other][$modifiers][$orderIndex][$matchIndex]".hashCode() + override fun toString() = "[$modifiers][$orderIndex][$matchIndex]" } \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/classes/data/ClassRulesData.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/classes/data/ClassRulesData.kt index c45678b3..96706808 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/classes/data/ClassRulesData.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/classes/data/ClassRulesData.kt @@ -175,9 +175,7 @@ internal class ClassRulesData internal constructor( isNoExtendsClass != null || isNoImplementsClass != null || extendsClass.isNotEmpty() || enclosingClass.isNotEmpty() || memberRules.isNotEmpty() || fieldRules.isNotEmpty() || methodRules.isNotEmpty() || constroctorRules.isNotEmpty() - override fun hashCode(other: Any?) = super.hashCode(other) + toString().hashCode() - override fun toString() = "[$fromPackages][$fullName][$simpleName][$singleName][$fullNameConditions][$simpleNameConditions]" + "[$singleNameConditions][$modifiers][$isAnonymousClass][$isNoExtendsClass][$isNoImplementsClass][$extendsClass][$implementsClass]" + - "[$enclosingClass][$memberRules][$fieldRules][$methodRules][$constroctorRules]" + "[$enclosingClass][$memberRules][$fieldRules][$methodRules][$constroctorRules]" + super.toString() } \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/ConstructorRulesData.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/ConstructorRulesData.kt index 53c88c04..a2c41e8f 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/ConstructorRulesData.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/ConstructorRulesData.kt @@ -63,7 +63,5 @@ internal class ConstructorRulesData internal constructor( get() = super.isInitializeOfSuper || paramTypes != null || paramTypesConditions != null || paramCount >= 0 || paramCountRange.isEmpty().not() || paramCountConditions != null - override fun hashCode(other: Any?) = super.hashCode(other) + toString().hashCode() - - override fun toString() = "[$paramTypes][$paramTypesConditions][$paramCount][$paramCountRange]" + override fun toString() = "[$paramTypes][$paramTypesConditions][$paramCount][$paramCountRange]" + super.toString() } \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/FieldRulesData.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/FieldRulesData.kt index 21bbee88..d2b89631 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/FieldRulesData.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/FieldRulesData.kt @@ -59,7 +59,5 @@ internal class FieldRulesData internal constructor( override val isInitialize get() = super.isInitializeOfSuper || name.isNotBlank() || nameConditions != null || type != null || typeConditions != null - override fun hashCode(other: Any?) = super.hashCode(other) + toString().hashCode() - - override fun toString() = "[$name][$nameConditions][$type][$typeConditions]" + override fun toString() = "[$name][$nameConditions][$type][$typeConditions]" + super.toString() } \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MemberRulesData.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MemberRulesData.kt index 2dcfb843..d38e636a 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MemberRulesData.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MemberRulesData.kt @@ -70,7 +70,5 @@ internal open class MemberRulesData internal constructor( override val isInitialize get() = isInitializeOfSuper || isInitializeOfMatch - override fun hashCode(other: Any?) = super.hashCode(other) + toString().hashCode() - - override fun toString() = "[$isFindInSuper][$matchIndex][$matchCountRange]" + override fun toString() = "[$isFindInSuper][$matchIndex][$matchCountRange][$matchCountConditions]" + super.toString() } \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MethodRulesData.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MethodRulesData.kt index f1059e1e..aee3dc41 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MethodRulesData.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/members/data/MethodRulesData.kt @@ -78,8 +78,6 @@ internal class MethodRulesData internal constructor( paramCount >= 0 || paramCountRange.isEmpty().not() || paramCountConditions != null || returnType != null || returnTypeConditions != null - override fun hashCode(other: Any?) = super.hashCode(other) + toString().hashCode() - override fun toString() = "[$name][$nameConditions][$paramTypes][$paramTypesConditions][$paramCount]" + - "[$paramCountRange][$returnType][$returnTypeConditions]" + "[$paramCountRange][$returnType][$returnTypeConditions]" + super.toString() } \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/store/ReflectsCacheStore.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/store/ReflectsCacheStore.kt deleted file mode 100644 index c8a11b60..00000000 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/store/ReflectsCacheStore.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * YukiHookAPI - An efficient Hook API and Xposed Module solution built in Kotlin. - * Copyright (C) 2019-2023 HighCapable - * https://github.com/fankes/YukiHookAPI - * - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * This file is Created by fankes on 2022/3/29. - */ -package com.highcapable.yukihookapi.hook.core.finder.store - -import android.util.ArrayMap -import com.highcapable.yukihookapi.YukiHookAPI -import java.lang.reflect.Constructor -import java.lang.reflect.Field -import java.lang.reflect.Member -import java.lang.reflect.Method - -/** - * 这是一个全局静态的 [Class]、[Member] 缓存实例 - * - * 为防止 [Class]、[Member] 复用过高造成的系统 GC 问题 - * - * 查找后的 [Class] 自动进入缓存 - 不受任何控制 - * - * 查找后的 [Member] 在 [YukiHookAPI.Configs.isEnableMemberCache] 启用后自动进入缓存 - */ -internal object ReflectsCacheStore { - - /** 缓存的 [Class] 列表 */ - private val dexClassListData = ArrayMap>() - - /** 缓存的 [Class] 对象 */ - private val classData = ArrayMap?>() - - /** 缓存的 [Class] 数组 */ - private val classesData = ArrayMap>>() - - /** 缓存的 [Method] 数组 */ - private val methodsData = ArrayMap>() - - /** 缓存的 [Constructor] 数组 */ - private val constructorsData = ArrayMap>>() - - /** 缓存的 [Field] 数组 */ - private val fieldsData = ArrayMap>() - - /** - * 查找缓存中的 [Class] 列表 - * @param hashCode 标识符 - * @return [List]<[Class]> - */ - internal fun findDexClassList(hashCode: Int) = dexClassListData[hashCode] - - /** - * 查找缓存中的 [Class] - * @param hashCode 标识符 - * @return [Class] or null - */ - internal fun findClass(hashCode: Int) = classData[hashCode] - - /** - * 查找缓存中的 [Class] 数组 - * @param hashCode 标识符 - * @return [HashSet]<[Class]> or null - */ - internal fun findClasses(hashCode: Int) = classesData[hashCode] - - /** - * 查找缓存中的 [Method] 数组 - * @param hashCode 标识符 - * @return [HashSet]<[Method]> - */ - internal fun findMethods(hashCode: Int) = methodsData[hashCode] - - /** - * 查找缓存中的 [Constructor] 数组 - * @param hashCode 标识符 - * @return [HashSet]<[Constructor]> - */ - internal fun findConstructors(hashCode: Int) = constructorsData[hashCode] - - /** - * 查找缓存中的 [Field] 数组 - * @param hashCode 标识符 - * @return [HashSet]<[Field]> - */ - internal fun findFields(hashCode: Int) = fieldsData[hashCode] - - /** - * 写入 [Class] 列表到缓存 - * @param hashCode 标识符 - * @param instance 实例 - */ - internal fun putDexClassList(hashCode: Int, instance: List) { - dexClassListData[hashCode] = instance - } - - /** - * 写入 [Class] 到缓存 - * @param hashCode 标识符 - * @param instance 实例 - */ - internal fun putClass(hashCode: Int, instance: Class<*>?) { - classData[hashCode] = instance - } - - /** - * 写入 [Class] 数组到缓存 - * @param hashCode 标识符 - * @param instance 实例 - */ - internal fun putClasses(hashCode: Int, instance: HashSet>) { - classesData[hashCode] = instance - } - - /** - * 写入 [Method] 数组到缓存 - * @param hashCode 标识符 - * @param instances 实例数组 - */ - internal fun putMethods(hashCode: Int, instances: HashSet) { - if (YukiHookAPI.Configs.isEnableMemberCache.not()) return - methodsData[hashCode] = instances - } - - /** - * 写入 [Constructor] 数组到缓存 - * @param hashCode 标识符 - * @param instances 实例数组 - */ - internal fun putConstructors(hashCode: Int, instances: HashSet>) { - if (YukiHookAPI.Configs.isEnableMemberCache.not()) return - constructorsData[hashCode] = instances - } - - /** - * 写入 [Field] 数组到缓存 - * @param hashCode 标识符 - * @param instances 实例数组 - */ - internal fun putFields(hashCode: Int, instances: HashSet) { - if (YukiHookAPI.Configs.isEnableMemberCache.not()) return - fieldsData[hashCode] = instances - } -} \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt index b4b3f5d1..d12d74f5 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/core/finder/tools/ReflectionTool.kt @@ -29,13 +29,13 @@ package com.highcapable.yukihookapi.hook.core.finder.tools +import android.util.ArrayMap import com.highcapable.yukihookapi.hook.core.finder.base.data.BaseRulesData import com.highcapable.yukihookapi.hook.core.finder.classes.data.ClassRulesData import com.highcapable.yukihookapi.hook.core.finder.members.data.ConstructorRulesData import com.highcapable.yukihookapi.hook.core.finder.members.data.FieldRulesData import com.highcapable.yukihookapi.hook.core.finder.members.data.MemberRulesData import com.highcapable.yukihookapi.hook.core.finder.members.data.MethodRulesData -import com.highcapable.yukihookapi.hook.core.finder.store.ReflectsCacheStore import com.highcapable.yukihookapi.hook.factory.* import com.highcapable.yukihookapi.hook.log.yLoggerW import com.highcapable.yukihookapi.hook.type.defined.UndefinedType @@ -63,13 +63,31 @@ internal object ReflectionTool { /** 当前工具类的标签 */ private const val TAG = "YukiHookAPI#ReflectionTool" + /** + * 当前工具类的 [ClassLoader] + * @return [ClassLoader] + */ + private val currentClassLoader get() = AppParasitics.baseClassLoader + + /** + * 内存缓存实例实现 + */ + private object MemoryCache { + + /** 缓存的 [Class] 列表数组 */ + val dexClassListData = ArrayMap>() + + /** 缓存的 [Class] 对象数组 */ + val classData = ArrayMap?>() + } + /** * 写出当前 [ClassLoader] 下所有 [Class] 名称数组 * @param loader 当前使用的 [ClassLoader] * @return [List]<[String]> * @throws IllegalStateException 如果 [loader] 不是 [BaseDexClassLoader] */ - internal fun findDexClassList(loader: ClassLoader?) = ReflectsCacheStore.findDexClassList(loader.hashCode()) + internal fun findDexClassList(loader: ClassLoader?) = MemoryCache.dexClassListData[loader.toString()] ?: DalvikBaseDexClassLoader.field { name = "pathList" }.ignored().get(loader.value().let { while (it.value !is BaseDexClassLoader) { if (it.value?.parent != null) it.value = it.value?.parent @@ -78,7 +96,7 @@ internal object ReflectionTool { }).current(ignored = true)?.field { name = "dexElements" }?.array()?.flatMap { element -> element.current(ignored = true).field { name = "dexFile" }.current(ignored = true) ?.method { name = "entries" }?.invoke>()?.toList().orEmpty() - }.orEmpty().also { if (it.isNotEmpty()) ReflectsCacheStore.putDexClassList(loader.hashCode(), it) } + }.orEmpty().also { if (it.isNotEmpty()) MemoryCache.dexClassListData[loader.toString()] = it } /** * 使用字符串类名查找 [Class] 是否存在 @@ -98,16 +116,16 @@ internal object ReflectionTool { */ @PublishedApi internal fun findClassByName(name: String, loader: ClassLoader?, initialize: Boolean = false): Class<*> { - val hashCode = ("[$name][$loader]").hashCode() + val uniqueCode = "[$name][$loader]" /** * 获取 [Class.forName] 的 [Class] 对象 * @param name [Class] 完整名称 * @param initialize 是否初始化 [Class] 的静态方法块 - * @param loader [Class] 所在的 [ClassLoader] - 默认为 [AppParasitics.baseClassLoader] + * @param loader [Class] 所在的 [ClassLoader] - 默认为 [currentClassLoader] * @return [Class] */ - fun classForName(name: String, initialize: Boolean, loader: ClassLoader? = AppParasitics.baseClassLoader) = + fun classForName(name: String, initialize: Boolean, loader: ClassLoader? = currentClassLoader) = Class.forName(name, initialize, loader) /** @@ -115,9 +133,9 @@ internal object ReflectionTool { * @return [Class] or null */ fun loadWithDefaultClassLoader() = if (initialize.not()) loader?.loadClass(name) else classForName(name, initialize, loader) - return ReflectsCacheStore.findClass(hashCode) ?: runCatching { - (loadWithDefaultClassLoader() ?: classForName(name, initialize)).also { ReflectsCacheStore.putClass(hashCode, it) } - }.getOrNull() ?: throw createException(loader ?: AppParasitics.baseClassLoader, name = "Class", "name:[$name]") + return MemoryCache.classData[uniqueCode] ?: runCatching { + (loadWithDefaultClassLoader() ?: classForName(name, initialize)).also { MemoryCache.classData[uniqueCode] = it } + }.getOrNull() ?: throw createException(loader ?: currentClassLoader, name = "Class", "name:[$name]") } /** @@ -129,7 +147,7 @@ internal object ReflectionTool { * @throws NoClassDefFoundError 如果找不到 [Class] */ internal fun findClasses(loaderSet: ClassLoader?, rulesData: ClassRulesData) = rulesData.createResult { - ReflectsCacheStore.findClasses(hashCode(loaderSet)) ?: hashSetOf>().also { classes -> + hashSetOf>().also { classes -> /** * 开始查找作业 * @param instance 当前 [Class] 实例 @@ -188,7 +206,7 @@ internal object ReflectionTool { value.modifiers?.also { runCatching { and(it(member.cast())) } } }.finally { numberOfFound++ } }.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } } - else rule.matchCount(size) { and(it) } + else rule.matchCount(count()) { and(it) } } } fieldRules.takeIf { it.isNotEmpty() }?.forEach { rule -> @@ -203,7 +221,7 @@ internal object ReflectionTool { value.typeConditions?.also { field.also { t -> runCatching { and(it(t.type(), t.type)) } } } }.finally { numberOfFound++ } }.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } } - else rule.matchCount(size) { and(it) } + else rule.matchCount(count()) { and(it) } } } methodRules.takeIf { it.isNotEmpty() }?.forEach { rule -> @@ -226,7 +244,7 @@ internal object ReflectionTool { value.nameConditions?.also { method.name.also { n -> runCatching { and(it(n.cast(), n)) } } } }.finally { numberOfFound++ } }.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } } - else rule.matchCount(size) { and(it) } + else rule.matchCount(count()) { and(it) } } } constroctorRules.takeIf { it.isNotEmpty() }?.forEach { rule -> @@ -244,7 +262,7 @@ internal object ReflectionTool { value.modifiers?.also { runCatching { and(it(constructor.cast())) } } }.finally { numberOfFound++ } }.run { rule.matchCount(numberOfFound) { and(it && numberOfFound > 0) } } - else rule.matchCount(size) { and(it) } + else rule.matchCount(count()) { and(it) } } } }.finally { classes.add(instance) } @@ -260,7 +278,7 @@ internal object ReflectionTool { ) startProcess(className.toClass(loaderSet)) } } - }.takeIf { it.isNotEmpty() }?.also { ReflectsCacheStore.putClasses(hashCode(loaderSet), it) } ?: throwNotFoundError(loaderSet) + }.takeIf { it.isNotEmpty() } ?: throwNotFoundError(loaderSet) } /** @@ -274,19 +292,19 @@ internal object ReflectionTool { internal fun findFields(classSet: Class<*>?, rulesData: FieldRulesData) = rulesData.createResult { if (type == UndefinedType) error("Field match type class is not found") if (classSet == null) return@createResult hashSetOf() - ReflectsCacheStore.findFields(hashCode(classSet)) ?: hashSetOf().also { fields -> + hashSetOf().also { fields -> classSet.existFields?.also { declares -> var iType = -1 var iName = -1 var iModify = -1 var iNameCds = -1 var iTypeCds = -1 - val iLType = type?.let(matchIndex) { e -> declares.filter { e == it.type }.lastIndex } ?: -1 - val iLName = name.takeIf(matchIndex) { it.isNotBlank() }?.let { e -> declares.filter { e == it.name }.lastIndex } ?: -1 - val iLModify = modifiers?.let(matchIndex) { e -> declares.filter { runOrFalse { e(it.cast()) } }.lastIndex } ?: -1 + val iLType = type?.let(matchIndex) { e -> declares.findLastIndex { e == it.type } } ?: -1 + val iLName = name.takeIf(matchIndex) { it.isNotBlank() }?.let { e -> declares.findLastIndex { e == it.name } } ?: -1 + val iLModify = modifiers?.let(matchIndex) { e -> declares.findLastIndex { runOrFalse { e(it.cast()) } } } ?: -1 val iLNameCds = nameConditions - ?.let(matchIndex) { e -> declares.filter { it.name.let { n -> runOrFalse { e(n.cast(), n) } } }.lastIndex } ?: -1 - val iLTypeCds = typeConditions?.let(matchIndex) { e -> declares.filter { runOrFalse { e(it.type(), it.type) } }.lastIndex } ?: -1 + ?.let(matchIndex) { e -> declares.findLastIndex { it.name.let { n -> runOrFalse { e(n.cast(), n) } } } } ?: -1 + val iLTypeCds = typeConditions?.let(matchIndex) { e -> declares.findLastIndex { runOrFalse { e(it.type(), it.type) } } } ?: -1 declares.forEachIndexed { index, instance -> conditions { type?.also { @@ -319,11 +337,11 @@ internal object ReflectionTool { hold && matchIndex.compare(iTypeCds, iLTypeCds) }) } - orderIndex.compare(index, declares.lastIndex) { and(it) } + orderIndex.compare(index, declares.lastIndex()) { and(it) } }.finally { fields.add(instance.apply { isAccessible = true }) } } } - }.takeIf { it.isNotEmpty() }?.also { ReflectsCacheStore.putFields(hashCode(classSet), it) } ?: findSuperOrThrow(classSet) + }.takeIf { it.isNotEmpty() } ?: findSuperOrThrow(classSet) } /** @@ -339,7 +357,7 @@ internal object ReflectionTool { if (classSet == null) return@createResult hashSetOf() paramTypes?.takeIf { it.isNotEmpty() } ?.forEachIndexed { p, it -> if (it == UndefinedType) error("Method match paramType[$p] class is not found") } - ReflectsCacheStore.findMethods(hashCode(classSet)) ?: hashSetOf().also { methods -> + hashSetOf().also { methods -> classSet.existMethods?.also { declares -> var iReturnType = -1 var iReturnTypeCds = -1 @@ -351,23 +369,23 @@ internal object ReflectionTool { var iName = -1 var iModify = -1 var iNameCds = -1 - val iLReturnType = returnType?.let(matchIndex) { e -> declares.filter { e == it.returnType }.lastIndex } ?: -1 + val iLReturnType = returnType?.let(matchIndex) { e -> declares.findLastIndex { e == it.returnType } } ?: -1 val iLReturnTypeCds = returnTypeConditions - ?.let(matchIndex) { e -> declares.filter { runOrFalse { e(it.returnType(), it.returnType) } }.lastIndex } ?: -1 + ?.let(matchIndex) { e -> declares.findLastIndex { runOrFalse { e(it.returnType(), it.returnType) } } } ?: -1 val iLParamCount = paramCount.takeIf(matchIndex) { it >= 0 } - ?.let { e -> declares.filter { e == it.parameterTypes.size }.lastIndex } ?: -1 + ?.let { e -> declares.findLastIndex { e == it.parameterTypes.size } } ?: -1 val iLParamCountRange = paramCountRange.takeIf(matchIndex) { it.isEmpty().not() } - ?.let { e -> declares.filter { it.parameterTypes.size in e }.lastIndex } ?: -1 + ?.let { e -> declares.findLastIndex { it.parameterTypes.size in e } } ?: -1 val iLParamCountCds = paramCountConditions?.let(matchIndex) { e -> - declares.filter { it.parameterTypes.size.let { s -> runOrFalse { e(s.cast(), s) } } }.lastIndex + declares.findLastIndex { it.parameterTypes.size.let { s -> runOrFalse { e(s.cast(), s) } } } } ?: -1 - val iLParamTypes = paramTypes?.let(matchIndex) { e -> declares.filter { paramTypesEq(e, it.parameterTypes) }.lastIndex } ?: -1 + val iLParamTypes = paramTypes?.let(matchIndex) { e -> declares.findLastIndex { paramTypesEq(e, it.parameterTypes) } } ?: -1 val iLParamTypesCds = paramTypesConditions - ?.let(matchIndex) { e -> declares.filter { runOrFalse { e(it.paramTypes(), it.parameterTypes) } }.lastIndex } ?: -1 - val iLName = name.takeIf(matchIndex) { it.isNotBlank() }?.let { e -> declares.filter { e == it.name }.lastIndex } ?: -1 - val iLModify = modifiers?.let(matchIndex) { e -> declares.filter { runOrFalse { e(it.cast()) } }.lastIndex } ?: -1 + ?.let(matchIndex) { e -> declares.findLastIndex { runOrFalse { e(it.paramTypes(), it.parameterTypes) } } } ?: -1 + val iLName = name.takeIf(matchIndex) { it.isNotBlank() }?.let { e -> declares.findLastIndex { e == it.name } } ?: -1 + val iLModify = modifiers?.let(matchIndex) { e -> declares.findLastIndex { runOrFalse { e(it.cast()) } } } ?: -1 val iLNameCds = nameConditions - ?.let(matchIndex) { e -> declares.filter { it.name.let { n -> runOrFalse { e(n.cast(), n) } } }.lastIndex } ?: -1 + ?.let(matchIndex) { e -> declares.findLastIndex { it.name.let { n -> runOrFalse { e(n.cast(), n) } } } } ?: -1 declares.forEachIndexed { index, instance -> conditions { name.takeIf { it.isNotBlank() }?.also { @@ -430,11 +448,11 @@ internal object ReflectionTool { hold && matchIndex.compare(iNameCds, iLNameCds) }) } - orderIndex.compare(index, declares.lastIndex) { and(it) } + orderIndex.compare(index, declares.lastIndex()) { and(it) } }.finally { methods.add(instance.apply { isAccessible = true }) } } } - }.takeIf { it.isNotEmpty() }?.also { ReflectsCacheStore.putMethods(hashCode(classSet), it) } ?: findSuperOrThrow(classSet) + }.takeIf { it.isNotEmpty() } ?: findSuperOrThrow(classSet) } /** @@ -449,7 +467,7 @@ internal object ReflectionTool { if (classSet == null) return@createResult hashSetOf() paramTypes?.takeIf { it.isNotEmpty() } ?.forEachIndexed { p, it -> if (it == UndefinedType) error("Constructor match paramType[$p] class is not found") } - ReflectsCacheStore.findConstructors(hashCode(classSet)) ?: hashSetOf>().also { constructors -> + hashSetOf>().also { constructors -> classSet.existConstructors?.also { declares -> var iParamTypes = -1 var iParamTypesCds = -1 @@ -458,16 +476,16 @@ internal object ReflectionTool { var iParamCountCds = -1 var iModify = -1 val iLParamCount = paramCount.takeIf(matchIndex) { it >= 0 } - ?.let { e -> declares.filter { e == it.parameterTypes.size }.lastIndex } ?: -1 + ?.let { e -> declares.findLastIndex { e == it.parameterTypes.size } } ?: -1 val iLParamCountRange = paramCountRange.takeIf(matchIndex) { it.isEmpty().not() } - ?.let { e -> declares.filter { it.parameterTypes.size in e }.lastIndex } ?: -1 + ?.let { e -> declares.findLastIndex { it.parameterTypes.size in e } } ?: -1 val iLParamCountCds = paramCountConditions?.let(matchIndex) { e -> - declares.filter { it.parameterTypes.size.let { s -> runOrFalse { e(s.cast(), s) } } }.lastIndex + declares.findLastIndex { it.parameterTypes.size.let { s -> runOrFalse { e(s.cast(), s) } } } } ?: -1 - val iLParamTypes = paramTypes?.let(matchIndex) { e -> declares.filter { paramTypesEq(e, it.parameterTypes) }.lastIndex } ?: -1 + val iLParamTypes = paramTypes?.let(matchIndex) { e -> declares.findLastIndex { paramTypesEq(e, it.parameterTypes) } } ?: -1 val iLParamTypesCds = paramTypesConditions - ?.let(matchIndex) { e -> declares.filter { runOrFalse { e(it.paramTypes(), it.parameterTypes) } }.lastIndex } ?: -1 - val iLModify = modifiers?.let(matchIndex) { e -> declares.filter { runOrFalse { e(it.cast()) } }.lastIndex } ?: -1 + ?.let(matchIndex) { e -> declares.findLastIndex { runOrFalse { e(it.paramTypes(), it.parameterTypes) } } } ?: -1 + val iLModify = modifiers?.let(matchIndex) { e -> declares.findLastIndex { runOrFalse { e(it.cast()) } } } ?: -1 declares.forEachIndexed { index, instance -> conditions { paramCount.takeIf { it >= 0 }?.also { @@ -506,11 +524,11 @@ internal object ReflectionTool { hold && matchIndex.compare(iModify, iLModify) }) } - orderIndex.compare(index, declares.lastIndex) { and(it) } + orderIndex.compare(index, declares.lastIndex()) { and(it) } }.finally { constructors.add(instance.apply { isAccessible = true }) } } } - }.takeIf { it.isNotEmpty() }?.also { ReflectsCacheStore.putConstructors(hashCode(classSet), it) } ?: findSuperOrThrow(classSet) + }.takeIf { it.isNotEmpty() } ?: findSuperOrThrow(classSet) } /** @@ -588,7 +606,7 @@ internal object ReflectionTool { is FieldRulesData -> throw createException(instanceSet, objectName, *templates) is MethodRulesData -> throw createException(instanceSet, objectName, *templates) is ConstructorRulesData -> throw createException(instanceSet, objectName, *templates) - is ClassRulesData -> throw createException(instanceSet ?: AppParasitics.baseClassLoader, objectName, *templates) + is ClassRulesData -> throw createException(instanceSet ?: currentClassLoader, objectName, *templates) else -> error("Type [$this] not allowed") } @@ -629,7 +647,7 @@ internal object ReflectionTool { /** * 获取当前 [Class] 中存在的 [Member] 数组 - * @return [Array]<[Member]> + * @return [Sequence]<[Member]> or null */ private val Class<*>.existMembers get() = runCatching { @@ -637,35 +655,35 @@ internal object ReflectionTool { addAll(declaredFields.toList()) addAll(declaredMethods.toList()) addAll(declaredConstructors.toList()) - }.toTypedArray() + }.asSequence() }.onFailure { yLoggerW(msg = "Failed to get the declared Members in [$this] because got an exception\n$it") }.getOrNull() /** * 获取当前 [Class] 中存在的 [Field] 数组 - * @return [Array]<[Field]> + * @return [Sequence]<[Field]> or null */ private val Class<*>.existFields - get() = runCatching { declaredFields }.onFailure { + get() = runCatching { declaredFields.asSequence() }.onFailure { yLoggerW(msg = "Failed to get the declared Fields in [$this] because got an exception\n$it") }.getOrNull() /** * 获取当前 [Class] 中存在的 [Method] 数组 - * @return [Array]<[Method]> + * @return [Sequence]<[Method]> or null */ private val Class<*>.existMethods - get() = runCatching { declaredMethods }.onFailure { + get() = runCatching { declaredMethods.asSequence() }.onFailure { yLoggerW(msg = "Failed to get the declared Methods in [$this] because got an exception\n$it") }.getOrNull() /** * 获取当前 [Class] 中存在的 [Constructor] 数组 - * @return [Array]<[Constructor]> + * @return [Sequence]<[Constructor]> or null */ private val Class<*>.existConstructors - get() = runCatching { declaredConstructors }.onFailure { + get() = runCatching { declaredConstructors.asSequence() }.onFailure { yLoggerW(msg = "Failed to get the declared Constructors in [$this] because got an exception\n$it") }.getOrNull() diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/LruCacheMemory.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/LruCacheMemory.kt deleted file mode 100644 index fd28fd93..00000000 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/LruCacheMemory.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * YukiHookAPI - An efficient Hook API and Xposed Module solution built in Kotlin. - * Copyright (C) 2019-2023 HighCapable - * https://github.com/fankes/YukiHookAPI - * - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * This file is Created by fankes on 2023/4/20. - */ -package com.highcapable.yukihookapi.hook.utils.memory - -import android.util.LruCache - -/** - * [LruCache] 内存定义类 - */ -internal object LruCacheMemory { - - /** 当前最大内存压缩倍数 */ - private const val MAX_COMPRESSION_FACTOR = 16 - - /** 当前可用内存大小 (KB) */ - private val maxMemorySize = (Runtime.getRuntime().maxMemory() / 1024).toInt() - - /** 当前可用缓存大小 (KB) */ - internal val maxCacheSize = maxMemorySize / MAX_COMPRESSION_FACTOR -} \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/factory/LruCacheFactory.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/factory/LruCacheFactory.kt deleted file mode 100644 index 75cd5bab..00000000 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/utils/memory/factory/LruCacheFactory.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * YukiHookAPI - An efficient Hook API and Xposed Module solution built in Kotlin. - * Copyright (C) 2019-2023 HighCapable - * https://github.com/fankes/YukiHookAPI - * - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * This file is Created by fankes on 2023/4/20. - */ -package com.highcapable.yukihookapi.hook.utils.memory.factory - -import android.util.LruCache -import com.highcapable.yukihookapi.hook.utils.memory.LruCacheMemory - -/** - * 创建 [LruCache]<[K], [V]> - * @param sizeOf 回调自定义缓存大小计算数值 - 默认不设置 - * @return [LruCache]<[K], [V]> - */ -internal fun createLruCache(sizeOf: (() -> Int)? = null) = object : LruCache(LruCacheMemory.maxCacheSize) { - override fun sizeOf(key: K?, value: V?) = when { - sizeOf != null -> sizeOf() - value is Array<*> -> { - var allLengths = 0 - if (value.isNotEmpty()) value.forEach { allLengths += it.toString().length } - allLengths / 1024 - } - value is Map<*, *> -> { - var allLengths = 0 - if (value.isNotEmpty()) value.forEach { allLengths += it.toString().length } - allLengths / 1024 - } - value is List<*> -> { - var allLengths = 0 - if (value.isNotEmpty()) value.forEach { allLengths += it.toString().length } - allLengths / 1024 - } - value is Set<*> -> { - var allLengths = 0 - if (value.isNotEmpty()) value.forEach { allLengths += it.toString().length } - allLengths / 1024 - } - value is String -> value.length / 1024 - else -> value.toString().length / 1024 - } -} \ No newline at end of file