refactor: take over KavaRef log to YLog

This commit is contained in:
2025-06-17 16:32:01 +08:00
parent beb7b431f8
commit 4ecc67507a
6 changed files with 95 additions and 43 deletions

View File

@@ -2,11 +2,12 @@
> Log is the most important part of the debugging process, `YukiHookAPI` encapsulates a set of stable and efficient debugging log functions for developers.
::: warning
::: tip
The log of `KavaRef` will be managed separately by itself.
For detailed configuration plans, you can refer to [here](https://highcapable.github.io/KavaRef/en/library/kavaref-core#exception-handling),
which will jump to the `KavaRef` document.
The logs of `KavaRef` can be managed separately by itself. For detailed configuration plans,
you can refer to [here](https://highcapable.github.io/KavaRef/en/library/kavaref-core#log-management), which will jump to the `KavaRef` document.
`YukiHookAPI` has taken over the logging function of `KavaRef` by default, and you can also configure the logging function of `KavaRef` yourself.
:::

View File

@@ -2,9 +2,11 @@
> 日志是调试过程最重要的一环,`YukiHookAPI` 为开发者封装了一套稳定高效的调试日志功能。
::: warning
::: tip
`KavaRef` 的日志由其自身单独管理,详细的配置方案你可以参考 [这里](https://highcapable.github.io/KavaRef/zh-cn/library/kavaref-core#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86),这将跳转到 `KavaRef` 的文档。
`KavaRef` 的日志可以由其自身单独管理,详细的配置方案你可以参考 [这里](https://highcapable.github.io/KavaRef/zh-cn/library/kavaref-core#%E6%97%A5%E5%BF%97%E7%AE%A1%E7%90%86),这将跳转到 `KavaRef` 的文档。
`YukiHookAPI` 默认接管了 `KavaRef` 的日志功能,你也可以自己配置 `KavaRef` 的日志功能。
:::

View File

@@ -25,6 +25,8 @@ package com.highcapable.yukihookapi.hook.log
import android.system.ErrnoException
import android.util.Log
import com.highcapable.kavaref.KavaRef
import com.highcapable.kavaref.runtime.KavaRefRuntime
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
import com.highcapable.yukihookapi.hook.log.data.YLogData
@@ -311,6 +313,8 @@ object YLog {
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
*/
private fun log(env: EnvType, data: YLogData, isImplicit: Boolean = false) {
initKavaRefLoggerIfNot()
/** 是否为有效日志 */
val isNotBlankLog = data.msg.isNotBlank() || (data.msg.isBlank() && data.throwable != null)
@@ -339,6 +343,48 @@ object YLog {
if (isImplicit.not() && Configs.isRecord && isNotBlankLog) inMemoryData.add(data)
}
/** 定义 [KavaRef] 日志记录器 */
private val kavaRefLogger = object : KavaRefRuntime.Logger {
override val tag get() = Configs.tag
override fun debug(msg: Any?, throwable: Throwable?) {
this@YLog.debug(msg.toString(), throwable)
}
override fun error(msg: Any?, throwable: Throwable?) {
this@YLog.error(msg.toString(), throwable)
}
override fun info(msg: Any?, throwable: Throwable?) {
this@YLog.info(msg.toString(), throwable)
}
override fun warn(msg: Any?, throwable: Throwable?) {
this@YLog.warn(msg.toString(), throwable)
}
}
/** 是否已初始化 [KavaRef] 日志记录器 */
private var isKavaRefLoggerInit = false
/** 初始化 [KavaRef] 日志记录器 - 仅在第一次调用时进行初始化 */
private fun initKavaRefLoggerIfNot() {
updateKavaRefLogLevel()
if (isKavaRefLoggerInit) return
KavaRef.setLogger(kavaRefLogger)
isKavaRefLoggerInit = true
}
/** 更新 [KavaRef] 日志记录器的日志级别 */
private fun updateKavaRefLogLevel() {
KavaRef.logLevel = when {
!Configs.isEnable -> KavaRefRuntime.LogLevel.OFF
YukiHookAPI.Configs.isDebug -> KavaRefRuntime.LogLevel.DEBUG
else -> KavaRefRuntime.LogLevel.INFO
}
}
/**
* 需要打印的日志环境类型
*

View File

@@ -111,7 +111,9 @@ internal object YukiXposedModuleStatus {
* @param name 方法名称
* @return [MethodResolver] or null
*/
private fun classMethod(name: String) = className.toClassOrNull()?.resolve()?.optional()?.firstMethodOrNull { this.name = name }.apply {
if (this == null) YLog.innerW("Failed to initialize YukiXposedModuleStatus")
}
private fun classMethod(name: String) = className.toClassOrNull()?.resolve()
?.optional(silent = true)
?.firstMethodOrNull { this.name = name }.apply {
if (this == null) YLog.innerW("Failed to initialize YukiXposedModuleStatus")
}
}

View File

@@ -121,7 +121,7 @@ internal object AppParasitics {
internal val systemContext get(): Context? {
val scope = ActivityThreadClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
val current = scope.firstMethodOrNull {
name = "currentActivityThread"
emptyParameters()
@@ -140,7 +140,7 @@ internal object AppParasitics {
get() = runCatching { AndroidAppHelper.currentApplication() }.getOrNull()
?: ActivityThreadClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull { name = "currentApplication" }
?.invoke<Application>()
@@ -153,14 +153,14 @@ internal object AppParasitics {
?: let {
val scope = ActivityThreadClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
val current = scope.firstMethodOrNull {
name = "currentActivityThread"
emptyParameters()
}?.invoke()
val currentScope = current?.resolve()?.optional()
val currentScope = current?.resolve()?.optional(silent = true)
val mBoundApplication = currentScope?.firstFieldOrNull { name = "mBoundApplication" }?.get()
val appScope = mBoundApplication?.resolve()?.optional()
val appScope = mBoundApplication?.resolve()?.optional(silent = true)
appScope?.firstFieldOrNull { name = "appInfo" }?.get<ApplicationInfo>()
}
@@ -178,7 +178,7 @@ internal object AppParasitics {
get() = runCatching { AndroidAppHelper.currentProcessName() }.getOrNull()
?: ActivityThreadClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull { name = "currentPackageName" }
?.invoke<String>()
?.takeIf { it.isNotBlank() }
@@ -196,7 +196,7 @@ internal object AppParasitics {
?: return 0
return UserHandle::class.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull {
name = "getUserId"
parameters(Int::class)
@@ -213,10 +213,12 @@ internal object AppParasitics {
if (YukiXposedModule.isXposedEnvironment.not()) return YLog.innerW("You can only use hook ClassLoader method in Xposed Environment")
classLoaderCallbacks[loader.hashCode()] = result
if (isClassLoaderHooked) return
val loadClass = ClassLoader::class.resolve().optional().firstMethodOrNull {
name = "loadClass"
parameters(String::class, Boolean::class)
}
val loadClass = ClassLoader::class.resolve()
.optional(silent = true)
.firstMethodOrNull {
name = "loadClass"
parameters(String::class, Boolean::class)
}
runCatching {
YukiHookHelper.hook(loadClass, object : YukiMemberHook() {
override fun afterHookedMember(param: Param) {
@@ -239,7 +241,7 @@ internal object AppParasitics {
YukiHookHelper.hook(
ContextImplClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull { name = "setFilePermissionsFromMode" },
object : YukiMemberHook() {
override fun beforeHookedMember(param: Param) {
@@ -247,7 +249,7 @@ internal object AppParasitics {
}
}
)
YukiXposedModuleStatus.className.toClassOrNull(loader)?.resolve()?.optional()?.apply {
YukiXposedModuleStatus.className.toClassOrNull(loader)?.resolve()?.optional(silent = true)?.apply {
if (type != HookEntryType.RESOURCES) {
YukiHookHelper.hook(firstMethodOrNull { name = YukiXposedModuleStatus.IS_ACTIVE_METHOD_NAME },
object : YukiMemberReplacement() {
@@ -294,7 +296,7 @@ internal object AppParasitics {
}
/** Hook [Application] 装载方法 */
runCatching {
if (appLifecycleActors.isNotEmpty()) Application::class.resolve().apply {
if (appLifecycleActors.isNotEmpty()) Application::class.resolve().optional(silent = true).apply {
YukiHookHelper.hook(firstMethod { name = "attach"; parameters(Context::class) }, object : YukiMemberHook() {
override fun beforeHookedMember(param: Param) {
runCatching {
@@ -351,7 +353,7 @@ internal object AppParasitics {
}
if (YukiHookAPI.Configs.isEnableDataChannel || appLifecycleActors.isNotEmpty())
YukiHookHelper.hook(
Instrumentation::class.resolve().optional().firstMethodOrNull { name = "callApplicationOnCreate" },
Instrumentation::class.resolve().optional(silent = true).firstMethodOrNull { name = "callApplicationOnCreate" },
object : YukiMemberHook() {
override fun afterHookedMember(param: Param) {
runCatching {
@@ -414,7 +416,7 @@ internal object AppParasitics {
return YLog.innerE("You cannot inject module resources into yourself")
hostResources.assets.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull {
name = "addAssetPath"
parameters(String::class)
@@ -450,7 +452,7 @@ internal object AppParasitics {
queryIntentActivities(getLaunchIntentForPackage(context.packageName)!!, 0).first().activityInfo.name
}?.getOrNull() ?: ""
val checkIsActivity = proxyClassName.toClassOrNull(context.classLoader)
?.resolve()?.optional()
?.resolve()?.optional(silent = true)
?.firstMethodOrNull {
name = "setIntent"
parameters(Intent::class)
@@ -464,27 +466,27 @@ internal object AppParasitics {
/** Patched [Instrumentation] */
val sCurrentActivityThread = ActivityThreadClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstFieldOrNull { name = "sCurrentActivityThread" }
?.get()
val instrumentation = sCurrentActivityThread?.resolve()
?.processor(AndroidHiddenApiBypassResolver.get())
?.optional()
?.optional(silent = true)
?.firstMethodOrNull { name = "getInstrumentation" }
?.invoke<Instrumentation>() ?: error("Could not found Instrumentation in ActivityThread")
sCurrentActivityThread.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstFieldOrNull { name = "mInstrumentation" }
?.set(InstrumentationDelegate.wrapper(instrumentation))
val mH = sCurrentActivityThread.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstFieldOrNull { name = "mH" }
?.get<Handler>() ?: error("Could not found mH in ActivityThread")
val mCallbackResolver = Handler::class.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstFieldOrNull { name = "mCallback" }
?.of(mH)
val mCallback = mCallbackResolver?.get<Handler.Callback>()
@@ -506,7 +508,7 @@ internal object AppParasitics {
}?.get()
val mInstanceResolver = SingletonClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstFieldOrNull { name = "mInstance" }
?.of(gDefault)
val mInstance = mInstanceResolver?.get()
@@ -520,7 +522,7 @@ internal object AppParasitics {
?.get()
SingletonClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull { name = "get" }
?.of(singleton)
?.invokeQuietly()

View File

@@ -52,7 +52,7 @@ internal object HandlerDelegateCaller {
private val ClientTransactionClass by lazyClass("android.app.servertransaction.ClientTransaction")
private val mExtrasResolver by lazy {
Intent::class.resolve().optional().firstFieldOrNull { name = "mExtras" }
Intent::class.resolve().optional(silent = true).firstFieldOrNull { name = "mExtras" }
}
/**
@@ -66,7 +66,7 @@ internal object HandlerDelegateCaller {
LAUNCH_ACTIVITY -> {
val intentResolver = msg.obj.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstFieldOrNull { name = "intent" }
val intent = intentResolver?.get<Intent>()
val mExtras = mExtrasResolver?.copy()?.of(intent)?.getQuietly<Bundle>()
@@ -78,14 +78,14 @@ internal object HandlerDelegateCaller {
EXECUTE_TRANSACTION -> {
val callbacks = ClientTransactionClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull {
name = "getCallbacks"
}?.of(msg.obj)
?.invokeQuietly<List<Any>>()
?.takeIf { it.isNotEmpty() }
callbacks?.filter { it.javaClass.name.contains("LaunchActivityItem") }?.forEach { item ->
val itemResolver = item.resolve().optional()
val itemResolver = item.resolve().optional(silent = true)
.firstFieldOrNull { name = "mIntent" }
val intent = itemResolver?.get<Intent>()
val mExtras = mExtrasResolver?.copy()?.of(intent)?.getQuietly<Bundle>()
@@ -96,31 +96,30 @@ internal object HandlerDelegateCaller {
if (Build.VERSION.SDK_INT >= 31) {
val currentActivityThread = ActivityThreadClass.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull { name = "currentActivityThread" }
?.invoke()
val token = msg.obj.resolve()
.processor(AndroidHiddenApiBypassResolver.get())
.optional()
.optional(silent = true)
.firstMethodOrNull { name = "getActivityToken" }
?.invokeQuietly()
val launchingActivity = currentActivityThread?.resolve()
?.processor(AndroidHiddenApiBypassResolver.get())
?.optional()
?.optional(silent = true)
?.firstMethodOrNull {
name = "getLaunchingActivity"
parameters(IBinder::class)
}?.invokeQuietly(token)
launchingActivity?.resolve()
?.processor(AndroidHiddenApiBypassResolver.get())
?.optional()
?.optional(silent = true)
?.firstFieldOrNull { name = "intent" }
?.set(subIntent)
}; itemResolver.set(subIntent)
}
}
}
}
return baseInstance?.handleMessage(msg) ?: false
}; return baseInstance?.handleMessage(msg) ?: false
}
}