mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 09:45:19 +08:00
refactor: split LoggerFactory to YLog and YLogData
This commit is contained in:
@@ -44,9 +44,7 @@ import com.highcapable.yukihookapi.hook.core.api.compat.type.ExecutorType
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.factory.isTaiChiModuleActive
|
||||
import com.highcapable.yukihookapi.hook.factory.processName
|
||||
import com.highcapable.yukihookapi.hook.log.YukiHookLogger
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerI
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
|
||||
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
|
||||
@@ -248,23 +246,23 @@ object YukiHookAPI {
|
||||
object Configs {
|
||||
|
||||
/**
|
||||
* 配置 [YukiHookLogger.Configs] 相关参数
|
||||
* 配置 [YLog.Configs] 相关参数
|
||||
* @param initiate 方法体
|
||||
*/
|
||||
inline fun debugLog(initiate: YukiHookLogger.Configs.() -> Unit) = YukiHookLogger.Configs.apply(initiate).build()
|
||||
inline fun debugLog(initiate: YLog.Configs.() -> Unit) = YLog.Configs.apply(initiate).build()
|
||||
|
||||
/**
|
||||
* 这是一个调试日志的全局标识
|
||||
*
|
||||
* - 此方法已弃用 - 在之后的版本中将直接被删除
|
||||
*
|
||||
* - 请现在迁移到 [debugLog] 并使用 [YukiHookLogger.Configs.tag]
|
||||
* - 请现在迁移到 [debugLog] 并使用 [YLog.Configs.tag]
|
||||
*/
|
||||
@Deprecated(message = "请使用新方式来实现此功能")
|
||||
var debugTag
|
||||
get() = YukiHookLogger.Configs.tag
|
||||
get() = YLog.Configs.tag
|
||||
set(value) {
|
||||
YukiHookLogger.Configs.tag = value
|
||||
YLog.Configs.tag = value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,7 +270,7 @@ object YukiHookAPI {
|
||||
*
|
||||
* 启用后将交由日志输出管理器打印详细 Hook 日志到控制台
|
||||
*
|
||||
* 当 [YukiHookLogger.Configs.isEnable] 关闭后 [isDebug] 也将同时关闭
|
||||
* 当 [YLog.Configs.isEnable] 关闭后 [isDebug] 也将同时关闭
|
||||
*/
|
||||
var isDebug = true
|
||||
|
||||
@@ -281,13 +279,13 @@ object YukiHookAPI {
|
||||
*
|
||||
* - 此方法已弃用 - 在之后的版本中将直接被删除
|
||||
*
|
||||
* - 请现在迁移到 [debugLog] 并使用 [YukiHookLogger.Configs.isEnable]
|
||||
* - 请现在迁移到 [debugLog] 并使用 [YLog.Configs.isEnable]
|
||||
*/
|
||||
@Deprecated(message = "请使用新方式来实现此功能")
|
||||
var isAllowPrintingLogs
|
||||
get() = YukiHookLogger.Configs.isEnable
|
||||
get() = YLog.Configs.isEnable
|
||||
set(value) {
|
||||
YukiHookLogger.Configs.isEnable = value
|
||||
YLog.Configs.isEnable = value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,7 +409,7 @@ object YukiHookAPI {
|
||||
YukiXposedModule.packageParamCallback = {
|
||||
if (hooker.isNotEmpty())
|
||||
hooker.forEach { it.assignInstance(packageParam = this) }
|
||||
else yLoggerE(msg = "Failed to passing \"encase\" method because your hooker param is empty", isImplicit = true)
|
||||
else YLog.innerE("Failed to passing \"encase\" method because your hooker param is empty", isImplicit = true)
|
||||
}
|
||||
else printNotFoundHookApiError()
|
||||
}
|
||||
@@ -471,7 +469,7 @@ object YukiHookAPI {
|
||||
if (hooker.isNotEmpty()) {
|
||||
printSplashInfo()
|
||||
hooker.forEach { it.assignInstance(packageParam = baseContext.createPackageParam()) }
|
||||
} else yLoggerE(msg = "Failed to passing \"encase\" method because your hooker param is empty", isImplicit = true))
|
||||
} else YLog.innerE("Failed to passing \"encase\" method because your hooker param is empty", isImplicit = true))
|
||||
else printNotFoundHookApiError()
|
||||
}
|
||||
|
||||
@@ -479,15 +477,12 @@ object YukiHookAPI {
|
||||
internal fun printSplashInfo() {
|
||||
if (Configs.isDebug.not() || isShowSplashLogOnceTime.not()) return
|
||||
isShowSplashLogOnceTime = false
|
||||
yLoggerI(
|
||||
msg = "Welcome to YukiHookAPI $VERSION! Using ${Status.Executor.name} API ${Status.Executor.apiLevel}",
|
||||
isImplicit = true
|
||||
)
|
||||
YLog.innerI("Welcome to YukiHookAPI $VERSION! Using ${Status.Executor.name} API ${Status.Executor.apiLevel}", isImplicit = true)
|
||||
}
|
||||
|
||||
/** 输出找不到 Hook API 的错误日志 */
|
||||
private fun printNotFoundHookApiError() =
|
||||
yLoggerE(msg = "Could not found any available Hook APIs in current environment! Aborted", isImplicit = true)
|
||||
YLog.innerE("Could not found any available Hook APIs in current environment! Aborted", isImplicit = true)
|
||||
|
||||
/**
|
||||
* 通过 baseContext 创建 Hook 入口类
|
||||
|
@@ -53,9 +53,7 @@ import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.factory.notExtends
|
||||
import com.highcapable.yukihookapi.hook.factory.notImplements
|
||||
import com.highcapable.yukihookapi.hook.factory.toJavaPrimitiveType
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerD
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.param.HookParam
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.type.java.AnyClass
|
||||
@@ -161,7 +159,7 @@ class YukiMemberHookCreator internal constructor(private val packageParam: Packa
|
||||
HookApiCategoryHelper.hasAvailableHookApi.not() -> Result()
|
||||
/** 过滤 [HookEntryType.ZYGOTE] and [HookEntryType.PACKAGE] or [HookParam.isCallbackCalled] 已被执行 */
|
||||
packageParam.wrapper?.type == HookEntryType.RESOURCES && HookParam.isCallbackCalled.not() -> Result()
|
||||
preHookMembers.isEmpty() -> Result().also { yLoggerW(msg = "Hook Members is empty in [${hookClass.name}], hook aborted") }
|
||||
preHookMembers.isEmpty() -> Result().also { YLog.innerW(msg = "Hook Members is empty in [${hookClass.name}], hook aborted") }
|
||||
else -> Result().await {
|
||||
when {
|
||||
isDisableCreatorRunHook.not() && hookClass.instance != null -> runCatching {
|
||||
@@ -170,12 +168,12 @@ class YukiMemberHookCreator internal constructor(private val packageParam: Packa
|
||||
preHookMembers.forEach { (_, m) -> m.hook() }
|
||||
}.onFailure {
|
||||
if (onHookClassNotFoundFailureCallback == null)
|
||||
yLoggerE(msg = "Hook initialization failed because got an Exception", e = it)
|
||||
YLog.innerE(msg = "Hook initialization failed because got an Exception", e = it)
|
||||
else onHookClassNotFoundFailureCallback?.invoke(it)
|
||||
}
|
||||
isDisableCreatorRunHook.not() && hookClass.instance == null ->
|
||||
if (onHookClassNotFoundFailureCallback == null)
|
||||
yLoggerE(msg = "HookClass [${hookClass.name}] not found", e = hookClass.throwable)
|
||||
YLog.innerE(msg = "HookClass [${hookClass.name}] not found", e = hookClass.throwable)
|
||||
else onHookClassNotFoundFailureCallback?.invoke(hookClass.throwable ?: Throwable("[${hookClass.name}] not found"))
|
||||
}
|
||||
}
|
||||
@@ -576,7 +574,7 @@ class YukiMemberHookCreator internal constructor(private val packageParam: Packa
|
||||
onNoSuchMemberFailureCallback?.invoke(it)
|
||||
onHookingFailureCallback?.invoke(it)
|
||||
onAllFailureCallback?.invoke(it)
|
||||
if (isNotIgnoredNoSuchMemberFailure) yLoggerE(
|
||||
if (isNotIgnoredNoSuchMemberFailure) YLog.innerE(
|
||||
msg = (if (isHookMemberSetup)
|
||||
"Hooked Member with a finding error by $hookClass [$tag]"
|
||||
else "Hooked Member cannot be non-null by $hookClass [$tag]"),
|
||||
@@ -676,7 +674,7 @@ class YukiMemberHookCreator internal constructor(private val packageParam: Packa
|
||||
* @param msg 调试日志内容
|
||||
*/
|
||||
private fun hookDebugMsg(msg: String) {
|
||||
if (YukiHookAPI.Configs.isDebug) yLoggerD(msg = msg)
|
||||
if (YukiHookAPI.Configs.isDebug) YLog.innerD(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -685,7 +683,7 @@ class YukiMemberHookCreator internal constructor(private val packageParam: Packa
|
||||
* @param member 异常 [Member] - 可空
|
||||
*/
|
||||
private fun hookErrorMsg(e: Throwable, member: Member? = null) =
|
||||
yLoggerE(msg = "Try to hook [${hookClass.instance ?: hookClass.name}]${member?.let { "[$it]" } ?: ""} got an Exception [$tag]", e = e)
|
||||
YLog.innerE(msg = "Try to hook [${hookClass.instance ?: hookClass.name}]${member?.let { "[$it]" } ?: ""} got an Exception [$tag]", e = e)
|
||||
|
||||
/**
|
||||
* 判断是否没有设置 Hook 过程中的任何异常拦截
|
||||
|
@@ -34,9 +34,7 @@ import android.util.ArrayMap
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.bean.HookResources
|
||||
import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerD
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
|
||||
@@ -66,7 +64,7 @@ class YukiResourcesHookCreator internal constructor(internal val packageParam: P
|
||||
if (HookApiCategoryHelper.hasAvailableHookApi.not()) return
|
||||
/** 过滤 [HookEntryType.ZYGOTE] 与 [HookEntryType.RESOURCES] */
|
||||
if (packageParam.wrapper?.type == HookEntryType.PACKAGE) return
|
||||
if (preHookResources.isEmpty()) return yLoggerW(msg = "Hook Resources is empty, hook aborted")
|
||||
if (preHookResources.isEmpty()) return YLog.innerW("Hook Resources is empty, hook aborted")
|
||||
preHookResources.forEach { (_, r) -> r.hook() }
|
||||
}
|
||||
|
||||
@@ -174,25 +172,25 @@ class YukiResourcesHookCreator internal constructor(internal val packageParam: P
|
||||
isHooked = true
|
||||
if (isDisableCreatorRunHook.not()) runCatching {
|
||||
when {
|
||||
conditions == null -> yLoggerE(msg = "You must set the conditions before hook a Resources [$tag]")
|
||||
replaceInstance == null && layoutInstance == null -> yLoggerE(msg = "Resources Hook got null replaceInstance [$tag]")
|
||||
conditions == null -> YLog.innerE("You must set the conditions before hook a Resources [$tag]")
|
||||
replaceInstance == null && layoutInstance == null -> YLog.innerE("Resources Hook got null replaceInstance [$tag]")
|
||||
packageParam.wrapper?.type == HookEntryType.RESOURCES && hookResources.instance != null ->
|
||||
if (resourceId == -1) when {
|
||||
layoutInstance != null ->
|
||||
hookResources.instance?.hookLayout(
|
||||
packageParam.packageName, conditions!!.type,
|
||||
conditions!!.name, layoutInstance!!
|
||||
) { onHookLogMsg(msg = "Hook Resources Layout $conditions done [$tag]") }
|
||||
) { hookDebugMsg(msg = "Hook Resources Layout $conditions done [$tag]") }
|
||||
else -> hookResources.instance?.setReplacement(
|
||||
packageParam.packageName, conditions!!.type,
|
||||
conditions!!.name, compat(replaceInstance)
|
||||
) { onHookLogMsg(msg = "Hook Resources Value $conditions done [$tag]") }
|
||||
) { hookDebugMsg(msg = "Hook Resources Value $conditions done [$tag]") }
|
||||
} else when {
|
||||
layoutInstance != null -> hookResources.instance?.hookLayout(resourceId, layoutInstance!!) {
|
||||
onHookLogMsg(msg = "Hook Resources Layout Id $resourceId done [$tag]")
|
||||
hookDebugMsg(msg = "Hook Resources Layout Id $resourceId done [$tag]")
|
||||
}
|
||||
else -> hookResources.instance?.setReplacement(resourceId, compat(replaceInstance)) {
|
||||
onHookLogMsg(msg = "Hook Resources Value Id $resourceId done [$tag]")
|
||||
hookDebugMsg(msg = "Hook Resources Value Id $resourceId done [$tag]")
|
||||
}
|
||||
}
|
||||
packageParam.wrapper?.type == HookEntryType.ZYGOTE ->
|
||||
@@ -201,24 +199,24 @@ class YukiResourcesHookCreator internal constructor(internal val packageParam: P
|
||||
YukiResources.hookSystemWideLayout(
|
||||
packageParam.packageName, conditions!!.type,
|
||||
conditions!!.name, layoutInstance!!
|
||||
) { onHookLogMsg(msg = "Hook Wide Resources Layout $conditions done [$tag]") }
|
||||
) { hookDebugMsg(msg = "Hook Wide Resources Layout $conditions done [$tag]") }
|
||||
else -> YukiResources.setSystemWideReplacement(
|
||||
packageParam.packageName, conditions!!.type,
|
||||
conditions!!.name, compat(replaceInstance)
|
||||
) { onHookLogMsg(msg = "Hook Wide Resources Value $conditions done [$tag]") }
|
||||
) { hookDebugMsg(msg = "Hook Wide Resources Value $conditions done [$tag]") }
|
||||
} else when {
|
||||
layoutInstance != null -> YukiResources.hookSystemWideLayout(resourceId, layoutInstance!!) {
|
||||
onHookLogMsg(msg = "Hook Wide Resources Layout Id $resourceId done [$tag]")
|
||||
hookDebugMsg(msg = "Hook Wide Resources Layout Id $resourceId done [$tag]")
|
||||
}
|
||||
else -> YukiResources.setSystemWideReplacement(resourceId, compat(replaceInstance)) {
|
||||
onHookLogMsg(msg = "Hook Wide Resources Value Id $resourceId done [$tag]")
|
||||
hookDebugMsg(msg = "Hook Wide Resources Value Id $resourceId done [$tag]")
|
||||
}
|
||||
}
|
||||
else -> yLoggerE(msg = "Resources Hook type is invalid [$tag]")
|
||||
else -> YLog.innerE("Resources Hook type is invalid [$tag]")
|
||||
}
|
||||
}.onFailure {
|
||||
if (onHookFailureCallback == null)
|
||||
yLoggerE(msg = "Resources Hook got an Exception [$tag]", e = it)
|
||||
YLog.innerE("Resources Hook got an Exception [$tag]", it)
|
||||
else onHookFailureCallback?.invoke(it)
|
||||
}
|
||||
}
|
||||
@@ -227,8 +225,8 @@ class YukiResourcesHookCreator internal constructor(internal val packageParam: P
|
||||
* Hook 过程中开启了 [YukiHookAPI.Configs.isDebug] 输出调试信息
|
||||
* @param msg 调试日志内容
|
||||
*/
|
||||
private fun onHookLogMsg(msg: String) {
|
||||
if (YukiHookAPI.Configs.isDebug) yLoggerD(msg = msg)
|
||||
private fun hookDebugMsg(msg: String) {
|
||||
if (YukiHookAPI.Configs.isDebug) YLog.innerD(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -35,7 +35,7 @@ import com.highcapable.yukihookapi.hook.core.api.store.YukiHookCacheStore
|
||||
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.ConstructorFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.members.MethodFinder
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import java.lang.reflect.Member
|
||||
|
||||
/**
|
||||
@@ -56,7 +56,7 @@ internal object YukiHookHelper {
|
||||
else -> error("Unexpected BaseFinder result interface type")
|
||||
}
|
||||
hookMember(member, callback)
|
||||
}.onFailure { yLoggerE(msg = "An exception occurred when hooking internal function", e = it) }.getOrNull() ?: YukiHookResult()
|
||||
}.onFailure { YLog.innerE("An exception occurred when hooking internal function", it) }.getOrNull() ?: YukiHookResult()
|
||||
|
||||
/**
|
||||
* Hook [Member]
|
||||
@@ -99,7 +99,7 @@ internal object YukiHookHelper {
|
||||
if (isMemberHooked(member)) member?.let {
|
||||
runCatching { HookCompatHelper.invokeOriginalMember(member, instance, args) }.onFailure {
|
||||
if (it.message?.lowercase()?.contains("wrong number of arguments") == true) error(it.message ?: it.toString())
|
||||
yLoggerE(msg = "Invoke original Member [$member] failed", e = it)
|
||||
YLog.innerE("Invoke original Member [$member] failed", it)
|
||||
}.getOrNull()
|
||||
} else null
|
||||
|
||||
|
@@ -29,8 +29,7 @@ package com.highcapable.yukihookapi.hook.core.finder.base
|
||||
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerD
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
|
||||
/**
|
||||
* 这是 [Class] 查找类功能的基本类实现
|
||||
@@ -63,7 +62,7 @@ abstract class ClassBaseFinder internal constructor(internal open val loaderSet:
|
||||
* @param msg 消息内容
|
||||
*/
|
||||
internal fun debugMsg(msg: String) {
|
||||
if (YukiHookAPI.Configs.isDebug && HookApiCategoryHelper.hasAvailableHookApi) yLoggerD(msg = msg)
|
||||
if (YukiHookAPI.Configs.isDebug && HookApiCategoryHelper.hasAvailableHookApi) YLog.innerD(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +73,7 @@ abstract class ClassBaseFinder internal constructor(internal open val loaderSet:
|
||||
if (isIgnoreErrorLogs) return
|
||||
/** 判断是否为 [LOADERSET_IS_NULL] */
|
||||
if (e?.message == LOADERSET_IS_NULL) return
|
||||
yLoggerE(msg = "NoClassDefFound happend in [$loaderSet]", e = e)
|
||||
YLog.innerE("NoClassDefFound happend in [$loaderSet]", e)
|
||||
}
|
||||
|
||||
override fun failure(throwable: Throwable?) = error("DexClassFinder does not contain this usage")
|
||||
|
@@ -30,8 +30,7 @@ package com.highcapable.yukihookapi.hook.core.finder.base
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator
|
||||
import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerD
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.await
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
@@ -96,7 +95,7 @@ abstract class MemberBaseFinder internal constructor(private val tag: String, in
|
||||
*/
|
||||
internal fun debugMsg(msg: String) {
|
||||
if (YukiHookAPI.Configs.isDebug && HookApiCategoryHelper.hasAvailableHookApi && hookerManager.instance != null)
|
||||
yLoggerD(msg = "$msg${hookerManager.tailTag}")
|
||||
YLog.innerD("$msg${hookerManager.tailTag}")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,8 +111,8 @@ abstract class MemberBaseFinder internal constructor(private val tag: String, in
|
||||
await {
|
||||
if (isIgnoreErrorLogs || hookerManager.isNotIgnoredNoSuchMemberFailure.not()) return@await
|
||||
if (isAlwaysMode.not() && isUsingRemedyPlan) return@await
|
||||
yLoggerE(msg = "NoSuch$tag happend in [$classSet] $msg${hookerManager.tailTag}".trim(), e = e)
|
||||
es.forEachIndexed { index, e -> yLoggerE(msg = "Throwable [${index + 1}]", e = e) }
|
||||
YLog.innerE("NoSuch$tag happend in [$classSet] $msg${hookerManager.tailTag}".trim(), e)
|
||||
es.forEachIndexed { index, e -> YLog.innerE("Throwable [${index + 1}]", e) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -48,7 +48,7 @@ import com.highcapable.yukihookapi.hook.core.finder.type.factory.NameConditions
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.factory.searchClass
|
||||
import com.highcapable.yukihookapi.hook.factory.toClass
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.await
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.runBlocking
|
||||
@@ -109,7 +109,7 @@ class DexClassFinder internal constructor(
|
||||
*/
|
||||
fun clearCache(context: Context? = currentContext, versionName: String? = null, versionCode: Long? = null) {
|
||||
context?.currentSp(versionName, versionCode)?.edit()?.clear()?.apply()
|
||||
?: yLoggerW(msg = "Cannot clear cache for DexClassFinder because got null context instance")
|
||||
?: YLog.innerW("Cannot clear cache for DexClassFinder because got null context instance")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,7 @@ import com.highcapable.yukihookapi.hook.core.finder.type.factory.CountConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ModifierConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ObjectsConditions
|
||||
import com.highcapable.yukihookapi.hook.factory.hasExtends
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
|
||||
import com.highcapable.yukihookapi.hook.type.defined.VagueType
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.runBlocking
|
||||
@@ -333,7 +333,7 @@ class ConstructorFinder internal constructor(override val classSet: Class<*>? =
|
||||
if (isFindSuccess) return
|
||||
errorMsg(msg = "RemedyPlan failed after ${remedyPlans.size} attempts", es = errors, isAlwaysMode = true)
|
||||
remedyPlans.clear()
|
||||
} else yLoggerW(msg = "RemedyPlan is empty, forgot it?${hookerManager.tailTag}")
|
||||
} else YLog.innerW("RemedyPlan is empty, forgot it?${hookerManager.tailTag}")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -42,7 +42,7 @@ import com.highcapable.yukihookapi.hook.core.finder.type.factory.NameConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ObjectConditions
|
||||
import com.highcapable.yukihookapi.hook.factory.current
|
||||
import com.highcapable.yukihookapi.hook.factory.hasExtends
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.runBlocking
|
||||
import java.lang.reflect.Field
|
||||
|
||||
@@ -282,7 +282,7 @@ class FieldFinder internal constructor(override val classSet: Class<*>? = null)
|
||||
if (isFindSuccess) return
|
||||
errorMsg(msg = "RemedyPlan failed after ${remedyPlans.size} attempts", es = errors, isAlwaysMode = true)
|
||||
remedyPlans.clear()
|
||||
} else yLoggerW(msg = "RemedyPlan is empty, forgot it?${hookerManager.tailTag}")
|
||||
} else YLog.innerW("RemedyPlan is empty, forgot it?${hookerManager.tailTag}")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -43,7 +43,7 @@ import com.highcapable.yukihookapi.hook.core.finder.type.factory.NameConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ObjectConditions
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ObjectsConditions
|
||||
import com.highcapable.yukihookapi.hook.factory.hasExtends
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
|
||||
import com.highcapable.yukihookapi.hook.type.defined.VagueType
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.runBlocking
|
||||
@@ -427,7 +427,7 @@ class MethodFinder internal constructor(override val classSet: Class<*>? = null)
|
||||
if (isFindSuccess) return
|
||||
errorMsg(msg = "RemedyPlan failed after ${remedyPlans.size} attempts", es = errors, isAlwaysMode = true)
|
||||
remedyPlans.clear()
|
||||
} else yLoggerW(msg = "RemedyPlan is empty, forgot it?${hookerManager.tailTag}")
|
||||
} else YLog.innerW("RemedyPlan is empty, forgot it?${hookerManager.tailTag}")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -37,22 +37,32 @@ import com.highcapable.yukihookapi.hook.core.finder.members.data.ConstructorRule
|
||||
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.factory.*
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.factory.current
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.factory.hasExtends
|
||||
import com.highcapable.yukihookapi.hook.factory.toClass
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
|
||||
import com.highcapable.yukihookapi.hook.type.defined.VagueType
|
||||
import com.highcapable.yukihookapi.hook.type.java.DalvikBaseDexClassLoader
|
||||
import com.highcapable.yukihookapi.hook.type.java.NoClassDefFoundErrorClass
|
||||
import com.highcapable.yukihookapi.hook.type.java.NoSuchFieldErrorClass
|
||||
import com.highcapable.yukihookapi.hook.type.java.NoSuchMethodErrorClass
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.*
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.conditions
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.findLastIndex
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.lastIndex
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.let
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.runOrFalse
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.takeIf
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.value
|
||||
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
|
||||
import dalvik.system.BaseDexClassLoader
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
import java.util.*
|
||||
import java.util.Enumeration
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
@@ -192,7 +202,7 @@ internal object ReflectionTool {
|
||||
fun MemberRulesData.exists(vararg type: Any?): Boolean {
|
||||
if (type.isEmpty()) return true
|
||||
for (i in type.indices) if (type[i] == UndefinedType) {
|
||||
yLoggerW(msg = "$objectName type[$i] mistake, it will be ignored in current conditions")
|
||||
YLog.innerW("$objectName type[$i] mistake, it will be ignored in current conditions")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -656,7 +666,7 @@ internal object ReflectionTool {
|
||||
addAll(declaredConstructors.toList())
|
||||
}.asSequence()
|
||||
}.onFailure {
|
||||
yLoggerW(msg = "Failed to get the declared Members in [$this] because got an exception\n$it")
|
||||
YLog.innerW("Failed to get the declared Members in [$this] because got an exception", it)
|
||||
}.getOrNull()
|
||||
|
||||
/**
|
||||
@@ -665,7 +675,7 @@ internal object ReflectionTool {
|
||||
*/
|
||||
private val Class<*>.existFields
|
||||
get() = runCatching { declaredFields.asSequence() }.onFailure {
|
||||
yLoggerW(msg = "Failed to get the declared Fields in [$this] because got an exception\n$it")
|
||||
YLog.innerW("Failed to get the declared Fields in [$this] because got an exception", it)
|
||||
}.getOrNull()
|
||||
|
||||
/**
|
||||
@@ -674,7 +684,7 @@ internal object ReflectionTool {
|
||||
*/
|
||||
private val Class<*>.existMethods
|
||||
get() = runCatching { declaredMethods.asSequence() }.onFailure {
|
||||
yLoggerW(msg = "Failed to get the declared Methods in [$this] because got an exception\n$it")
|
||||
YLog.innerW("Failed to get the declared Methods in [$this] because got an exception", it)
|
||||
}.getOrNull()
|
||||
|
||||
/**
|
||||
@@ -683,7 +693,7 @@ internal object ReflectionTool {
|
||||
*/
|
||||
private val Class<*>.existConstructors
|
||||
get() = runCatching { declaredConstructors.asSequence() }.onFailure {
|
||||
yLoggerW(msg = "Failed to get the declared Constructors in [$this] because got an exception\n$it")
|
||||
YLog.innerW("Failed to get the declared Constructors in [$this] because got an exception", it)
|
||||
}.getOrNull()
|
||||
|
||||
/**
|
||||
|
@@ -1,447 +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/2/3.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.log
|
||||
|
||||
import android.system.ErrnoException
|
||||
import android.util.Log
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
|
||||
import com.highcapable.yukihookapi.hook.factory.current
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.dumpToString
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 需要打印的日志类型
|
||||
*
|
||||
* 决定于模块与 (Xposed) 宿主环境使用的打印方式
|
||||
*/
|
||||
enum class LoggerType {
|
||||
/** 仅使用 [Log] */
|
||||
LOGD,
|
||||
|
||||
/**
|
||||
* 仅在 (Xposed) 宿主环境使用
|
||||
*
|
||||
* - 此方法已弃用 - 在之后的版本中将直接被删除
|
||||
*
|
||||
* - 请现在迁移到 [XPOSED_ENVIRONMENT]
|
||||
*/
|
||||
@Deprecated(message = "请使用新的命名方法", ReplaceWith("XPOSED_ENVIRONMENT"))
|
||||
XPOSEDBRIDGE,
|
||||
|
||||
/**
|
||||
* 仅在 (Xposed) 宿主环境使用
|
||||
*
|
||||
* - 只能在 (Xposed) 宿主环境中使用 - 模块环境将不生效
|
||||
*/
|
||||
XPOSED_ENVIRONMENT,
|
||||
|
||||
/**
|
||||
* 分区使用
|
||||
*
|
||||
* (Xposed) 宿主环境仅使用 [XPOSED_ENVIRONMENT]
|
||||
*
|
||||
* 模块环境仅使用 [LOGD]
|
||||
*/
|
||||
SCOPE,
|
||||
|
||||
/**
|
||||
* 同时使用
|
||||
*
|
||||
* (Xposed) 宿主环境使用 [LOGD] 与 [XPOSED_ENVIRONMENT]
|
||||
*
|
||||
* 模块环境仅使用 [LOGD]
|
||||
*/
|
||||
BOTH
|
||||
}
|
||||
|
||||
/**
|
||||
* 调试日志数据实现类
|
||||
* @param timestamp 当前时间戳
|
||||
* @param time 当前 UTC 时间
|
||||
* @param tag 当前标签
|
||||
* @param priority 当前优先级 - D、I、W、E
|
||||
* @param packageName 当前包名
|
||||
* @param userId 当前用户 ID
|
||||
* @param msg 当前日志内容
|
||||
* @param throwable 当前异常堆栈
|
||||
*/
|
||||
data class YukiLoggerData internal constructor(
|
||||
var timestamp: Long = 0L,
|
||||
var time: String = "",
|
||||
var tag: String = YukiHookLogger.Configs.tag,
|
||||
var priority: String = "",
|
||||
var packageName: String = "",
|
||||
var userId: Int = 0,
|
||||
var msg: String = "",
|
||||
var throwable: Throwable? = null
|
||||
) : Serializable {
|
||||
|
||||
/** 是否隐式打印 */
|
||||
internal var isImplicit = false
|
||||
|
||||
init {
|
||||
timestamp = System.currentTimeMillis()
|
||||
time = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.ROOT).format(Date(timestamp))
|
||||
packageName = if (YukiXposedModule.isXposedEnvironment) YukiXposedModule.hostProcessName else AppParasitics.currentPackageName
|
||||
userId = AppParasitics.findUserId(AppParasitics.currentPackageName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头部时间字符串
|
||||
* @return [String]
|
||||
*/
|
||||
internal val head get() = "$time ------ "
|
||||
|
||||
override fun toString(): String {
|
||||
var content = ""
|
||||
YukiHookLogger.Configs.elements.takeIf { it.isNotEmpty() }?.forEach {
|
||||
if (it == YukiHookLogger.Configs.TAG) content += "[$tag]"
|
||||
if (it == YukiHookLogger.Configs.PRIORITY) content += "[$priority]"
|
||||
if (it == YukiHookLogger.Configs.PACKAGE_NAME && isImplicit.not() && packageName.isNotBlank()) content += "[$packageName]"
|
||||
if (it == YukiHookLogger.Configs.USER_ID && isImplicit.not() && userId != 0) content += "[$userId]"
|
||||
}
|
||||
return content.takeIf { it.isNotBlank() }?.let { "$content--> $msg" } ?: msg
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调试日志实现类
|
||||
*/
|
||||
object YukiHookLogger {
|
||||
|
||||
/**
|
||||
* 当前全部已记录的日志数据
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
*/
|
||||
val inMemoryData = ArrayList<YukiLoggerData>()
|
||||
|
||||
/**
|
||||
* 获取当前日志文件内容
|
||||
*
|
||||
* 如果当前没有已记录的日志会返回空字符串
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
* @return [String]
|
||||
*/
|
||||
val contents get() = contents()
|
||||
|
||||
/**
|
||||
* 获取、格式化当前日志文件内容
|
||||
*
|
||||
* 如果当前没有已记录的日志 ([data] 为空) 会返回空字符串
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
* @param data 日志数据 - 默认为 [inMemoryData]
|
||||
* @return [String]
|
||||
*/
|
||||
fun contents(data: ArrayList<YukiLoggerData> = inMemoryData): String {
|
||||
var content = ""
|
||||
data.takeIf { it.isNotEmpty() }?.forEach {
|
||||
content += "${it.head}$it\n"
|
||||
it.throwable?.also { e ->
|
||||
content += "${it.head}Dump stack trace for \"${e.current().name}\":\n"
|
||||
content += e.dumpToString()
|
||||
}
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除全部已记录的日志
|
||||
*
|
||||
* 你也可以直接获取 [inMemoryData] 来清除
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
*/
|
||||
fun clear() = inMemoryData.clear()
|
||||
|
||||
/**
|
||||
* 保存当前日志到文件
|
||||
*
|
||||
* 若当前未开启 [Configs.isRecord] 或记录为空则不会进行任何操作
|
||||
*
|
||||
* 日志文件会追加到 [fileName] 的文件结尾 - 若文件不存在会自动创建
|
||||
*
|
||||
* - 文件读写权限取决于当前宿主、模块已获取的权限
|
||||
* @param fileName 完整文件名 - 例如 /data/data/.../files/xxx.log
|
||||
* @param data 日志数据 - 默认为 [inMemoryData]
|
||||
* @throws ErrnoException 如果目标路径不可写
|
||||
*/
|
||||
fun saveToFile(fileName: String, data: ArrayList<YukiLoggerData> = inMemoryData) {
|
||||
if (data.isNotEmpty()) File(fileName).appendText(contents(data))
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置 [YukiHookLogger]
|
||||
*/
|
||||
object Configs {
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [YukiHookAPI][...][...]--> ...
|
||||
* ```
|
||||
*/
|
||||
const val TAG = 1000
|
||||
|
||||
/**
|
||||
* 优先级
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [...][E][...]--> ...
|
||||
* ```
|
||||
*/
|
||||
const val PRIORITY = 1001
|
||||
|
||||
/**
|
||||
* 当前宿主的包名
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [...][com.demo.test][...]--> ...
|
||||
* ```
|
||||
*/
|
||||
const val PACKAGE_NAME = 1002
|
||||
|
||||
/**
|
||||
* 当前宿主的用户 ID (主用户不显示)
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [...][...][999]--> ...
|
||||
* ```
|
||||
*/
|
||||
const val USER_ID = 1003
|
||||
|
||||
/** 当前已添加的元素顺序列表数组 */
|
||||
internal var elements = arrayOf(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
|
||||
|
||||
/**
|
||||
* 是否启用调试日志的输出功能 - 默认启用
|
||||
*
|
||||
* - 关闭后将会停用 [YukiHookAPI] 对全部日志的输出
|
||||
*
|
||||
* 但是不影响当你手动调用下面这些方法输出日志
|
||||
*
|
||||
* [loggerD]、[loggerI]、[loggerW]、[loggerE]
|
||||
*
|
||||
* 当 [isEnable] 关闭后 [YukiHookAPI.Configs.isDebug] 也将同时关闭
|
||||
*/
|
||||
var isEnable = true
|
||||
|
||||
/**
|
||||
* 是否启用调试日志的记录功能 - 默认不启用
|
||||
*
|
||||
* 开启后将会在内存中记录全部可用的日志和异常堆栈
|
||||
*
|
||||
* 需要同时启用 [isEnable] 才能有效
|
||||
*
|
||||
* - 过量的日志可能会导致宿主运行缓慢或造成频繁 GC
|
||||
*
|
||||
* 开启后你可以调用 [YukiHookLogger.saveToFile] 实时保存日志到文件或使用 [YukiHookLogger.contents] 获取实时日志文件
|
||||
*/
|
||||
var isRecord = false
|
||||
|
||||
/**
|
||||
* 这是一个调试日志的全局标识
|
||||
*
|
||||
* 默认文案为 [YukiHookAPI.TAG]
|
||||
*
|
||||
* 你可以修改为你自己的文案
|
||||
*/
|
||||
var tag = YukiHookAPI.TAG
|
||||
|
||||
/**
|
||||
* 自定义调试日志对外显示的元素
|
||||
*
|
||||
* 只对日志记录和 (Xposed) 宿主环境的日志生效
|
||||
*
|
||||
* 日志元素的排列将按照你在 [item] 中设置的顺序进行显示
|
||||
*
|
||||
* 你还可以留空 [item] 以不显示除日志内容外的全部元素
|
||||
*
|
||||
* 可用的元素有:[TAG]、[PRIORITY]、[PACKAGE_NAME]、[USER_ID]
|
||||
*
|
||||
* 默认排列方式如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [TAG][PRIORITY][PACKAGE_NAME][USER_ID]--> Message
|
||||
* ```
|
||||
* @param item 自定义的元素数组
|
||||
*/
|
||||
fun elements(vararg item: Int) {
|
||||
elements = arrayOf(*item.toTypedArray())
|
||||
}
|
||||
|
||||
/** 结束方法体 */
|
||||
internal fun build() = Unit
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志 - 最终实现方法
|
||||
* @param type 日志打印的类型
|
||||
* @param data 日志数据
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
*/
|
||||
private fun baseLogger(type: LoggerType, data: YukiLoggerData, isImplicit: Boolean = false) {
|
||||
/** 是否为有效日志 */
|
||||
val isNotBlankLog = data.msg.isNotBlank() || (data.msg.isBlank() && data.throwable != null)
|
||||
|
||||
/** 打印到 [Log] */
|
||||
fun logByLogd() = when (data.priority) {
|
||||
"D" -> Log.d(data.tag, data.msg)
|
||||
"I" -> Log.i(data.tag, data.msg)
|
||||
"W" -> Log.w(data.tag, data.msg)
|
||||
"E" -> Log.e(data.tag, data.msg, data.throwable)
|
||||
else -> Log.wtf(data.tag, data.msg, data.throwable)
|
||||
}
|
||||
|
||||
/** 打印到 (Xposed) 宿主环境 */
|
||||
fun logByHooker() {
|
||||
if (isNotBlankLog) YukiHookHelper.logByHooker(data.also { it.isImplicit = isImplicit }.toString(), data.throwable)
|
||||
}
|
||||
@Suppress("DEPRECATION")
|
||||
when (type) {
|
||||
LoggerType.LOGD -> logByLogd()
|
||||
LoggerType.XPOSEDBRIDGE, LoggerType.XPOSED_ENVIRONMENT -> logByHooker()
|
||||
LoggerType.SCOPE -> if (YukiXposedModule.isXposedEnvironment) logByHooker() else logByLogd()
|
||||
LoggerType.BOTH -> {
|
||||
logByLogd()
|
||||
if (YukiXposedModule.isXposedEnvironment) logByHooker()
|
||||
}
|
||||
}
|
||||
if (isImplicit.not() && YukiHookLogger.Configs.isRecord && isNotBlankLog) YukiHookLogger.inMemoryData.add(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - D
|
||||
* @param msg 日志打印的内容
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerD(msg: String, isImplicit: Boolean = false, isDisableLog: Boolean = false) {
|
||||
if (YukiHookLogger.Configs.isEnable.not() || isDisableLog) return
|
||||
baseLogger(LoggerType.BOTH, YukiLoggerData(priority = "D", msg = msg), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - I
|
||||
* @param msg 日志打印的内容
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerI(msg: String, isImplicit: Boolean = false, isDisableLog: Boolean = false) {
|
||||
if (YukiHookLogger.Configs.isEnable.not() || isDisableLog) return
|
||||
baseLogger(LoggerType.BOTH, YukiLoggerData(priority = "I", msg = msg), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - W
|
||||
* @param msg 日志打印的内容
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerW(msg: String, isImplicit: Boolean = false, isDisableLog: Boolean = false) {
|
||||
if (YukiHookLogger.Configs.isEnable.not() || isDisableLog) return
|
||||
baseLogger(LoggerType.BOTH, YukiLoggerData(priority = "W", msg = msg), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] 向控制台和 (Xposed) 宿主环境打印日志 - E
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisableLog 禁止打印日志 - 标识后将什么也不做 - 默认为 false
|
||||
*/
|
||||
internal fun yLoggerE(msg: String = "", e: Throwable? = null, isImplicit: Boolean = false, isDisableLog: Boolean = false) {
|
||||
if (YukiHookLogger.Configs.isEnable.not() || isDisableLog) return
|
||||
baseLogger(LoggerType.BOTH, YukiLoggerData(priority = "E", msg = msg, throwable = e), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志 - D
|
||||
*
|
||||
* (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
|
||||
* @param msg 日志打印的内容
|
||||
* @param type 日志打印的类型 - 默认为 [LoggerType.BOTH]
|
||||
*/
|
||||
fun loggerD(tag: String = YukiHookLogger.Configs.tag, msg: String, type: LoggerType = LoggerType.BOTH) =
|
||||
baseLogger(type, YukiLoggerData(priority = "D", tag = tag, msg = msg))
|
||||
|
||||
/**
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志 - I
|
||||
*
|
||||
* (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
|
||||
* @param msg 日志打印的内容
|
||||
* @param type 日志打印的类型 - 默认为 [LoggerType.BOTH]
|
||||
*/
|
||||
fun loggerI(tag: String = YukiHookLogger.Configs.tag, msg: String, type: LoggerType = LoggerType.BOTH) =
|
||||
baseLogger(type, YukiLoggerData(priority = "I", tag = tag, msg = msg))
|
||||
|
||||
/**
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志 - W
|
||||
*
|
||||
* (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
|
||||
* @param msg 日志打印的内容
|
||||
* @param type 日志打印的类型 - 默认为 [LoggerType.BOTH]
|
||||
*/
|
||||
fun loggerW(tag: String = YukiHookLogger.Configs.tag, msg: String, type: LoggerType = LoggerType.BOTH) =
|
||||
baseLogger(type, YukiLoggerData(priority = "W", tag = tag, msg = msg))
|
||||
|
||||
/**
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志 - E
|
||||
*
|
||||
* (Xposed) 宿主环境中的日志打印风格为 [[tag]]「类型」--> [msg]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [YukiHookLogger.Configs.tag]
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param type 日志打印的类型 - 默认为 [LoggerType.BOTH]
|
||||
*/
|
||||
fun loggerE(tag: String = YukiHookLogger.Configs.tag, msg: String = "", e: Throwable? = null, type: LoggerType = LoggerType.BOTH) =
|
||||
baseLogger(type, YukiLoggerData(priority = "E", tag = tag, msg = msg, throwable = e))
|
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* 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/9/27.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.log
|
||||
|
||||
import android.system.ErrnoException
|
||||
import android.util.Log
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
|
||||
import com.highcapable.yukihookapi.hook.factory.current
|
||||
import com.highcapable.yukihookapi.hook.log.data.YLogData
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.dumpToString
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 全局 Log 管理类
|
||||
*/
|
||||
object YLog {
|
||||
|
||||
/**
|
||||
* 配置 [YLog]
|
||||
*/
|
||||
object Configs {
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [YukiHookAPI][...][...] ...
|
||||
* ```
|
||||
*/
|
||||
const val TAG = 1000
|
||||
|
||||
/**
|
||||
* 优先级
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [...][E][...] ...
|
||||
* ```
|
||||
*/
|
||||
const val PRIORITY = 1001
|
||||
|
||||
/**
|
||||
* 当前宿主的包名
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [...][com.demo.test][...] ...
|
||||
* ```
|
||||
*/
|
||||
const val PACKAGE_NAME = 1002
|
||||
|
||||
/**
|
||||
* 当前宿主的用户 ID (主用户不显示)
|
||||
*
|
||||
* 显示效果如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [...][...][999] ...
|
||||
* ```
|
||||
*/
|
||||
const val USER_ID = 1003
|
||||
|
||||
/**
|
||||
* 这是一个调试日志的全局标识
|
||||
*
|
||||
* 默认文案为 [YukiHookAPI.TAG]
|
||||
*
|
||||
* 你可以修改为你自己的文案
|
||||
*/
|
||||
var tag = YukiHookAPI.TAG
|
||||
|
||||
/**
|
||||
* 是否启用调试日志的输出功能 - 默认启用
|
||||
*
|
||||
* - 关闭后将会停用 [YukiHookAPI] 对全部日志的输出
|
||||
*
|
||||
* 但是不影响当你手动调用下面这些方法输出日志
|
||||
*
|
||||
* [debug]、[info]、[warn]、[error]
|
||||
*
|
||||
* 当 [isEnable] 关闭后 [YukiHookAPI.Configs.isDebug] 也将同时关闭
|
||||
*/
|
||||
var isEnable = true
|
||||
|
||||
/**
|
||||
* 是否启用调试日志的记录功能 - 默认不启用
|
||||
*
|
||||
* 开启后将会在内存中记录全部可用的日志和异常堆栈
|
||||
*
|
||||
* 需要同时启用 [isEnable] 才能有效
|
||||
*
|
||||
* - 过量的日志可能会导致宿主运行缓慢或造成频繁 GC
|
||||
*
|
||||
* 开启后你可以调用 [saveToFile] 实时保存日志到文件或使用 [contents] 获取实时日志文件
|
||||
*/
|
||||
var isRecord = false
|
||||
|
||||
/** 当前已添加的元素顺序列表数组 */
|
||||
internal var elements = arrayOf(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
|
||||
|
||||
/**
|
||||
* 自定义调试日志对外显示的元素
|
||||
*
|
||||
* 只对日志记录和 (Xposed) 宿主环境的日志生效
|
||||
*
|
||||
* 日志元素的排列将按照你在 [item] 中设置的顺序进行显示
|
||||
*
|
||||
* 你还可以留空 [item] 以不显示除日志内容外的全部元素
|
||||
*
|
||||
* 可用的元素有:[TAG]、[PRIORITY]、[PACKAGE_NAME]、[USER_ID]
|
||||
*
|
||||
* 默认排列方式如下 ↓
|
||||
*
|
||||
* ```
|
||||
* [TAG][PRIORITY][PACKAGE_NAME][USER_ID] Message
|
||||
* ```
|
||||
* @param item 自定义的元素数组
|
||||
*/
|
||||
fun elements(vararg item: Int) {
|
||||
elements = arrayOf(*item.toTypedArray())
|
||||
}
|
||||
|
||||
/** 结束方法体 */
|
||||
internal fun build() = Unit
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前全部已记录的日志数据
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
*/
|
||||
val inMemoryData = mutableListOf<YLogData>()
|
||||
|
||||
/**
|
||||
* 获取当前日志文件内容
|
||||
*
|
||||
* 如果当前没有已记录的日志会返回空字符串
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
* @return [String]
|
||||
*/
|
||||
val contents get() = contents()
|
||||
|
||||
/**
|
||||
* 获取、格式化当前日志文件内容
|
||||
*
|
||||
* 如果当前没有已记录的日志 ([data] 为空) 会返回空字符串
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
* @param data 日志数据 - 默认为 [inMemoryData]
|
||||
* @return [String]
|
||||
*/
|
||||
fun contents(data: List<YLogData> = inMemoryData): String {
|
||||
var content = ""
|
||||
data.takeIf { it.isNotEmpty() }?.forEach {
|
||||
content += "${it.head}$it\n"
|
||||
it.throwable?.also { e ->
|
||||
content += "${it.head}Dump stack trace for \"${e.current().name}\":\n"
|
||||
content += e.dumpToString()
|
||||
}
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除全部已记录的日志
|
||||
*
|
||||
* 你也可以直接获取 [inMemoryData] 来清除
|
||||
*
|
||||
* - 获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的
|
||||
*/
|
||||
fun clear() = inMemoryData.clear()
|
||||
|
||||
/**
|
||||
* 保存当前日志到文件
|
||||
*
|
||||
* 若当前未开启 [Configs.isRecord] 或记录为空则不会进行任何操作
|
||||
*
|
||||
* 日志文件会追加到 [fileName] 的文件结尾 - 若文件不存在会自动创建
|
||||
*
|
||||
* - 文件读写权限取决于当前宿主、模块已获取的权限
|
||||
* @param fileName 完整文件名 - 例如 /data/data/.../files/xxx.log
|
||||
* @param data 日志数据 - 默认为 [inMemoryData]
|
||||
* @throws ErrnoException 如果目标路径不可写
|
||||
*/
|
||||
fun saveToFile(fileName: String, data: List<YLogData> = inMemoryData) {
|
||||
if (data.isNotEmpty()) File(fileName).appendText(contents(data))
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印 Debug 级别 Log
|
||||
*
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [Configs.tag]
|
||||
* @param env 日志打印的环境 - 默认为 [EnvType.BOTH]
|
||||
*/
|
||||
fun debug(msg: String = "", e: Throwable? = null, tag: String = Configs.tag, env: EnvType = EnvType.BOTH) =
|
||||
log(env, YLogData(priority = "D", tag = tag, msg = msg, throwable = e))
|
||||
|
||||
/**
|
||||
* 打印 Info 级别 Log
|
||||
*
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [Configs.tag]
|
||||
* @param env 日志打印的环境 - 默认为 [EnvType.BOTH]
|
||||
*/
|
||||
fun info(msg: String = "", e: Throwable? = null, tag: String = Configs.tag, env: EnvType = EnvType.BOTH) =
|
||||
log(env, YLogData(priority = "I", tag = tag, msg = msg, throwable = e))
|
||||
|
||||
/**
|
||||
* 打印 Warn 级别 Log
|
||||
*
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [Configs.tag]
|
||||
* @param env 日志打印的环境 - 默认为 [EnvType.BOTH]
|
||||
*/
|
||||
fun warn(msg: String = "", e: Throwable? = null, tag: String = Configs.tag, env: EnvType = EnvType.BOTH) =
|
||||
log(env, YLogData(priority = "W", tag = tag, msg = msg, throwable = e))
|
||||
|
||||
/**
|
||||
* 打印 Error 级别 Log
|
||||
*
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param tag 日志打印的标签 - 建议和自己的模块名称设置成一样的 - 默认为 [Configs.tag]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param env 日志打印的环境 - 默认为 [EnvType.BOTH]
|
||||
*/
|
||||
fun error(msg: String = "", e: Throwable? = null, tag: String = Configs.tag, env: EnvType = EnvType.BOTH) =
|
||||
log(env, YLogData(priority = "E", tag = tag, msg = msg, throwable = e))
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] (内部) 打印 Debug 级别 Log
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisable 禁止打印日志 - 标识后将什么也不做 - 默认否
|
||||
*/
|
||||
internal fun innerD(msg: String = "", e: Throwable? = null, isImplicit: Boolean = false, isDisable: Boolean = false) {
|
||||
if (Configs.isEnable.not() || isDisable) return
|
||||
log(EnvType.BOTH, YLogData(priority = "D", msg = msg, throwable = e), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] (内部) 打印 Info 级别 Log
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisable 禁止打印日志 - 标识后将什么也不做 - 默认否
|
||||
*/
|
||||
internal fun innerI(msg: String = "", e: Throwable? = null, isImplicit: Boolean = false, isDisable: Boolean = false) {
|
||||
if (Configs.isEnable.not() || isDisable) return
|
||||
log(EnvType.BOTH, YLogData(priority = "I", msg = msg, throwable = e), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] (内部) 打印 Warn 级别 Log
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisable 禁止打印日志 - 标识后将什么也不做 - 默认否
|
||||
*/
|
||||
internal fun innerW(msg: String = "", e: Throwable? = null, isImplicit: Boolean = false, isDisable: Boolean = false) {
|
||||
if (Configs.isEnable.not() || isDisable) return
|
||||
log(EnvType.BOTH, YLogData(priority = "W", msg = msg, throwable = e), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] (内部) 打印 Error 级别 Log
|
||||
* @param msg 日志打印的内容 - 默认空 - 如果你仅想打印异常堆栈可只设置 [e]
|
||||
* @param e 可填入异常堆栈信息 - 将自动完整打印到控制台
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
* @param isDisable 禁止打印日志 - 标识后将什么也不做 - 默认否
|
||||
*/
|
||||
internal fun innerE(msg: String = "", e: Throwable? = null, isImplicit: Boolean = false, isDisable: Boolean = false) {
|
||||
if (Configs.isEnable.not() || isDisable) return
|
||||
log(EnvType.BOTH, YLogData(priority = "E", msg = msg, throwable = e), isImplicit)
|
||||
}
|
||||
|
||||
/**
|
||||
* 向控制台和 (Xposed) 宿主环境打印日志 - 最终实现方法
|
||||
* @param env 日志打印的环境
|
||||
* @param data 日志数据
|
||||
* @param isImplicit 是否隐式打印 - 不会记录 - 也不会显示包名和用户 ID
|
||||
*/
|
||||
private fun log(env: EnvType, data: YLogData, isImplicit: Boolean = false) {
|
||||
/** 是否为有效日志 */
|
||||
val isNotBlankLog = data.msg.isNotBlank() || (data.msg.isBlank() && data.throwable != null)
|
||||
|
||||
/** 打印到 [Log] */
|
||||
fun logByLogd() = when (data.priority) {
|
||||
"D" -> Log.d(data.tag, data.msg)
|
||||
"I" -> Log.i(data.tag, data.msg)
|
||||
"W" -> Log.w(data.tag, data.msg)
|
||||
"E" -> Log.e(data.tag, data.msg, data.throwable)
|
||||
else -> Log.wtf(data.tag, data.msg, data.throwable)
|
||||
}
|
||||
|
||||
/** 打印到 (Xposed) 宿主环境 */
|
||||
fun logByHooker() {
|
||||
if (isNotBlankLog) YukiHookHelper.logByHooker(data.also { it.isImplicit = isImplicit }.toString(), data.throwable)
|
||||
}
|
||||
when (env) {
|
||||
EnvType.LOGD -> logByLogd()
|
||||
EnvType.XPOSED_ENVIRONMENT -> logByHooker()
|
||||
EnvType.SCOPE -> if (YukiXposedModule.isXposedEnvironment) logByHooker() else logByLogd()
|
||||
EnvType.BOTH -> {
|
||||
logByLogd()
|
||||
if (YukiXposedModule.isXposedEnvironment) logByHooker()
|
||||
}
|
||||
}
|
||||
if (isImplicit.not() && Configs.isRecord && isNotBlankLog) inMemoryData.add(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 需要打印的日志环境类型
|
||||
*
|
||||
* 决定于模块与 (Xposed) 宿主环境使用的打印方式
|
||||
*/
|
||||
enum class EnvType {
|
||||
/** 仅使用 [Log] */
|
||||
LOGD,
|
||||
|
||||
/**
|
||||
* 仅在 (Xposed) 宿主环境使用
|
||||
*
|
||||
* - 只能在 (Xposed) 宿主环境中使用 - 模块环境将不生效
|
||||
*/
|
||||
XPOSED_ENVIRONMENT,
|
||||
|
||||
/**
|
||||
* 分区使用
|
||||
*
|
||||
* (Xposed) 宿主环境仅使用 [XPOSED_ENVIRONMENT]
|
||||
*
|
||||
* 模块环境仅使用 [LOGD]
|
||||
*/
|
||||
SCOPE,
|
||||
|
||||
/**
|
||||
* 同时使用
|
||||
*
|
||||
* (Xposed) 宿主环境使用 [LOGD] 与 [XPOSED_ENVIRONMENT]
|
||||
*
|
||||
* 模块环境仅使用 [LOGD]
|
||||
*/
|
||||
BOTH
|
||||
}
|
||||
}
|
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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/2/3.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate", "DeprecatedCallableAddReplaceWith", "DEPRECATION")
|
||||
|
||||
package com.highcapable.yukihookapi.hook.log
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
enum class LoggerType {
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
LOGD,
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
XPOSEDBRIDGE,
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
XPOSED_ENVIRONMENT,
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
SCOPE,
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
BOTH
|
||||
}
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
data class YukiLoggerData @Deprecated(message = "请迁移到 YLog") internal constructor(
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var timestamp: Long = 0L,
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var time: String = "",
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var tag: String = YukiHookLogger.Configs.tag,
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var priority: String = "",
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var packageName: String = "",
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var userId: Int = 0,
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var msg: String = "",
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var throwable: Throwable? = null
|
||||
) : Serializable
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
object YukiHookLogger {
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
val inMemoryData = ArrayList<YukiLoggerData>()
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
val contents get() = ""
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
fun contents(data: ArrayList<YukiLoggerData> = inMemoryData) = ""
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
fun clear() = Unit
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
fun saveToFile(fileName: String, data: ArrayList<YukiLoggerData> = inMemoryData) = Unit
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
object Configs {
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
const val TAG = ""
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
const val PRIORITY = -1
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
const val PACKAGE_NAME = -1
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
const val USER_ID = -1
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var isEnable = true
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var isRecord = false
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
var tag = ""
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog")
|
||||
fun elements(vararg item: Int) = Unit
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog", ReplaceWith("YLog.debug(msg = msg, tag = tag)"))
|
||||
fun loggerD(tag: String = YLog.Configs.tag, msg: String, type: LoggerType = LoggerType.BOTH) {
|
||||
YLog.debug(msg, tag = tag, env = when (type) {
|
||||
LoggerType.BOTH -> YLog.EnvType.BOTH
|
||||
LoggerType.LOGD -> YLog.EnvType.LOGD
|
||||
LoggerType.SCOPE -> YLog.EnvType.SCOPE
|
||||
LoggerType.XPOSEDBRIDGE, LoggerType.XPOSED_ENVIRONMENT -> YLog.EnvType.XPOSED_ENVIRONMENT
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog", ReplaceWith("YLog.info(msg = msg, tag = tag)"))
|
||||
fun loggerI(tag: String = YLog.Configs.tag, msg: String, type: LoggerType = LoggerType.BOTH) {
|
||||
YLog.info(msg, tag = tag, env = when (type) {
|
||||
LoggerType.BOTH -> YLog.EnvType.BOTH
|
||||
LoggerType.LOGD -> YLog.EnvType.LOGD
|
||||
LoggerType.SCOPE -> YLog.EnvType.SCOPE
|
||||
LoggerType.XPOSEDBRIDGE, LoggerType.XPOSED_ENVIRONMENT -> YLog.EnvType.XPOSED_ENVIRONMENT
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog", ReplaceWith("YLog.warn(msg = msg, tag = tag)"))
|
||||
fun loggerW(tag: String = YLog.Configs.tag, msg: String, type: LoggerType = LoggerType.BOTH) {
|
||||
YLog.warn(msg, tag = tag, env = when (type) {
|
||||
LoggerType.BOTH -> YLog.EnvType.BOTH
|
||||
LoggerType.LOGD -> YLog.EnvType.LOGD
|
||||
LoggerType.SCOPE -> YLog.EnvType.SCOPE
|
||||
LoggerType.XPOSEDBRIDGE, LoggerType.XPOSED_ENVIRONMENT -> YLog.EnvType.XPOSED_ENVIRONMENT
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* - LoggerFactory 已被弃用 - 请迁移到 [YLog]
|
||||
*/
|
||||
@Deprecated(message = "请迁移到 YLog", ReplaceWith("YLog.error(msg = msg, e = e, tag = tag)"))
|
||||
fun loggerE(tag: String = YLog.Configs.tag, msg: String = "", e: Throwable? = null, type: LoggerType = LoggerType.BOTH) {
|
||||
YLog.error(msg, e = e, tag = tag, env = when (type) {
|
||||
LoggerType.BOTH -> YLog.EnvType.BOTH
|
||||
LoggerType.LOGD -> YLog.EnvType.LOGD
|
||||
LoggerType.SCOPE -> YLog.EnvType.SCOPE
|
||||
LoggerType.XPOSEDBRIDGE, LoggerType.XPOSED_ENVIRONMENT -> YLog.EnvType.XPOSED_ENVIRONMENT
|
||||
})
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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/9/27.
|
||||
*/
|
||||
package com.highcapable.yukihookapi.hook.log.data
|
||||
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
|
||||
import java.io.Serializable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 调试日志数据实现类
|
||||
* @param timestamp 当前时间戳
|
||||
* @param time 当前 UTC 时间
|
||||
* @param tag 当前标签
|
||||
* @param priority 当前优先级 - D、I、W、E
|
||||
* @param packageName 当前包名
|
||||
* @param userId 当前用户 ID
|
||||
* @param msg 当前日志内容
|
||||
* @param throwable 当前异常堆栈
|
||||
*/
|
||||
data class YLogData internal constructor(
|
||||
var timestamp: Long = 0L,
|
||||
var time: String = "",
|
||||
var tag: String = YLog.Configs.tag,
|
||||
var priority: String = "",
|
||||
var packageName: String = "",
|
||||
var userId: Int = 0,
|
||||
var msg: String = "",
|
||||
var throwable: Throwable? = null
|
||||
) : Serializable {
|
||||
|
||||
/** 是否隐式打印 */
|
||||
internal var isImplicit = false
|
||||
|
||||
init {
|
||||
timestamp = System.currentTimeMillis()
|
||||
time = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.ROOT).format(Date(timestamp))
|
||||
packageName = if (YukiXposedModule.isXposedEnvironment) YukiXposedModule.hostProcessName else AppParasitics.currentPackageName
|
||||
userId = AppParasitics.findUserId(AppParasitics.currentPackageName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头部时间字符串
|
||||
* @return [String]
|
||||
*/
|
||||
internal val head get() = "$time ------ "
|
||||
|
||||
override fun toString(): String {
|
||||
var content = ""
|
||||
YLog.Configs.elements.takeIf { it.isNotEmpty() }?.forEach {
|
||||
if (it == YLog.Configs.TAG) content += "[$tag]"
|
||||
if (it == YLog.Configs.PRIORITY) content += "[$priority]"
|
||||
if (it == YLog.Configs.PACKAGE_NAME && isImplicit.not() && packageName.isNotBlank()) content += "[$packageName]"
|
||||
if (it == YLog.Configs.USER_ID && isImplicit.not() && userId != 0) content += "[$userId]"
|
||||
}; return content.takeIf { it.isNotBlank() }?.let { "$content $msg" } ?: msg
|
||||
}
|
||||
}
|
@@ -36,7 +36,7 @@ import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreator.MemberHookCre
|
||||
import com.highcapable.yukihookapi.hook.core.api.helper.YukiHookHelper
|
||||
import com.highcapable.yukihookapi.hook.core.api.proxy.YukiHookCallback
|
||||
import com.highcapable.yukihookapi.hook.factory.classOf
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
@@ -179,7 +179,7 @@ class HookParam internal constructor(
|
||||
*/
|
||||
fun Throwable.throwToApp() {
|
||||
param?.throwable = this
|
||||
yLoggerE(msg = message ?: "", e = this)
|
||||
YLog.innerE(message ?: "", this)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -47,7 +47,7 @@ import com.highcapable.yukihookapi.hook.core.finder.classes.DexClassFinder
|
||||
import com.highcapable.yukihookapi.hook.core.finder.tools.ReflectionTool
|
||||
import com.highcapable.yukihookapi.hook.core.finder.type.factory.ClassConditions
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.value
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||
@@ -422,7 +422,7 @@ open class PackageParam internal constructor(internal var wrapper: PackageParamW
|
||||
if (it.packageName.isNotBlank() && it.type != HookEntryType.ZYGOTE)
|
||||
if (it.packageName == wrapper?.packageName)
|
||||
hooker.assignInstance(packageParam = this)
|
||||
else yLoggerW(
|
||||
else YLog.innerW(
|
||||
msg = "This Hooker \"${hooker::class.java.name}\" is singleton or reused, " +
|
||||
"but the current process has multiple package name \"${wrapper?.packageName}\", " +
|
||||
"the original is \"${it.packageName}\"\n" +
|
||||
|
@@ -34,7 +34,7 @@ import android.util.ArrayMap
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.core.api.compat.HookApiCategoryHelper
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.proxy.IYukiXposedModuleLifecycle
|
||||
@@ -220,7 +220,7 @@ internal object YukiXposedModule : IYukiXposedModuleLifecycle {
|
||||
AppParasitics.hookModuleAppRelated(it.appClassLoader, it.type)
|
||||
if (it.type == HookEntryType.PACKAGE) AppParasitics.registerToAppLifecycle(it.packageName)
|
||||
if (it.type == HookEntryType.RESOURCES) isSupportResourcesHook = true
|
||||
}.onFailure { yLoggerE(msg = "An exception occurred in the Hooking Process of YukiHookAPI", e = it) }
|
||||
}.onFailure { YLog.innerE("An exception occurred in the Hooking Process of YukiHookAPI", it) }
|
||||
}
|
||||
}
|
||||
}
|
@@ -30,7 +30,7 @@
|
||||
package com.highcapable.yukihookapi.hook.xposed.bridge.caller
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
|
||||
@@ -77,9 +77,9 @@ internal object YukiXposedModuleCaller {
|
||||
) = YukiXposedModule.onPackageLoaded(type, packageName, processName, appClassLoader, appInfo, appResources)
|
||||
|
||||
/**
|
||||
* 打印内部 E 级别的日志
|
||||
* 打印 Error 级别 Log
|
||||
* @param msg 日志打印的内容
|
||||
* @param e 异常堆栈信息 - 默认空
|
||||
*/
|
||||
internal fun internalLoggerE(msg: String, e: Throwable? = null) = yLoggerE(msg = msg, e = e)
|
||||
internal fun callLogError(msg: String, e: Throwable? = null) = YLog.innerE(msg, e)
|
||||
}
|
@@ -33,7 +33,7 @@ import android.content.res.Resources
|
||||
import android.content.res.XResources
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources.LayoutInflatedParam
|
||||
import de.robv.android.xposed.callbacks.XC_LayoutInflated
|
||||
|
||||
@@ -153,7 +153,7 @@ class YukiResources private constructor(private val baseInstance: XResources) :
|
||||
private inline fun runIfAnyErrors(name: String, initiate: () -> Unit) {
|
||||
runCatching {
|
||||
initiate()
|
||||
}.onFailure { yLoggerE(msg = "Failed to execute method \"$name\", maybe your Hook Framework not support Resources Hook", it) }
|
||||
}.onFailure { YLog.innerE("Failed to execute method \"$name\", maybe your Hook Framework not support Resources Hook", it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -45,10 +45,8 @@ import android.os.Parcelable
|
||||
import android.os.TransactionTooLargeException
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
|
||||
import com.highcapable.yukihookapi.hook.log.YukiHookLogger
|
||||
import com.highcapable.yukihookapi.hook.log.YukiLoggerData
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.log.data.YLogData
|
||||
import com.highcapable.yukihookapi.hook.utils.factory.RandomSeed
|
||||
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||
@@ -92,7 +90,7 @@ class YukiHookDataChannel private constructor() {
|
||||
private const val GET_YUKI_LOGGER_INMEMORY_DATA = "yuki_logger_inmemory_data_get"
|
||||
|
||||
/** 调试日志数据结果标签 */
|
||||
private val RESULT_YUKI_LOGGER_INMEMORY_DATA = ChannelData<ArrayList<YukiLoggerData>>("yuki_logger_inmemory_data_result")
|
||||
private val RESULT_YUKI_LOGGER_INMEMORY_DATA = ChannelData<List<YLogData>>("yuki_logger_inmemory_data_result")
|
||||
|
||||
/** 仅监听结果键值 */
|
||||
private const val VALUE_WAIT_FOR_LISTENER = "wait_for_listener_value"
|
||||
@@ -167,7 +165,7 @@ class YukiHookDataChannel private constructor() {
|
||||
destroyedCallbacks.takeIf { it.isNotEmpty() }?.forEach { remove(it) }
|
||||
}
|
||||
}
|
||||
}.onFailure { yLoggerE(msg = "Received action \"$action\" failed", e = it) }
|
||||
}.onFailure { YLog.innerE("Received action \"$action\" failed", it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +189,7 @@ class YukiHookDataChannel private constructor() {
|
||||
context is Application || isXposedEnvironment || (((context ?: receiverContext)
|
||||
?.getSystemService(ACTIVITY_SERVICE) as? ActivityManager?)
|
||||
?.getRunningTasks(9999)?.filter { context?.javaClass?.name == it?.topActivity?.className }?.size ?: 0) > 0
|
||||
}.getOrNull() ?: yLoggerW(msg = "Couldn't got current Activity status because a SecurityException blocked it").let { false }
|
||||
}.getOrNull() ?: YLog.innerW("Couldn't got current Activity status because a SecurityException blocked it").let { false }
|
||||
|
||||
/**
|
||||
* 获取宿主广播 Action 名称
|
||||
@@ -237,7 +235,7 @@ class YukiHookDataChannel private constructor() {
|
||||
}
|
||||
/** 注册监听模块与宿主之间的调试日志数据 */
|
||||
wait<String>(GET_YUKI_LOGGER_INMEMORY_DATA) { fromPackageName ->
|
||||
nameSpace(context, fromPackageName).put(RESULT_YUKI_LOGGER_INMEMORY_DATA, YukiHookLogger.inMemoryData)
|
||||
nameSpace(context, fromPackageName).put(RESULT_YUKI_LOGGER_INMEMORY_DATA, YLog.inMemoryData)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -439,17 +437,17 @@ class YukiHookDataChannel private constructor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块与宿主之间的 [ArrayList]<[YukiLoggerData]> 数据
|
||||
* 获取模块与宿主之间的 [List]<[YLogData]> 数据
|
||||
*
|
||||
* 由于模块与宿主处于不同的进程 - 我们可以使用数据通讯桥访问各自的调试日志数据
|
||||
*
|
||||
* - 模块与宿主必须启用 [YukiHookLogger.Configs.isRecord] 才能获取到调试日志数据
|
||||
* - 模块与宿主必须启用 [YLog.Configs.isRecord] 才能获取到调试日志数据
|
||||
*
|
||||
* - 由于 Android 限制了数据传输大小的最大值 - 如果调试日志过多将会自动进行分段发送 - 数据越大速度越慢
|
||||
* @param priority 响应优先级 - 默认不设置
|
||||
* @param result 回调 [ArrayList]<[YukiLoggerData]>
|
||||
* @param result 回调 [List]<[YLogData]>
|
||||
*/
|
||||
fun obtainLoggerInMemoryData(priority: ChannelPriority? = null, result: (ArrayList<YukiLoggerData>) -> Unit) {
|
||||
fun obtainLoggerInMemoryData(priority: ChannelPriority? = null, result: (List<YLogData>) -> Unit) {
|
||||
wait(RESULT_YUKI_LOGGER_INMEMORY_DATA, priority) { result(it) }
|
||||
put(GET_YUKI_LOGGER_INMEMORY_DATA, packageName)
|
||||
}
|
||||
@@ -565,10 +563,10 @@ class YukiHookDataChannel private constructor() {
|
||||
segmentsTempData.remove(wrapper.wrapperId)
|
||||
}
|
||||
}
|
||||
else -> yLoggerE(msg = "Unsupported segments data key of \"${wrapper.instance.key}\"'s type")
|
||||
else -> YLog.innerE("Unsupported segments data key of \"${wrapper.instance.key}\"'s type")
|
||||
}
|
||||
}.onFailure {
|
||||
yLoggerE(msg = "YukiHookDataChannel cannot merge this segments data key of \"${wrapper.instance.key}\"", e = it)
|
||||
YLog.innerE("YukiHookDataChannel cannot merge this segments data key of \"${wrapper.instance.key}\"", it)
|
||||
} else wrapper.instance.value?.let { e -> result(e) }
|
||||
}
|
||||
|
||||
@@ -583,7 +581,7 @@ class YukiHookDataChannel private constructor() {
|
||||
|
||||
/** 当前需要发送的数据字节大小 */
|
||||
val dataByteSize = wrapper.instance.calDataByteSize()
|
||||
if (dataByteSize < 0 && isAllowSendTooLargeData.not()) return yLoggerE(
|
||||
if (dataByteSize < 0 && isAllowSendTooLargeData.not()) return YLog.innerE(
|
||||
msg = "YukiHookDataChannel cannot calculate the byte size of the data key of \"${wrapper.instance.key}\" to be sent, " +
|
||||
"so this data cannot be sent\n" +
|
||||
"If you want to lift this restriction, use the allowSendTooLargeData function when calling, " +
|
||||
@@ -595,7 +593,7 @@ class YukiHookDataChannel private constructor() {
|
||||
* @param size 分段总大小 (长度)
|
||||
*/
|
||||
fun loggerForTooLargeData(name: String, size: Int) {
|
||||
if (YukiHookAPI.Configs.isDebug) yLoggerW(
|
||||
if (YukiHookAPI.Configs.isDebug) YLog.innerW(
|
||||
msg = "This data key of \"${wrapper.instance.key}\" type $name is too large (total ${dataByteSize / 1024f} KB, " +
|
||||
"limit ${receiverDataMaxByteSize / 1024f} KB), will be segmented to $size piece to send"
|
||||
)
|
||||
@@ -605,7 +603,7 @@ class YukiHookDataChannel private constructor() {
|
||||
* 如果数据过大且无法分段打印错误信息
|
||||
* @param suggestionMessage 建议内容 - 默认空
|
||||
*/
|
||||
fun loggerForUnprocessableData(suggestionMessage: String = "") = yLoggerE(
|
||||
fun loggerForUnprocessableData(suggestionMessage: String = "") = YLog.innerE(
|
||||
msg = "YukiHookDataChannel cannot send this data key of \"${wrapper.instance.key}\" type ${wrapper.instance.value?.javaClass}, " +
|
||||
"because it is too large (total ${dataByteSize / 1024f} KB, " +
|
||||
"limit ${receiverDataMaxByteSize / 1024f} KB) and cannot be segmented\n" +
|
||||
@@ -710,7 +708,7 @@ class YukiHookDataChannel private constructor() {
|
||||
if (packageName != AppParasitics.SYSTEM_FRAMEWORK_NAME)
|
||||
setPackage(if (isXposedEnvironment) YukiXposedModule.modulePackageName else packageName)
|
||||
putExtra(wrapper.instance.key + keyNonRepeatName, wrapper)
|
||||
}) ?: yLoggerE(msg = "Failed to sendBroadcast like \"${wrapper.instance.key}\", because got null context in \"$packageName\"")
|
||||
}) ?: YLog.innerE("Failed to sendBroadcast like \"${wrapper.instance.key}\", because got null context in \"$packageName\"")
|
||||
}
|
||||
}
|
||||
}
|
@@ -63,8 +63,7 @@ import com.highcapable.yukihookapi.hook.factory.hasMethod
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.factory.toClass
|
||||
import com.highcapable.yukihookapi.hook.factory.toClassOrNull
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.type.android.ActivityManagerClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.ActivityManagerNativeClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.ActivityTaskManagerClass
|
||||
@@ -199,7 +198,7 @@ internal object AppParasitics {
|
||||
*/
|
||||
internal fun hookClassLoader(loader: ClassLoader?, result: (Class<*>) -> Unit) {
|
||||
if (loader == null) return
|
||||
if (YukiXposedModule.isXposedEnvironment.not()) return yLoggerW(msg = "You can only use hook ClassLoader method in Xposed Environment")
|
||||
if (YukiXposedModule.isXposedEnvironment.not()) return YLog.innerW("You can only use hook ClassLoader method in Xposed Environment")
|
||||
classLoaderCallbacks[loader.hashCode()] = result
|
||||
if (isClassLoaderHooked) return
|
||||
runCatching {
|
||||
@@ -211,7 +210,7 @@ internal object AppParasitics {
|
||||
}
|
||||
})
|
||||
isClassLoaderHooked = true
|
||||
}.onFailure { yLoggerW(msg = "Try to hook ClassLoader failed: $it") }
|
||||
}.onFailure { YLog.innerW("Try to hook ClassLoader failed: $it") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,7 +269,7 @@ internal object AppParasitics {
|
||||
*/
|
||||
fun YukiHookCallback.Param.throwToAppOrLogger(throwable: Throwable) {
|
||||
if (AppLifecycleCallback.isOnFailureThrowToApp) this.throwable = throwable
|
||||
else yLoggerE(msg = "An exception occurred during AppLifecycle event", e = throwable)
|
||||
else YLog.innerE("An exception occurred during AppLifecycle event", e = throwable)
|
||||
}
|
||||
/** Hook [Application] 装载方法 */
|
||||
runCatching {
|
||||
@@ -378,14 +377,14 @@ internal object AppParasitics {
|
||||
internal fun injectModuleAppResources(hostResources: Resources) {
|
||||
if (YukiXposedModule.isXposedEnvironment) runCatching {
|
||||
if (currentPackageName == YukiXposedModule.modulePackageName)
|
||||
return yLoggerE(msg = "You cannot inject module resources into yourself")
|
||||
return YLog.innerE("You cannot inject module resources into yourself")
|
||||
hostResources.assets.current(ignored = true).method {
|
||||
name = "addAssetPath"
|
||||
param(StringClass)
|
||||
}.call(YukiXposedModule.moduleAppFilePath)
|
||||
}.onFailure {
|
||||
yLoggerE(msg = "Failed to inject module resources into [$hostResources]", e = it)
|
||||
} else yLoggerW(msg = "You can only inject module resources in Xposed Environment")
|
||||
YLog.innerE("Failed to inject module resources into [$hostResources]", it)
|
||||
} else YLog.innerW("You can only inject module resources in Xposed Environment")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,9 +395,9 @@ internal object AppParasitics {
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
internal fun registerModuleAppActivities(context: Context, proxy: Any?) {
|
||||
if (isActivityProxyRegistered) return
|
||||
if (YukiXposedModule.isXposedEnvironment.not()) return yLoggerW(msg = "You can only register Activity Proxy in Xposed Environment")
|
||||
if (context.packageName == YukiXposedModule.modulePackageName) return yLoggerE(msg = "You cannot register Activity Proxy into yourself")
|
||||
if (Build.VERSION.SDK_INT < 24) return yLoggerE(msg = "Activity Proxy only support for Android 7.0 (API 24) or higher")
|
||||
if (YukiXposedModule.isXposedEnvironment.not()) return YLog.innerW("You can only register Activity Proxy in Xposed Environment")
|
||||
if (context.packageName == YukiXposedModule.modulePackageName) return YLog.innerE("You cannot register Activity Proxy into yourself")
|
||||
if (Build.VERSION.SDK_INT < 24) return YLog.innerE("Activity Proxy only support for Android 7.0 (API 24) or higher")
|
||||
runCatching {
|
||||
ActivityProxyConfig.apply {
|
||||
proxyIntentName = "${YukiXposedModule.modulePackageName}.ACTIVITY_PROXY_INTENT"
|
||||
@@ -444,7 +443,7 @@ internal object AppParasitics {
|
||||
}
|
||||
}
|
||||
isActivityProxyRegistered = true
|
||||
}.onFailure { yLoggerE(msg = "Activity Proxy initialization failed because got an Exception", e = it) }
|
||||
}.onFailure { YLog.innerE("Activity Proxy initialization failed because got an Exception", it) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -39,7 +39,7 @@ import android.os.Message
|
||||
import com.highcapable.yukihookapi.hook.factory.current
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.type.android.ActivityThreadClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.ClientTransactionClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.IBinderClass
|
||||
@@ -76,7 +76,7 @@ internal object HandlerDelegateCaller {
|
||||
set(intent.getParcelableExtra(ActivityProxyConfig.proxyIntentName))
|
||||
}
|
||||
}
|
||||
}.onFailure { yLoggerE(msg = "Activity Proxy got an Exception in msg.what [$LAUNCH_ACTIVITY]", e = it) }
|
||||
}.onFailure { YLog.innerE("Activity Proxy got an Exception in msg.what [$LAUNCH_ACTIVITY]", it) }
|
||||
EXECUTE_TRANSACTION -> msg.obj?.runCatching client@{
|
||||
ClientTransactionClass.method { name = "getCallbacks" }.ignored().get(this).list<Any?>().takeIf { it.isNotEmpty() }
|
||||
?.forEach { item ->
|
||||
@@ -100,7 +100,7 @@ internal object HandlerDelegateCaller {
|
||||
}
|
||||
}
|
||||
}
|
||||
}?.onFailure { yLoggerE(msg = "Activity Proxy got an Exception in msg.what [$EXECUTE_TRANSACTION]", e = it) }
|
||||
}?.onFailure { YLog.innerE("Activity Proxy got an Exception in msg.what [$EXECUTE_TRANSACTION]", it) }
|
||||
}
|
||||
return baseInstance?.handleMessage(msg) ?: false
|
||||
}
|
||||
|
@@ -37,8 +37,7 @@ import android.content.SharedPreferences
|
||||
import android.util.ArrayMap
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerE
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
import com.highcapable.yukihookapi.hook.log.YLog
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
|
||||
import com.highcapable.yukihookapi.hook.xposed.bridge.delegate.XSharedPreferencesDelegate
|
||||
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics
|
||||
@@ -150,7 +149,7 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
||||
makeWorldReadable()
|
||||
reload()
|
||||
}
|
||||
}.onFailure { yLoggerE(msg = it.message ?: "Operating system not supported", e = it) }.getOrNull()
|
||||
}.onFailure { YLog.innerE(it.message ?: "Operating system not supported", it) }.getOrNull()
|
||||
?: error("Cannot load the XSharedPreferences, maybe is your Hook Framework not support it")
|
||||
}
|
||||
|
||||
@@ -680,7 +679,7 @@ class YukiHookPrefsBridge private constructor(private var context: Context? = nu
|
||||
*/
|
||||
private inline fun specifiedScope(callback: () -> Unit): Editor {
|
||||
if (isXposedEnvironment.not() || isUsingNativeStorage) callback()
|
||||
else yLoggerW(msg = "YukiHookPrefsBridge.Editor not allowed in Xposed Environment")
|
||||
else YLog.innerW("YukiHookPrefsBridge.Editor not allowed in Xposed Environment")
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
@@ -30,7 +30,6 @@
|
||||
package com.highcapable.yukihookapi.hook.xposed.proxy
|
||||
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.log.yLoggerW
|
||||
|
||||
/**
|
||||
* [YukiHookAPI] 的 Xposed 装载 API 调用接口
|
||||
@@ -48,7 +47,7 @@ interface YukiHookXposedInitProxy {
|
||||
* - 请将接口迁移到 [IYukiHookXposedInit]
|
||||
*/
|
||||
@Deprecated(message = "请将接口迁移到 IYukiHookXposedInit", level = DeprecationLevel.ERROR)
|
||||
fun onInit() = yLoggerW(msg = "YukiHookXposedInitProxy was deprecated")
|
||||
fun onInit() = Unit
|
||||
|
||||
/**
|
||||
* - 此方法已过时
|
||||
@@ -56,5 +55,5 @@ interface YukiHookXposedInitProxy {
|
||||
* - 请将接口迁移到 [IYukiHookXposedInit]
|
||||
*/
|
||||
@Deprecated(message = "请将接口迁移到 IYukiHookXposedInit", level = DeprecationLevel.ERROR)
|
||||
fun onHook() = yLoggerW(msg = "YukiHookXposedInitProxy was deprecated")
|
||||
fun onHook() = Unit
|
||||
}
|
@@ -346,12 +346,12 @@ fun GenerateData.sources() = mapOf(
|
||||
hookEntry.onXposedEvent()
|
||||
hookEntry.onInit()
|
||||
if (${ExternalCallerName.YukiXposedModuleCaller.second}.isXposedCallbackSetUp) {
|
||||
${ExternalCallerName.YukiXposedModuleCaller.second}.internalLoggerE("You cannot load a hooker in \"onInit\" or \"onXposedEvent\" method! Aborted")
|
||||
${ExternalCallerName.YukiXposedModuleCaller.second}.callLogError("You cannot load a hooker in \"onInit\" or \"onXposedEvent\" method! Aborted")
|
||||
return
|
||||
}
|
||||
hookEntry.onHook()
|
||||
${ExternalCallerName.YukiXposedModuleCaller.second}.callOnFinishLoadModule()
|
||||
}.onFailure { ${ExternalCallerName.YukiXposedModuleCaller.second}.internalLoggerE("YukiHookAPI try to load hook entry class failed", it) }
|
||||
}.onFailure { ${ExternalCallerName.YukiXposedModuleCaller.second}.callLogError("YukiHookAPI try to load hook entry class failed", it) }
|
||||
${ExternalCallerName.YukiXposedModuleCaller.second}.callOnPackageLoaded(
|
||||
type = when {
|
||||
isZygoteLoaded -> HookEntryType.ZYGOTE
|
||||
@@ -373,7 +373,7 @@ fun GenerateData.sources() = mapOf(
|
||||
${ExternalCallerName.YukiXposedModuleCaller.second}.callOnStartLoadModule(modulePackageName, sparam.modulePath)
|
||||
callOnXposedModuleLoaded(isZygoteLoaded = true)
|
||||
isZygoteCalled = true
|
||||
}.onFailure { ${ExternalCallerName.YukiXposedModuleCaller.second}.internalLoggerE("An exception occurred when YukiHookAPI loading Xposed Module", it) }
|
||||
}.onFailure { ${ExternalCallerName.YukiXposedModuleCaller.second}.callLogError("An exception occurred when YukiHookAPI loading Xposed Module", it) }
|
||||
}
|
||||
|
||||
fun callHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
|
||||
|
Reference in New Issue
Block a user