refactor: migrate to YukiHookAPI new usage

This commit is contained in:
2023-10-07 21:15:15 +08:00
parent 52367b5c41
commit d215440e83
6 changed files with 110 additions and 139 deletions

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools">
package="com.fankes.apperrorstracking">
<uses-permission <uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES" android:name="android.permission.QUERY_ALL_PACKAGES"

View File

@@ -31,7 +31,7 @@ import com.fankes.apperrorstracking.utils.factory.appVersionCodeOf
import com.fankes.apperrorstracking.utils.factory.appVersionNameOf import com.fankes.apperrorstracking.utils.factory.appVersionNameOf
import com.fankes.apperrorstracking.utils.factory.toEntityOrNull import com.fankes.apperrorstracking.utils.factory.toEntityOrNull
import com.fankes.apperrorstracking.utils.factory.toJsonOrNull import com.fankes.apperrorstracking.utils.factory.toJsonOrNull
import com.highcapable.yukihookapi.hook.log.loggerE import com.highcapable.yukihookapi.hook.log.YLog
import java.io.File import java.io.File
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
@@ -76,7 +76,7 @@ object AppErrorsRecordData {
runCatching { runCatching {
errorsInfoDataFolder.also { if (it.exists().not() || it.isFile) it.apply { delete(); mkdirs() } } errorsInfoDataFolder.also { if (it.exists().not() || it.isFile) it.apply { delete(); mkdirs() } }
}.onFailure { }.onFailure {
loggerE(msg = "Can't create directory \"$FOLDER_PATH\", there will be problems with the app errors records function", e = it) YLog.error("Can't create directory \"$FOLDER_PATH\", there will be problems with the app errors records function", it)
} }
} }

View File

@@ -26,7 +26,7 @@ package com.fankes.apperrorstracking.data
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import com.highcapable.yukihookapi.hook.factory.prefs import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.log.loggerW import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.param.PackageParam import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
@@ -91,7 +91,7 @@ object ConfigData {
internal fun putStringSet(key: String, value: Set<String>) { internal fun putStringSet(key: String, value: Set<String>) {
when (instance) { when (instance) {
is Context -> (instance as Context).prefs().edit { putStringSet(key, value) } is Context -> (instance as Context).prefs().edit { putStringSet(key, value) }
is PackageParam -> loggerW(msg = "Not support for this method") is PackageParam -> YLog.warn("Not support for this method")
else -> error("Unknown type for put prefs data") else -> error("Unknown type for put prefs data")
} }
} }
@@ -115,7 +115,7 @@ object ConfigData {
internal fun putInt(data: PrefsData<Int>, value: Int) { internal fun putInt(data: PrefsData<Int>, value: Int) {
when (instance) { when (instance) {
is Context -> (instance as Context).prefs().edit { put(data, value) } is Context -> (instance as Context).prefs().edit { put(data, value) }
is PackageParam -> loggerW(msg = "Not support for this method") is PackageParam -> YLog.warn("Not support for this method")
else -> error("Unknown type for put prefs data") else -> error("Unknown type for put prefs data")
} }
} }
@@ -139,7 +139,7 @@ object ConfigData {
internal fun putBoolean(data: PrefsData<Boolean>, value: Boolean) { internal fun putBoolean(data: PrefsData<Boolean>, value: Boolean) {
when (instance) { when (instance) {
is Context -> (instance as Context).prefs().edit { put(data, value) } is Context -> (instance as Context).prefs().edit { put(data, value) }
is PackageParam -> loggerW(msg = "Not support for this method") is PackageParam -> YLog.warn("Not support for this method")
else -> error("Unknown type for put prefs data") else -> error("Unknown type for put prefs data")
} }
} }

View File

@@ -63,37 +63,39 @@ import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.field import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.hasMethod import com.highcapable.yukihookapi.hook.factory.hasMethod
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.log.loggerE import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.type.android.BundleClass import com.highcapable.yukihookapi.hook.type.android.BundleClass
import com.highcapable.yukihookapi.hook.type.android.MessageClass import com.highcapable.yukihookapi.hook.type.android.MessageClass
import com.highcapable.yukihookapi.hook.type.java.BooleanType import com.highcapable.yukihookapi.hook.type.java.BooleanType
object FrameworkHooker : YukiBaseHooker() { object FrameworkHooker : YukiBaseHooker() {
private const val ActivityManagerServiceClass = "com.android.server.am.ActivityManagerService" private val UserControllerClass by lazyClass("com.android.server.am.UserController")
private const val UserControllerClass = "com.android.server.am.UserController" private val AppErrorsClass by lazyClass("com.android.server.am.AppErrors")
private const val AppErrorsClass = "com.android.server.am.AppErrors" private val AppErrorDialogClass by lazyClass("com.android.server.am.AppErrorDialog")
private const val AppErrorDialogClass = "com.android.server.am.AppErrorDialog" private val AppErrorDialog_DataClass by lazyClass("com.android.server.am.AppErrorDialog\$Data")
private const val AppErrorDialog_DataClass = "com.android.server.am.AppErrorDialog\$Data" private val ProcessRecordClass by lazyClass("com.android.server.am.ProcessRecord")
private const val ProcessRecordClass = "com.android.server.am.ProcessRecord" private val ActivityManagerServiceClass by lazyClassOrNull("com.android.server.am.ActivityManagerService")
private const val ActivityTaskManagerService_LocalServiceClass = "com.android.server.wm.ActivityTaskManagerService\$LocalService" private val ActivityTaskManagerService_LocalServiceClass by lazyClassOrNull("com.android.server.wm.ActivityTaskManagerService\$LocalService")
private val PackageListClass = VariousClass( private val PackageListClass by lazyClassOrNull(
"com.android.server.am.ProcessRecord\$PackageList", VariousClass(
"com.android.server.am.PackageList" "com.android.server.am.ProcessRecord\$PackageList",
"com.android.server.am.PackageList"
)
) )
private val ErrorDialogControllerClass = VariousClass( private val ErrorDialogControllerClass by lazyClassOrNull(
"com.android.server.am.ProcessRecord\$ErrorDialogController", VariousClass(
"com.android.server.am.ErrorDialogController" "com.android.server.am.ProcessRecord\$ErrorDialogController",
"com.android.server.am.ErrorDialogController"
)
) )
/** 已忽略错误的 APP 数组 - 直到重新解锁 */ /** 已忽略错误的 APP 数组 - 直到重新解锁 */
private var mutedErrorsIfUnlockApps = HashSet<String>() private var mutedErrorsIfUnlockApps = mutableSetOf<String>()
/** 已忽略错误的 APP 数组 - 直到重新启动 */ /** 已忽略错误的 APP 数组 - 直到重新启动 */
private var mutedErrorsIfRestartApps = HashSet<String>() private var mutedErrorsIfRestartApps = mutableSetOf<String>()
/** /**
* APP 进程异常数据定义类 * APP 进程异常数据定义类
@@ -107,40 +109,40 @@ object FrameworkHooker : YukiBaseHooker() {
* 获取当前包列表实例 * 获取当前包列表实例
* @return [Any] or null * @return [Any] or null
*/ */
private val pkgList = if (ProcessRecordClass.toClass().hasMethod { name = "getPkgList"; emptyParam() }) private val pkgList = if (ProcessRecordClass.hasMethod { name = "getPkgList"; emptyParam() })
ProcessRecordClass.toClass().method { name = "getPkgList"; emptyParam() }.get(proc).call() ProcessRecordClass.method { name = "getPkgList"; emptyParam() }.get(proc).call()
else ProcessRecordClass.toClass().field { name = "pkgList" }.get(proc).any() else ProcessRecordClass.field { name = "pkgList" }.get(proc).any()
/** /**
* 获取当前包列表数组大小 * 获取当前包列表数组大小
* @return [Int] * @return [Int]
*/ */
private val pkgListSize = PackageListClass.toClassOrNull()?.method { name = "size"; emptyParam() }?.get(pkgList)?.int() private val pkgListSize = PackageListClass?.method { name = "size"; emptyParam() }?.get(pkgList)?.int()
?: ProcessRecordClass.toClass().field { name = "pkgList" }.get(proc).cast<ArrayMap<*, *>>()?.size ?: -1 ?: ProcessRecordClass.field { name = "pkgList" }.get(proc).cast<ArrayMap<*, *>>()?.size ?: -1
/** /**
* 获取当前 pid 信息 * 获取当前 pid 信息
* @return [Int] * @return [Int]
*/ */
val pid = ProcessRecordClass.toClass().field { name { it == "mPid" || it == "pid" } }.get(proc).int() val pid = ProcessRecordClass.field { name { it == "mPid" || it == "pid" } }.get(proc).int()
/** /**
* 获取当前用户 ID 信息 * 获取当前用户 ID 信息
* @return [Int] * @return [Int]
*/ */
val userId = ProcessRecordClass.toClass().field { name = "userId" }.get(proc).int() val userId = ProcessRecordClass.field { name = "userId" }.get(proc).int()
/** /**
* 获取当前 APP 信息 * 获取当前 APP 信息
* @return [ApplicationInfo] or null * @return [ApplicationInfo] or null
*/ */
val appInfo = ProcessRecordClass.toClass().field { name = "info" }.get(proc).cast<ApplicationInfo>() val appInfo = ProcessRecordClass.field { name = "info" }.get(proc).cast<ApplicationInfo>()
/** /**
* 获取当前进程名称 * 获取当前进程名称
* @return [String] * @return [String]
*/ */
val processName = ProcessRecordClass.toClass().field { name = "processName" }.get(proc).string() val processName = ProcessRecordClass.field { name = "processName" }.get(proc).string()
/** /**
* 获取当前 APP、进程 包名 * 获取当前 APP、进程 包名
@@ -164,17 +166,17 @@ object FrameworkHooker : YukiBaseHooker() {
* 获取当前进程是否为后台进程 * 获取当前进程是否为后台进程
* @return [Boolean] * @return [Boolean]
*/ */
val isBackgroundProcess = UserControllerClass.toClass() val isBackgroundProcess = UserControllerClass
.method { name { it == "getCurrentProfileIds" || it == "getCurrentProfileIdsLocked" } } .method { name { it == "getCurrentProfileIds" || it == "getCurrentProfileIdsLocked" } }
.get(ActivityManagerServiceClass.toClass().field { name = "mUserController" } .get(ActivityManagerServiceClass?.field { name = "mUserController" }
.get(AppErrorsClass.toClass().field { name = "mService" }.get(errors).any()).any()) ?.get(AppErrorsClass.field { name = "mService" }.get(errors).any())?.any())
.invoke<IntArray>()?.takeIf { it.isNotEmpty() }?.any { it != userId } ?: false .invoke<IntArray>()?.takeIf { it.isNotEmpty() }?.any { it != userId } ?: false
/** /**
* 获取当前进程是否短时内重复崩溃 * 获取当前进程是否短时内重复崩溃
* @return [Boolean] * @return [Boolean]
*/ */
val isRepeatingCrash = resultData?.let { AppErrorDialog_DataClass.toClass().field { name = "repeating" }.get(it).boolean() } ?: false val isRepeatingCrash = resultData?.let { AppErrorDialog_DataClass.field { name = "repeating" }.get(it).boolean() } ?: false
} }
/** 注册生命周期 */ /** 注册生命周期 */
@@ -193,34 +195,34 @@ object FrameworkHooker : YukiBaseHooker() {
SystemClock.sleep(100) SystemClock.sleep(100)
/** 刷新存储类 */ /** 刷新存储类 */
AppErrorsConfigData.refresh() AppErrorsConfigData.refresh()
if (prefs.isPreferencesAvailable.not()) loggerW(msg = "Cannot refreshing app errors config data, preferences is not available") if (prefs.isPreferencesAvailable.not()) YLog.warn("Cannot refreshing app errors config data, preferences is not available")
} }
onOpenAppUsedFramework { onOpenAppUsedFramework {
appContext?.openApp(it.first, it.second) appContext?.openApp(it.first, it.second)
loggerI(msg = "Opened \"${it.first}\"${it.second.takeIf { e -> e > 0 }?.let { e -> " --user $e" } ?: ""}") YLog.info("Opened \"${it.first}\"${it.second.takeIf { e -> e > 0 }?.let { e -> " --user $e" } ?: ""}")
} }
onPushAppErrorInfoData { onPushAppErrorInfoData {
AppErrorsRecordData.allData.firstOrNull { e -> e.pid == it } ?: run { AppErrorsRecordData.allData.firstOrNull { e -> e.pid == it } ?: run {
loggerW(msg = "Cannot received crash application data --pid $it") YLog.warn("Cannot received crash application data --pid $it")
AppErrorsInfoBean() AppErrorsInfoBean()
} }
} }
onPushAppErrorsInfoData { AppErrorsRecordData.allData.toArrayList() } onPushAppErrorsInfoData { AppErrorsRecordData.allData.toArrayList() }
onRemoveAppErrorsInfoData { onRemoveAppErrorsInfoData {
loggerI(msg = "Removed app errors info data for package \"${it.packageName}\"") YLog.info("Removed app errors info data for package \"${it.packageName}\"")
AppErrorsRecordData.remove(it) AppErrorsRecordData.remove(it)
} }
onClearAppErrorsInfoData { onClearAppErrorsInfoData {
loggerI(msg = "Cleared all app errors info data, size ${AppErrorsRecordData.allData.size}") YLog.info("Cleared all app errors info data, size ${AppErrorsRecordData.allData.size}")
AppErrorsRecordData.clearAll() AppErrorsRecordData.clearAll()
} }
onMutedErrorsIfUnlock { onMutedErrorsIfUnlock {
mutedErrorsIfUnlockApps.add(it) mutedErrorsIfUnlockApps.add(it)
loggerI(msg = "Muted \"$it\" until unlocks") YLog.info("Muted \"$it\" until unlocks")
} }
onMutedErrorsIfRestart { onMutedErrorsIfRestart {
mutedErrorsIfRestartApps.add(it) mutedErrorsIfRestartApps.add(it)
loggerI(msg = "Muted \"$it\" until restarts") YLog.info("Muted \"$it\" until restarts")
} }
onPushMutedErrorsAppsData { onPushMutedErrorsAppsData {
arrayListOf<MutedErrorsAppBean>().apply { arrayListOf<MutedErrorsAppBean>().apply {
@@ -233,17 +235,17 @@ object FrameworkHooker : YukiBaseHooker() {
onUnmuteErrorsApp { onUnmuteErrorsApp {
when (it.type) { when (it.type) {
MutedErrorsAppBean.MuteType.UNTIL_UNLOCKS -> { MutedErrorsAppBean.MuteType.UNTIL_UNLOCKS -> {
loggerI(msg = "Unmuted if unlocks errors app \"${it.packageName}\"") YLog.info("Unmuted if unlocks errors app \"${it.packageName}\"")
mutedErrorsIfUnlockApps.remove(it.packageName) mutedErrorsIfUnlockApps.remove(it.packageName)
} }
MutedErrorsAppBean.MuteType.UNTIL_REBOOTS -> { MutedErrorsAppBean.MuteType.UNTIL_REBOOTS -> {
loggerI(msg = "Unmuted if restarts errors app \"${it.packageName}\"") YLog.info("Unmuted if restarts errors app \"${it.packageName}\"")
mutedErrorsIfRestartApps.remove(it.packageName) mutedErrorsIfRestartApps.remove(it.packageName)
} }
} }
} }
onUnmuteAllErrorsApps { onUnmuteAllErrorsApps {
loggerI(msg = "Unmute all errors apps --unlocks ${mutedErrorsIfUnlockApps.size} --restarts ${mutedErrorsIfRestartApps.size}") YLog.info("Unmute all errors apps --unlocks ${mutedErrorsIfUnlockApps.size} --restarts ${mutedErrorsIfRestartApps.size}")
mutedErrorsIfUnlockApps.clear() mutedErrorsIfUnlockApps.clear()
mutedErrorsIfRestartApps.clear() mutedErrorsIfRestartApps.clear()
} }
@@ -269,7 +271,7 @@ object FrameworkHooker : YukiBaseHooker() {
} }
}.sortedByDescending { it.lastUpdateTime } }.sortedByDescending { it.lastUpdateTime }
.forEach { add(AppInfoBean(name = context.appNameOf(it.packageName), packageName = it.packageName)) } .forEach { add(AppInfoBean(name = context.appNameOf(it.packageName), packageName = it.packageName)) }
else loggerW(msg = "Fetched installed packages but got empty list") else YLog.warn("Fetched installed packages but got empty list")
} }
} }
} ?: arrayListOf() } ?: arrayListOf()
@@ -333,7 +335,7 @@ object FrameworkHooker : YukiBaseHooker() {
when { when {
packageName == BuildConfigWrapper.APPLICATION_ID -> { packageName == BuildConfigWrapper.APPLICATION_ID -> {
context.toast(msg = "AppErrorsTracking has crashed, please see the log in console") context.toast(msg = "AppErrorsTracking has crashed, please see the log in console")
loggerE(msg = "AppErrorsTracking has crashed itself, please see the Android Runtime Exception in console") YLog.error("AppErrorsTracking has crashed itself, please see the Android Runtime Exception in console")
} }
ConfigData.isEnableAppConfigTemplate -> when { ConfigData.isEnableAppConfigTemplate -> when {
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.GLOBAL, packageName) -> when { AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.GLOBAL, packageName) -> when {
@@ -350,11 +352,11 @@ object FrameworkHooker : YukiBaseHooker() {
else -> showAppErrorsWithDialog() else -> showAppErrorsWithDialog()
} }
/** 打印错误日志 */ /** 打印错误日志 */
if (isActualApp) loggerE( if (isActualApp) YLog.error(
msg = "Application \"$packageName\" ${if (isRepeatingCrash) "keeps stopping" else "has stopped"}" + msg = "Application \"$packageName\" ${if (isRepeatingCrash) "keeps stopping" else "has stopped"}" +
(if (packageName != processName) " --process \"$processName\"" else "") + (if (packageName != processName) " --process \"$processName\"" else "") +
"${if (userId != 0) " --user $userId" else ""} --pid $pid" "${if (userId != 0) " --user $userId" else ""} --pid $pid"
) else loggerE(msg = "Process \"$processName\" ${if (isRepeatingCrash) "keeps stopping" else "has stopped"} --pid $pid") ) else YLog.error("Process \"$processName\" ${if (isRepeatingCrash) "keeps stopping" else "has stopped"} --pid $pid")
} }
/** /**
@@ -364,101 +366,73 @@ object FrameworkHooker : YukiBaseHooker() {
*/ */
private fun AppErrorsProcessData.handleAppErrorsInfo(context: Context, info: ApplicationErrorReport.CrashInfo?) { private fun AppErrorsProcessData.handleAppErrorsInfo(context: Context, info: ApplicationErrorReport.CrashInfo?) {
AppErrorsRecordData.add(AppErrorsInfoBean.clone(context, pid, userId, appInfo?.packageName, info)) AppErrorsRecordData.add(AppErrorsInfoBean.clone(context, pid, userId, appInfo?.packageName, info))
loggerI(msg = "Received crash application data${if (userId != 0) " --user $userId" else ""} --pid $pid") YLog.info("Received crash application data${if (userId != 0) " --user $userId" else ""} --pid $pid")
} }
override fun onHook() { override fun onHook() {
/** 注册生命周期 */ /** 注册生命周期 */
registerLifecycle() registerLifecycle()
/** 干掉原生错误对话框 - 如果有 */ /** 干掉原生错误对话框 - 如果有 */
ErrorDialogControllerClass.hook { ErrorDialogControllerClass?.apply {
injectMember { method {
method { name = "hasCrashDialogs"
name = "hasCrashDialogs" emptyParam()
emptyParam() }.hook().replaceToTrue()
} method {
replaceToTrue() name = "showCrashDialogs"
} paramCount = 1
injectMember { }.hook().intercept()
method { }
name = "showCrashDialogs"
paramCount = 1
}
intercept()
}
}.ignoredHookClassNotFoundFailure()
/** 干掉原生错误对话框 - API 30 以下 */ /** 干掉原生错误对话框 - API 30 以下 */
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
ActivityTaskManagerService_LocalServiceClass.hook { ActivityTaskManagerService_LocalServiceClass?.method {
injectMember { name = "canShowErrorDialogs"
method { emptyParam()
name = "canShowErrorDialogs" }?.ignored()?.hook()?.replaceToFalse()
emptyParam() ActivityManagerServiceClass?.method {
} name = "canShowErrorDialogs"
replaceToFalse() emptyParam()
}.ignoredNoSuchMemberFailure() }?.ignored()?.hook()?.replaceToFalse()
}.ignoredHookClassNotFoundFailure()
ActivityManagerServiceClass.hook {
injectMember {
method {
name = "canShowErrorDialogs"
emptyParam()
}
replaceToFalse()
}.ignoredNoSuchMemberFailure()
}.ignoredHookClassNotFoundFailure()
} }
/** 干掉原生错误对话框 - 如果上述方法全部失效则直接结束对话框 */ /** 干掉原生错误对话框 - 如果上述方法全部失效则直接结束对话框 */
AppErrorDialogClass.hook { AppErrorDialogClass.apply {
injectMember { method {
method { name = "onCreate"
name = "onCreate" param(BundleClass)
param(BundleClass) }.ignored().hook().after { instance<Dialog>().cancel() }
} method {
afterHook { instance<Dialog>().cancel() } name = "onStart"
}.ignoredNoSuchMemberFailure() emptyParam()
injectMember { }.ignored().hook().after { instance<Dialog>().cancel() }
method {
name = "onStart"
emptyParam()
}
afterHook { instance<Dialog>().cancel() }
}.ignoredNoSuchMemberFailure()
} }
/** 注入自定义错误对话框 */ /** 注入自定义错误对话框 */
AppErrorsClass.hook { AppErrorsClass.apply {
injectMember { method {
method { name = "handleShowAppErrorUi"
name = "handleShowAppErrorUi" param(MessageClass)
param(MessageClass) }.hook().after {
} /** 当前实例 */
afterHook { val context = appContext ?: field { name = "mContext" }.get(instance).cast<Context>() ?: return@after
/** 当前实例 */
val context = appContext ?: field { name = "mContext" }.get(instance).cast<Context>() ?: return@afterHook
/** 当前错误数据 */ /** 当前错误数据 */
val resultData = args().first().cast<Message>()?.obj val resultData = args().first().cast<Message>()?.obj
/** 当前进程信息 */ /** 当前进程信息 */
val proc = AppErrorDialog_DataClass.toClass().field { name = "proc" }.get(resultData).any() val proc = AppErrorDialog_DataClass.field { name = "proc" }.get(resultData).any()
/** 创建 APP 进程异常数据类 */ /** 创建 APP 进程异常数据类 */
AppErrorsProcessData(instance, proc, resultData).handleShowAppErrorUi(context) AppErrorsProcessData(instance, proc, resultData).handleShowAppErrorUi(context)
}
} }
injectMember { method {
method { name = "handleAppCrashInActivityController"
name = "handleAppCrashInActivityController" returnType = BooleanType
returnType = BooleanType }.hook().after {
} /** 当前实例 */
afterHook { val context = appContext ?: field { name = "mContext" }.get(instance).cast<Context>() ?: return@after
/** 当前实例 */
val context = appContext ?: field { name = "mContext" }.get(instance).cast<Context>() ?: return@afterHook
/** 当前进程信息 */ /** 当前进程信息 */
val proc = args().first().any() ?: return@afterHook loggerW(msg = "Received but got null ProcessRecord") val proc = args().first().any() ?: return@after YLog.warn("Received but got null ProcessRecord")
/** 创建 APP 进程异常数据类 */ /** 创建 APP 进程异常数据类 */
AppErrorsProcessData(instance, proc).handleAppErrorsInfo(context, args(index = 1).cast()) AppErrorsProcessData(instance, proc).handleAppErrorsInfo(context, args(index = 1).cast())
}
} }
} }
} }

View File

@@ -43,8 +43,8 @@ import com.fankes.apperrorstracking.utils.factory.showDialog
import com.fankes.apperrorstracking.utils.factory.toUtcTime import com.fankes.apperrorstracking.utils.factory.toUtcTime
import com.fankes.apperrorstracking.utils.factory.toast import com.fankes.apperrorstracking.utils.factory.toast
import com.highcapable.yukihookapi.hook.factory.dataChannel import com.highcapable.yukihookapi.hook.factory.dataChannel
import com.highcapable.yukihookapi.hook.log.YukiHookLogger import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.log.YukiLoggerData import com.highcapable.yukihookapi.hook.log.data.YLogData
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.PrintStream import java.io.PrintStream
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@@ -65,7 +65,7 @@ class LoggerActivity : BaseActivity<ActivitiyLoggerBinding>() {
private var filters = arrayListOf("D", "I", "W", "E") private var filters = arrayListOf("D", "I", "W", "E")
/** 全部的调试日志数据 */ /** 全部的调试日志数据 */
private val listData = ArrayList<YukiLoggerData>() private val listData = mutableListOf<YLogData>()
override fun onCreate() { override fun onCreate() {
binding.titleBackIcon.setOnClickListener { finish() } binding.titleBackIcon.setOnClickListener { finish() }
@@ -176,7 +176,7 @@ class LoggerActivity : BaseActivity<ActivitiyLoggerBinding>() {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) runCatching { if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) runCatching {
data?.data?.let { data?.data?.let {
contentResolver?.openOutputStream(it)?.apply { write(YukiHookLogger.contents(listData).toByteArray()) }?.close() contentResolver?.openOutputStream(it)?.apply { write(YLog.contents(listData).toByteArray()) }?.close()
toast(LocaleString.exportAllLogsSuccess) toast(LocaleString.exportAllLogsSuccess)
} ?: toast(LocaleString.exportAllLogsFail) } ?: toast(LocaleString.exportAllLogsFail)
}.onFailure { toast(LocaleString.exportAllLogsFail) } }.onFailure { toast(LocaleString.exportAllLogsFail) }

View File

@@ -19,7 +19,7 @@
* *
* This file is created by fankes on 2022/5/12. * This file is created by fankes on 2022/5/12.
*/ */
@file:Suppress("unused", "OPT_IN_USAGE", "EXPERIMENTAL_API_USAGE") @file:Suppress("unused")
package com.fankes.apperrorstracking.utils.factory package com.fankes.apperrorstracking.utils.factory
@@ -38,7 +38,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.CircularProgressIndicator import com.google.android.material.progressindicator.CircularProgressIndicator
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
@@ -184,7 +183,6 @@ class DialogBuilder<VB : ViewBinding>(
fun cancel() = dialogInstance?.cancel() fun cancel() = dialogInstance?.cancel()
/** 显示对话框 */ /** 显示对话框 */
@CauseProblemsApi
fun show() { fun show() {
/** 若当前自定义 View 的对话框没有调用 [binding] 将会对其手动调用一次以确保显示布局 */ /** 若当前自定义 View 的对话框没有调用 [binding] 将会对其手动调用一次以确保显示布局 */
if (bindingClass != null) binding if (bindingClass != null) binding