mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-01 08:15:37 +08:00
refactor: take over KavaRef log to YLog
This commit is contained in:
@@ -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.
|
||||
|
||||
:::
|
||||
|
||||
|
@@ -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` 的日志功能。
|
||||
|
||||
:::
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 需要打印的日志环境类型
|
||||
*
|
||||
|
@@ -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")
|
||||
}
|
||||
}
|
@@ -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()
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user