Android ANR 信息收集的 "破案" 故事:系统如何追踪卡死现场

一、ANR 报警:程序卡死的 "110" 呼叫

想象 Android 系统是一个繁忙的城市,各个应用程序就像忙碌的工厂。当一个工厂(应用)超过规定时间没响应(比如前台服务超过 20 秒没干完活),就会触发 "城市报警中心"AMS(ActivityManagerService)的警报系统。

java

scss 复制代码
// AMS接到报警的第一反应
final void appNotResponding(ProcessRecord app, ...) {
    // 记录报警时间和基本信息到"城市日志"EventLog
    EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, ...);
    // 组建"专案组":先把卡死工厂和关键部门加入调查名单
    firstPids.add(app.pid); // 卡死的工厂
    firstPids.add(MY_PID); // 城市管理中心system_server
    for (ProcessRecord r : mLruProcesses) {
        if (r.persistent) firstPids.add(r.pid); // 重要的"国企"进程
        else lastPids.put(r.pid, true); // 其他"民营企业"进程
    }
}

关键比喻

  • EventLog 相当于 110 接警记录,精确记录报警时间
  • firstPids 是 "重点嫌疑名单",包括卡死应用和核心系统进程
  • lastPids 是 "普通围观群众" 名单,后续按需调查

二、现场勘查:多团队协作收集证据

1. 组建 "证据收集小组"

当 AMS 决定调查后,会启动一个 "证据收集小组",专门负责获取各个进程的 "工作记录"(堆栈信息):

java

arduino 复制代码
// 证据收集总负责人
public static File dumpStackTraces(...) {
    String tracesPath = "/data/anr/traces.txt"; // 证据档案柜
    File tracesFile = new File(tracesPath);
    tracesFile.createNewFile(); // 清空旧档案,准备新记录
    
    // 先调查"重点嫌疑名单"
    for (int pid : firstPids) {
        Process.sendSignal(pid, Process.SIGNAL_QUIT); // 给工厂发信号:交工作记录!
        Thread.sleep(200); // 等200ms收报告
    }
    
    // 再调查"Native特种部门"(如显卡、媒体部门)
    String[] nativeProcs = {"mediaserver", "surfaceflinger"};
    int[] pids = Process.getPidsForCommands(nativeProcs);
    for (int pid : pids) {
        Debug.dumpNativeBacktraceToFile(pid, tracesPath); // 用特殊工具获取Native部门记录
    }
    
    // 最后调查"CPU高负荷工厂"(前5名)
    for (ProcessCpuTracker.Stats stats : processCpuTracker.getWorkingStats()) {
        if (lastPids.containsKey(stats.pid) && numProcs < 5) {
            Process.sendSignal(stats.pid, Process.SIGNAL_QUIT); // 高负荷工厂也交记录
            numProcs++;
        }
    }
}

2. Native 部门的特殊调查手段

当需要调查 Native 进程(如显卡驱动、媒体引擎)时,系统会派出 "特种调查员"debuggerd,通过 socket 发送专门的调查命令:

c

运行

arduino 复制代码
// debugger.c中的Native调查流程
int dump_backtrace_to_file(pid_t tid, int fd) {
    int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid, 0);
    // 通过socket向debuggerd发送"获取堆栈"命令
    while (read(sock_fd, buffer, sizeof(buffer)) > 0) {
        write(fd, buffer, n); // 把调查结果写入档案柜
    }
}

关键比喻

  • SIGNAL_QUIT 信号相当于给 Java 工厂发 "交工作日志" 通知
  • debuggerd 相当于特种调查队,专门处理 Native 部门的调查
  • traces.txt 是 "案件档案柜",所有证据都汇总到这里

三、证据分析:CPU 使用率与现场报告

1. CPU"工作效率" 统计

在收集堆栈的同时,系统会统计各个工厂的 "工作效率"(CPU 使用率),看看是不是因为某个工厂太繁忙导致卡死:

java

scss 复制代码
// 两次更新CPU统计,计算时间段内的效率
updateCpuStatsNow(); // 第一次记录
// 中间收集堆栈...
updateCpuStatsNow(); // 第二次记录

// 生成效率报告
String cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
String loadInfo = processCpuTracker.printCurrentLoad();
info.append("CPU负载: ").append(loadInfo);
info.append("进程效率: ").append(cpuInfo);

2. 证据归档:重要证据存入 "证据库"

所有收集到的堆栈和 CPU 报告,最终会被存入系统的 "证据库"dropbox,方便后续分析:

java

scss 复制代码
// 把证据存入dropbox
addErrorToDropBox("anr", app, app.processName, 
                  tracesFile, cpuInfo, ...);

关键比喻

  • CPU 统计相当于工厂的 "考勤记录",查看是否有超负荷工作
  • dropbox 相当于 "中央证据库",所有重要案件证据都会存档
  • 证据包括:卡死原因(Reason)、各工厂日志(堆栈)、工作效率(CPU)

四、结案流程:根据情况决定处理方式

1. 后台工厂:直接 "停业整顿"

如果是后台不重要的工厂(用户不关心的应用),系统会直接让它 "停业整顿"(杀死进程):

java

kotlin 复制代码
// 后台且用户不关心的工厂,直接杀死
if (!showBackground && !app.isInterestingToUserLocked()) {
    app.kill("bg anr", true);
    return;
}

2. 前台工厂:弹出 "停业通知"

如果是前台重要工厂(用户正在使用的应用),系统会弹出 "停业通知"(ANR 对话框),让用户选择处理方式:

java

ini 复制代码
// 准备通知内容
Message msg = Message.obtain();
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
map.put("app", app);
// 发送给UI线程,显示ANR对话框
mUiHandler.sendMessage(msg);

五、破案总结:ANR 调查的完整流程

  1. 报警阶段:应用超时触发 AMS 报警,记录 EventLog

  2. 组建专案组:确定重点调查对象(firstPids、lastPids)

  3. 现场勘查

    • 给 Java 工厂发 SIGNAL_QUIT 获取工作日志(堆栈)
    • 用 debuggerd 调查 Native 特种部门
    • 调查 CPU 高负荷的前 5 个工厂
  4. 效率分析:统计各工厂 CPU 使用率,分析是否超负荷

  5. 证据归档:所有证据存入 dropbox,方便后续分析

  6. 结案处理:后台工厂直接关闭,前台工厂通知用户

关键技术点对比

工厂类型 调查手段 对应命令
Java 工厂 发送 SIGNAL_QUIT kill -3 [pid]
Native 工厂 debuggerd 特殊调查 debuggerd -b [pid]

通过这个 "破案" 故事,我们可以理解 Android 系统在 ANR 发生时,如何像侦探一样收集现场证据,分析问题原因,并记录关键信息以便后续排查。整个过程的核心就是围绕 "收集各进程堆栈" 和 "分析 CPU 使用情况" 展开,最终将证据归档到 dropbox 供开发者分析。

相关推荐
敲代码的剑缘一心5 分钟前
手把手教你学会写 Gradle 插件
android·gradle
青蛙娃娃36 分钟前
漫画Android:动画是如何实现的?
android·android studio
aningxiaoxixi1 小时前
android 之 CALL
android
用户2018792831672 小时前
Android 核心大管家 ActivityManagerService (AMS)
android
春马与夏3 小时前
Android自动化AirScript
android·运维·自动化
键盘歌唱家4 小时前
mysql索引失效
android·数据库·mysql
webbin5 小时前
Compose @Immutable注解
android·android jetpack
无知的前端5 小时前
Flutter开发,GetX框架路由相关详细示例
android·flutter·ios
玲小珑5 小时前
Auto.js 入门指南(十二)网络请求与数据交互
android·前端
webbin6 小时前
Compose 副作用
android·android jetpack