mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-01 08:45:16 +08:00
Added multi-user display app's user id feature
This commit is contained in:
@@ -32,6 +32,7 @@ import java.util.*
|
||||
|
||||
/**
|
||||
* 应用异常信息 bean
|
||||
* @param userId 用户 ID
|
||||
* @param packageName 包名
|
||||
* @param isNativeCrash 是否为原生层异常
|
||||
* @param exceptionClassName 异常类名
|
||||
@@ -44,6 +45,7 @@ import java.util.*
|
||||
* @param timestamp 记录时间戳
|
||||
*/
|
||||
data class AppErrorsInfoBean(
|
||||
@Keep var userId: Int,
|
||||
@Keep var packageName: String,
|
||||
@Keep var isNativeCrash: Boolean,
|
||||
@Keep var exceptionClassName: String,
|
||||
@@ -61,12 +63,14 @@ data class AppErrorsInfoBean(
|
||||
/**
|
||||
* 从 [ApplicationErrorReport.CrashInfo] 克隆
|
||||
* @param packageName APP 包名
|
||||
* @param userId APP 用户 ID
|
||||
* @param crashInfo [ApplicationErrorReport.CrashInfo]
|
||||
* @return [AppErrorsInfoBean]
|
||||
*/
|
||||
fun clone(packageName: String?, crashInfo: ApplicationErrorReport.CrashInfo?) =
|
||||
fun clone(packageName: String?, userId: Int?, crashInfo: ApplicationErrorReport.CrashInfo?) =
|
||||
(crashInfo?.exceptionClassName?.lowercase() == "native crash").let { isNativeCrash ->
|
||||
AppErrorsInfoBean(
|
||||
userId = userId ?: 0,
|
||||
packageName = packageName ?: "unknown",
|
||||
isNativeCrash = isNativeCrash,
|
||||
exceptionClassName = crashInfo?.exceptionClassName ?: "unknown",
|
||||
@@ -122,6 +126,7 @@ data class AppErrorsInfoBean(
|
||||
"[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]: $dateTime\n" +
|
||||
"[Stack Trace]:\n" + stackTrace
|
||||
@@ -142,6 +147,7 @@ data class AppErrorsInfoBean(
|
||||
"[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]: $dateTime\n" +
|
||||
"[Stack Trace]:\n" + stackTrace
|
||||
|
@@ -75,6 +75,9 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
"com.android.server.am.ErrorDialogController"
|
||||
)
|
||||
|
||||
/** 已记录的 APP 用户 ID */
|
||||
private var appUserIdRecords = HashMap<String, Int>()
|
||||
|
||||
/** 已忽略错误的 APP 数组 - 直到重新解锁 */
|
||||
private var mutedErrorsIfUnlockApps = HashSet<String>()
|
||||
|
||||
@@ -250,10 +253,12 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
|
||||
/** 崩溃标题 */
|
||||
val errorTitle = if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName)
|
||||
/** 写入到用户 ID 记录 */
|
||||
appUserIdRecords[proc.toString()] = userId
|
||||
/** 打印错误日志 */
|
||||
if (isApp) loggerE(
|
||||
msg = "App \"$packageName\"${if (packageName != processName) " --process \"$processName\"" else ""}" +
|
||||
" has crashed${if (isRepeating) " again" else ""}"
|
||||
"${if (userId != 0) " --user $userId" else ""} has crashed${if (isRepeating) " again" else ""}"
|
||||
) else loggerE(msg = "Process \"$processName\" has crashed${if (isRepeating) " again" else ""}")
|
||||
/** 判断是否为模块自身崩溃 */
|
||||
if (packageName == BuildConfig.APPLICATION_ID) {
|
||||
@@ -308,10 +313,15 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
paramCount = 2
|
||||
}
|
||||
afterHook {
|
||||
/** 当前进程信息 */
|
||||
val proc = args().first().any()
|
||||
|
||||
/** 当前 APP 信息 */
|
||||
val appInfo = ProcessRecordClass.toClass().field { name = "info" }.get(args().first().any()).cast<ApplicationInfo>()
|
||||
val appInfo = ProcessRecordClass.toClass().field { name = "info" }.get(proc).cast<ApplicationInfo>()
|
||||
/** 添加当前异常信息到第一位 */
|
||||
appErrorsRecords.add(0, AppErrorsInfoBean.clone(appInfo?.packageName, args().last().cast()))
|
||||
appErrorsRecords.add(
|
||||
0, AppErrorsInfoBean.clone(appInfo?.packageName, appUserIdRecords[proc.toString()], args().last().cast())
|
||||
)
|
||||
/** 保存异常记录到本地 */
|
||||
saveAllAppErrorsRecords()
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDetailBinding
|
||||
@@ -86,6 +87,8 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
binding.appIcon.setImageDrawable(appIconOf(appErrorsInfo.packageName))
|
||||
binding.appNameText.text = appNameOf(appErrorsInfo.packageName)
|
||||
binding.appVersionText.text = appVersionBrandOf(appErrorsInfo.packageName)
|
||||
binding.appUserIdText.isVisible = appErrorsInfo.userId > 0
|
||||
binding.appUserIdText.text = LocaleString.userId(appErrorsInfo.userId)
|
||||
binding.appAbiText.text = appCpuAbiOf(appErrorsInfo.packageName).ifBlank { LocaleString.noCpuAbi }
|
||||
binding.jvmErrorPanel.isGone = appErrorsInfo.isNativeCrash
|
||||
binding.errorTypeIcon.setImageResource(if (appErrorsInfo.isNativeCrash) R.drawable.ic_cpp else R.drawable.ic_java)
|
||||
|
@@ -134,6 +134,8 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
|
||||
listData[position].also { bean ->
|
||||
binding.appIcon.setImageDrawable(appIconOf(bean.packageName))
|
||||
binding.appNameText.text = appNameOf(bean.packageName)
|
||||
binding.appUserIdText.isVisible = bean.userId > 0
|
||||
binding.appUserIdText.text = LocaleString.userId(bean.userId)
|
||||
binding.errorsTimeText.text = bean.crossTime
|
||||
binding.errorTypeIcon.setImageResource(if (bean.isNativeCrash) R.drawable.ic_cpp else R.drawable.ic_java)
|
||||
binding.errorTypeText.text = if (bean.isNativeCrash) "Native crash" else bean.exceptionClassName.simpleThwName()
|
||||
|
6
app/src/main/res/drawable/bg_blue_round.xml
Normal file
6
app/src/main/res/drawable/bg_blue_round.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#2196F3" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
@@ -151,6 +151,23 @@
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_user_id_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="@drawable/bg_blue_round"
|
||||
android:ellipsize="end"
|
||||
android:paddingLeft="3dp"
|
||||
android:paddingTop="0.5dp"
|
||||
android:paddingRight="3dp"
|
||||
android:paddingBottom="0.5dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/user_id"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="9sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="13dp"
|
||||
android:layout_height="13dp"
|
||||
|
@@ -39,16 +39,39 @@
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name_text"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_weight="0.75"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
android:gravity="center|start">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_user_id_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="@drawable/bg_blue_round"
|
||||
android:ellipsize="end"
|
||||
android:paddingLeft="3dp"
|
||||
android:paddingTop="0.5dp"
|
||||
android:paddingRight="3dp"
|
||||
android:paddingBottom="0.5dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/user_id"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="9sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errors_time_text"
|
||||
|
Reference in New Issue
Block a user