Modify make crashed apps info persistence and add more info to stackOutputShareContent, stackOutputFileContent in AppErrorsInfoBean, FrameworkHooker, AppErrorsDetailActivity

This commit is contained in:
2023-01-22 14:51:15 +08:00
parent 9dce54f326
commit 4d5dadae8b
3 changed files with 47 additions and 24 deletions

View File

@@ -22,10 +22,10 @@
package com.fankes.apperrorstracking.bean package com.fankes.apperrorstracking.bean
import android.app.ApplicationErrorReport import android.app.ApplicationErrorReport
import android.content.Context
import android.os.Build import android.os.Build
import com.fankes.apperrorstracking.locale.LocaleString import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.utils.factory.difference import com.fankes.apperrorstracking.utils.factory.*
import com.fankes.apperrorstracking.utils.factory.toUtcTime
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import java.io.Serializable import java.io.Serializable
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@@ -35,7 +35,10 @@ import java.util.*
* 应用异常信息 bean * 应用异常信息 bean
* @param pid 进程 ID * @param pid 进程 ID
* @param userId 用户 ID * @param userId 用户 ID
* @param cpuAbi CPU 架构类型
* @param packageName 包名 * @param packageName 包名
* @param versionName 版本名称
* @param versionCode 版本号
* @param isNativeCrash 是否为原生层异常 * @param isNativeCrash 是否为原生层异常
* @param exceptionClassName 异常类名 * @param exceptionClassName 异常类名
* @param exceptionMessage 异常信息 * @param exceptionMessage 异常信息
@@ -51,8 +54,14 @@ data class AppErrorsInfoBean(
var pid: Int = -1, var pid: Int = -1,
@SerializedName("userId") @SerializedName("userId")
var userId: Int = -1, var userId: Int = -1,
@SerializedName("cpuAbi")
var cpuAbi: String = "",
@SerializedName("packageName") @SerializedName("packageName")
var packageName: String = "", var packageName: String = "",
@SerializedName("versionName")
var versionName: String = "",
@SerializedName("versionCode")
var versionCode: Long = -1L,
@SerializedName("isNativeCrash") @SerializedName("isNativeCrash")
var isNativeCrash: Boolean = false, var isNativeCrash: Boolean = false,
@SerializedName("exceptionClassName") @SerializedName("exceptionClassName")
@@ -77,18 +86,22 @@ data class AppErrorsInfoBean(
/** /**
* 从 [ApplicationErrorReport.CrashInfo] 克隆 * 从 [ApplicationErrorReport.CrashInfo] 克隆
* @param context 当前实例
* @param pid APP 进程 ID * @param pid APP 进程 ID
* @param userId APP 用户 ID * @param userId APP 用户 ID
* @param packageName APP 包名 * @param packageName APP 包名
* @param crashInfo [ApplicationErrorReport.CrashInfo] * @param crashInfo [ApplicationErrorReport.CrashInfo]
* @return [AppErrorsInfoBean] * @return [AppErrorsInfoBean]
*/ */
fun clone(pid: Int, userId: Int, packageName: String?, crashInfo: ApplicationErrorReport.CrashInfo?) = fun clone(context: Context, pid: Int, userId: Int, packageName: String?, crashInfo: ApplicationErrorReport.CrashInfo?) =
(crashInfo?.exceptionClassName?.lowercase() == "native crash").let { isNativeCrash -> (crashInfo?.exceptionClassName?.lowercase() == "native crash").let { isNativeCrash ->
AppErrorsInfoBean( AppErrorsInfoBean(
pid = pid, pid = pid,
userId = userId, userId = userId,
cpuAbi = packageName?.let { context.appCpuAbiOf(it) } ?: "",
packageName = packageName ?: "unknown", packageName = packageName ?: "unknown",
versionName = packageName?.let { context.appVersionNameOf(it) } ?: "",
versionCode = packageName?.let { context.appVersionCodeOf(it) } ?: -1L,
isNativeCrash = isNativeCrash, isNativeCrash = isNativeCrash,
exceptionClassName = crashInfo?.exceptionClassName ?: "unknown", exceptionClassName = crashInfo?.exceptionClassName ?: "unknown",
exceptionMessage = if (isNativeCrash) crashInfo?.stackTrace.let { exceptionMessage = if (isNativeCrash) crashInfo?.stackTrace.let {
@@ -119,6 +132,12 @@ data class AppErrorsInfoBean(
*/ */
val jsonFileName get() = "${packageName}_${pid}_${timestamp}.json" val jsonFileName get() = "${packageName}_${pid}_${timestamp}.json"
/**
* 获取 APP 版本信息与版本号
* @return [String]
*/
val versionBrand get() = if (versionName.isBlank()) "unknown" else "$versionName($versionCode)"
/** /**
* 获取异常本地化 UTC 时间 * 获取异常本地化 UTC 时间
* @return [String] * @return [String]
@@ -153,18 +172,7 @@ data class AppErrorsInfoBean(
val stackOutputShareContent val stackOutputShareContent
get() = "Generated by AppErrorsTracking\n" + get() = "Generated by AppErrorsTracking\n" +
"Project Url: https://github.com/KitsunePie/AppErrorsTracking\n" + "Project Url: https://github.com/KitsunePie/AppErrorsTracking\n" +
"===============\n" + "===============\n$environmentInfo"
"[Device Brand]: ${Build.BRAND}\n" +
"[Device Model]: ${Build.MODEL}\n" +
"[Display]: ${Build.DISPLAY}\n" +
"[Android Version]: ${Build.VERSION.RELEASE}\n" +
"[API Version]: ${Build.VERSION.SDK_INT}\n" +
"[System Locale]: ${Locale.getDefault()}\n" +
"[Package Name]: $packageName\n" +
(if (userId > 0) "[User Id]: $userId\n" else "") +
"[Error Type]: ${if (isNativeCrash) "Native" else "Jvm"}\n" +
"[Crash Time]: $utcTime\n" +
"[Stack Trace]:\n" + stackTrace
/** /**
* 获取异常堆栈文件模板 * 获取异常堆栈文件模板
@@ -175,15 +183,26 @@ data class AppErrorsInfoBean(
" Generated by AppErrorsTracking\n" + " Generated by AppErrorsTracking\n" +
" Project Url: https://github.com/KitsunePie/AppErrorsTracking\n" + " Project Url: https://github.com/KitsunePie/AppErrorsTracking\n" +
"================================================================\n" + "================================================================\n" +
"[Device Brand]: ${Build.BRAND}\n" + environmentInfo
/**
* 获取运行环境信息
* @return [String]
*/
private val environmentInfo
get() = "[Device Brand]: ${Build.BRAND}\n" +
"[Device Model]: ${Build.MODEL}\n" + "[Device Model]: ${Build.MODEL}\n" +
"[Display]: ${Build.DISPLAY}\n" + "[Display]: ${Build.DISPLAY}\n" +
"[Android Version]: ${Build.VERSION.RELEASE}\n" + "[Android Version]: ${Build.VERSION.RELEASE}\n" +
"[API Version]: ${Build.VERSION.SDK_INT}\n" + "[Android API Level]: ${Build.VERSION.SDK_INT}\n" +
"[System Locale]: ${Locale.getDefault()}\n" + "[System Locale]: ${Locale.getDefault()}\n" +
"[Package Name]: $packageName\n" + "[Process ID]: $pid\n" +
(if (userId > 0) "[User Id]: $userId\n" else "") + (if (userId > 0) "[User Id]: $userId\n" else "") +
"[Error Type]: ${if (isNativeCrash) "Native" else "Jvm"}\n" + "[CPU ABI]: ${cpuAbi.ifBlank { "none" }}\n" +
"[Package Name]: $packageName\n" +
"[Version Name]: ${versionName.ifBlank { "unknown" }}\n" +
"[Version Code]: ${versionCode.takeIf { it != -1L } ?: "unknown"}\n" +
"[Error Type]: ${if (isNativeCrash) "Native" else "JVM"}\n" +
"[Crash Time]: $utcTime\n" + "[Crash Time]: $utcTime\n" +
"[Stack Trace]:\n" + stackTrace "[Stack Trace]:\n" + stackTrace
} }

View File

@@ -350,10 +350,11 @@ object FrameworkHooker : YukiBaseHooker() {
/** /**
* 处理 APP 进程异常数据 * 处理 APP 进程异常数据
* @param context 当前实例
* @param info 系统错误报告数据实例 * @param info 系统错误报告数据实例
*/ */
private fun AppErrorsProcessData.handleAppErrorsInfo(info: ApplicationErrorReport.CrashInfo?) { private fun AppErrorsProcessData.handleAppErrorsInfo(context: Context, info: ApplicationErrorReport.CrashInfo?) {
AppErrorsRecordData.add(AppErrorsInfoBean.clone(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") loggerI(msg = "Received crash application data${if (userId != 0) " --user $userId" else ""} --pid $pid")
} }
@@ -441,10 +442,13 @@ object FrameworkHooker : YukiBaseHooker() {
returnType = BooleanType returnType = BooleanType
} }
afterHook { afterHook {
/** 当前实例 */
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@afterHook loggerW(msg = "Received but got null ProcessRecord")
/** 创建 APP 进程异常数据类 */ /** 创建 APP 进程异常数据类 */
AppErrorsProcessData(instance, proc).handleAppErrorsInfo(args(index = 1).cast()) AppErrorsProcessData(instance, proc).handleAppErrorsInfo(context, args(index = 1).cast())
} }
} }
} }

View File

@@ -105,10 +105,10 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
} }
binding.appIcon.setImageDrawable(appIconOf(appErrorsInfo.packageName)) binding.appIcon.setImageDrawable(appIconOf(appErrorsInfo.packageName))
binding.appNameText.text = appNameOf(appErrorsInfo.packageName) binding.appNameText.text = appNameOf(appErrorsInfo.packageName)
binding.appVersionText.text = appVersionBrandOf(appErrorsInfo.packageName) binding.appVersionText.text = appErrorsInfo.versionBrand
binding.appUserIdText.isVisible = appErrorsInfo.userId > 0 binding.appUserIdText.isVisible = appErrorsInfo.userId > 0
binding.appUserIdText.text = LocaleString.userId(appErrorsInfo.userId) binding.appUserIdText.text = LocaleString.userId(appErrorsInfo.userId)
binding.appCpuAbiText.text = appCpuAbiOf(appErrorsInfo.packageName).ifBlank { LocaleString.noCpuAbi } binding.appCpuAbiText.text = appErrorsInfo.cpuAbi.ifBlank { LocaleString.noCpuAbi }
binding.jvmErrorPanel.isGone = appErrorsInfo.isNativeCrash binding.jvmErrorPanel.isGone = appErrorsInfo.isNativeCrash
binding.errorTypeIcon.setImageResource(if (appErrorsInfo.isNativeCrash) R.drawable.ic_cpp else R.drawable.ic_java) binding.errorTypeIcon.setImageResource(if (appErrorsInfo.isNativeCrash) R.drawable.ic_cpp else R.drawable.ic_java)
binding.errorInfoText.text = appErrorsInfo.exceptionMessage binding.errorInfoText.text = appErrorsInfo.exceptionMessage