Fix some custom system can't read application crash info on-time will get wrong errors data problem

This commit is contained in:
2022-10-03 07:19:13 +08:00
parent 1153494dfa
commit 2472f8b7e5
5 changed files with 71 additions and 25 deletions

View File

@@ -26,6 +26,7 @@ import java.io.Serializable
/**
* 应用异常信息显示 bean
* @param pid APP 进程 ID
* @param userId APP 用户 ID
* @param packageName APP 包名
* @param processName APP 进程名
@@ -36,6 +37,7 @@ import java.io.Serializable
* @param isShowReopenButton 是否显示重新打开按钮
*/
data class AppErrorsDisplayBean(
@Keep var pid: Int,
@Keep var userId: Int,
@Keep var packageName: String,
@Keep var processName: String,

View File

@@ -33,6 +33,7 @@ import java.util.*
/**
* 应用异常信息 bean
* @param pid 进程 ID
* @param userId 用户 ID
* @param packageName 包名
* @param isNativeCrash 是否为原生层异常
@@ -46,31 +47,40 @@ import java.util.*
* @param timestamp 记录时间戳
*/
data class AppErrorsInfoBean(
@Keep var userId: Int,
@Keep var packageName: String,
@Keep var isNativeCrash: Boolean,
@Keep var exceptionClassName: String,
@Keep var exceptionMessage: String,
@Keep var throwFileName: String,
@Keep var throwClassName: String,
@Keep var throwMethodName: String,
@Keep var throwLineNumber: Int,
@Keep var stackTrace: String,
@Keep var timestamp: Long,
@Keep var pid: Int = -1,
@Keep var userId: Int = -1,
@Keep var packageName: String = "",
@Keep var isNativeCrash: Boolean = false,
@Keep var exceptionClassName: String = "",
@Keep var exceptionMessage: String = "",
@Keep var throwFileName: String = "",
@Keep var throwClassName: String = "",
@Keep var throwMethodName: String = "",
@Keep var throwLineNumber: Int = -1,
@Keep var stackTrace: String = "",
@Keep var timestamp: Long = -1L
) : Serializable {
companion object {
/**
* 创建一个空的 [AppErrorsInfoBean]
* @return [AppErrorsInfoBean]
*/
fun createEmpty() = AppErrorsInfoBean().apply { isEmpty = true }
/**
* 从 [ApplicationErrorReport.CrashInfo] 克隆
* @param pid APP 进程 ID
* @param packageName APP 包名
* @param userId APP 用户 ID
* @param crashInfo [ApplicationErrorReport.CrashInfo]
* @return [AppErrorsInfoBean]
*/
fun clone(packageName: String?, userId: Int?, crashInfo: ApplicationErrorReport.CrashInfo?) =
fun clone(pid: Int, packageName: String?, userId: Int?, crashInfo: ApplicationErrorReport.CrashInfo?) =
(crashInfo?.exceptionClassName?.lowercase() == "native crash").let { isNativeCrash ->
AppErrorsInfoBean(
pid = pid,
userId = userId ?: 0,
packageName = packageName ?: "unknown",
isNativeCrash = isNativeCrash,
@@ -91,6 +101,9 @@ data class AppErrorsInfoBean(
}
}
/** 标识当前内容是否为空 */
var isEmpty = false
/**
* 获取异常本地化 UTC 时间
* @return [String]

View File

@@ -76,7 +76,7 @@ object FrameworkHooker : YukiBaseHooker() {
)
/** 已记录的 APP 用户 ID */
private var appUserIdRecords = HashMap<String, Int>()
private var appUserIdRecords = HashMap<Int, Int>()
/** 已忽略错误的 APP 数组 - 直到重新解锁 */
private var mutedErrorsIfUnlockApps = HashSet<String>()
@@ -99,6 +99,7 @@ object FrameworkHooker : YukiBaseHooker() {
}
FrameworkTool.Host.with(instance = this) {
onOpenAppUsedFramework { appContext?.openApp(it.first, it.second) }
onPushAppErrorInfoData { appErrorsRecords.firstOrNull { e -> e.pid == it } ?: AppErrorsInfoBean.createEmpty() }
onPushAppErrorsInfoData { appErrorsRecords }
onRemoveAppErrorsInfoData {
appErrorsRecords.remove(it)
@@ -257,7 +258,7 @@ object FrameworkHooker : YukiBaseHooker() {
/** 崩溃标题 */
val errorTitle = if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName)
/** 写入到用户 ID 记录 */
appUserIdRecords[proc.toString()] = userId
appUserIdRecords[pid] = userId
/** 打印错误日志 */
if (isApp) loggerE(
msg = "App \"$packageName\"${if (packageName != processName) " --process \"$processName\"" else ""}" +
@@ -298,6 +299,7 @@ object FrameworkHooker : YukiBaseHooker() {
/** 启动错误对话框显示窗口 */
AppErrorsDisplayActivity.start(
context, AppErrorsDisplayBean(
pid = pid,
userId = userId,
packageName = packageName,
processName = processName,
@@ -320,12 +322,20 @@ object FrameworkHooker : YukiBaseHooker() {
/** 当前进程信息 */
val proc = args().first().any()
/** 当前 pid 信息 */
val pid = ProcessRecordClass.toClass().field { name { it == "mPid" || it == "pid" } }.get(proc).int()
/** 当前 APP 信息 */
val appInfo = ProcessRecordClass.toClass().field { name = "info" }.get(proc).cast<ApplicationInfo>()
/** 添加当前异常信息到第一位 */
appErrorsRecords.add(
0, AppErrorsInfoBean.clone(appInfo?.packageName, appUserIdRecords[proc.toString()], args().last().cast())
)
/** 启动新线程延迟防止方法执行顺序在前导致无法正确获取数据 */
newThread {
/** 延迟 50ms */
Thread.sleep(50)
/** 添加当前异常信息到第一位 */
appErrorsRecords.add(
0, AppErrorsInfoBean.clone(pid, appInfo?.packageName, appUserIdRecords[pid], args().last().cast())
)
}
/** 保存异常记录到本地 */
saveAllAppErrorsRecords()
}

View File

@@ -84,13 +84,11 @@ class AppErrorsDisplayActivity : BaseActivity<ActivityAppErrorsDisplayBinding>()
cancel()
}
binding.errorDetailItem.setOnClickListener {
FrameworkTool.fetchAppErrorsInfoData(context) { appErrorsInfos ->
appErrorsInfos.takeIf { it.isNotEmpty() }
?.filter { it.packageName == appErrorsDisplay.packageName }
?.takeIf { it.isNotEmpty() }?.get(0)?.let {
AppErrorsDetailActivity.start(context, it)
cancel()
} ?: toast(msg = "No errors founded")
FrameworkTool.fetchAppErrorInfoData(context, appErrorsDisplay.pid) { appErrorsInfo ->
appErrorsInfo.takeIf { it.isEmpty.not() }?.also {
AppErrorsDetailActivity.start(context, it)
cancel()
} ?: toast(LocaleString.unableGetAppErrorsRecordTip)
}
}
binding.mutedIfUnlockItem.setOnClickListener {

View File

@@ -56,10 +56,12 @@ object FrameworkTool {
private const val CALL_UNMUTE_ERRORS_APP_DATA_RESULT = "call_unmute_errors_app_data_result"
private const val CALL_UNMUTE_ALL_ERRORS_APPS_DATA_RESULT = "call_unmute_all_errors_apps_data_result"
private val CALL_APP_ERROR_DATA_GET = ChannelData<Int>("call_app_error_data_get")
private val CALL_OPEN_SPECIFY_APP = ChannelData<Pair<String, Int>>("call_open_specify_app")
private val CALL_APP_LIST_DATA_GET = ChannelData<AppFiltersBean>("call_app_info_list_data_get")
private val CALL_APP_ERRORS_DATA_REMOVE = ChannelData<AppErrorsInfoBean>("call_app_errors_data_remove")
private val CALL_APP_LIST_DATA_GET_RESULT = ChannelData<ArrayList<AppInfoBean>>("call_app_info_list_data_get_result")
private val CALL_APP_ERROR_DATA_GET_RESULT = ChannelData<AppErrorsInfoBean>("call_app_error_data_get_result")
private val CALL_APP_ERRORS_DATA_GET_RESULT = ChannelData<ArrayList<AppErrorsInfoBean>>("call_app_errors_data_get_result")
private val CALL_MUTED_ERRORS_APP_DATA_GET_RESULT = ChannelData<ArrayList<MutedErrorsAppBean>>("call_muted_app_errors_data_get_result")
private val CALL_UNMUTE_ERRORS_APP_DATA = ChannelData<MutedErrorsAppBean>("call_unmute_errors_app_data")
@@ -88,6 +90,14 @@ object FrameworkTool {
*/
fun onOpenAppUsedFramework(result: (Pair<String, Int>) -> Unit) = instance?.dataChannel?.wait(CALL_OPEN_SPECIFY_APP) { result(it) }
/**
* 监听发送指定 APP 异常信息
* @param result 回调数据
*/
fun onPushAppErrorInfoData(result: (Int) -> AppErrorsInfoBean) {
instance?.dataChannel?.with { wait(CALL_APP_ERROR_DATA_GET) { put(CALL_APP_ERROR_DATA_GET_RESULT, result(it)) } }
}
/**
* 监听发送 APP 异常信息数组
* @param result 回调数据
@@ -235,6 +245,19 @@ object FrameworkTool {
fun openAppUsedFramework(context: Context, packageName: String, userId: Int) =
context.dataChannel(SYSTEM_FRAMEWORK_NAME).put(CALL_OPEN_SPECIFY_APP, Pair(packageName, userId))
/**
* 获取指定 APP 异常信息
* @param context 实例
* @param pid 当前进程 ID
* @param result 回调数据
*/
fun fetchAppErrorInfoData(context: Context, pid: Int, result: (AppErrorsInfoBean) -> Unit) {
context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
wait(CALL_APP_ERROR_DATA_GET_RESULT) { result(it) }
put(CALL_APP_ERROR_DATA_GET, pid)
}
}
/**
* 获取 APP 异常信息数组
* @param context 实例