阅读错误报告

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

错误在任何类型的开发中都是现实——错误报告对于识别和解决问题至关重要。所有版本的 Android 都支持使用Android Debug Bridge (adb)捕获错误报告; Android 4.2 及更高版本支持开发者选项,用于获取错误报告并通过电子邮件、云端硬盘等进行共享。

Android 错误报告包含文本 (.txt) 格式的dumpsysdumpstatelogcat数据,使您能够轻松搜索特定内容。以下部分详细介绍了错误报告组件,描述了常见问题,并提供了有用的提示和grep命令以查找与这些错误相关的日志。大多数部分还包括grep命令和输出和/或dumpsys输出的示例。

日志猫

logcat日志是所有logcat信息的基于字符串的转储。系统部分是为框架保留的,并且比包含其他所有内容的main具有更长的历史。每行通常以timestamp UID PID TID log-level开头,尽管UID可能不会在旧版本的 Android 中列出。

查看事件日志

此日志包含二进制格式的日志消息的字符串表示形式。它比logcat日志噪音小,但也更难阅读。查看事件日志时,您可以在此部分搜索特定的进程 ID (PID),以查看进程一直在做什么。基本格式为: timestamp PID TID log-level log-tag tag-values

日志级别包括以下内容:

  • 五:冗长
  • D:调试
  • 一:资料
  • W:警告
  • E:错误

有关其他有用的事件日志标签,请参阅/services/core/java/com/android/server/EventLogTags.logtags

ANR 和死锁

错误报告可以帮助您确定导致应用程序无响应 (ANR)错误和死锁事件的原因。

识别无响应的应用程序

当应用程序在一定时间内没有响应时,通常是由于主线程阻塞或繁忙,系统会终止进程并将堆栈转储到/data/anr 。要发现 ANR 背后的罪魁祸首,请在二进制事件日志中 grep 查找am_anr

您还可以在logcat日志中对ANR in grep,其中包含有关 ANR 时 CPU 使用情况的更多信息。

查找堆栈跟踪

您通常可以找到与 ANR 对应的堆栈跟踪。确保 VM 跟踪上的时间戳和 PID 与您正在调查的 ANR 匹配,然后检查进程的主线程。记住:

  • 主线程只告诉您在 ANR 时线程在做什么,这可能对应也可能不对应 ANR 的真正原因。 (错误报告中的堆栈可能是无辜的;其他东西可能已经被卡住了很长时间——但还不足以导致 ANR——在解除卡住之前。)
  • 可能存在不止一组堆栈跟踪( VM TRACES JUST NOWVM TRACES AT LAST ANR )。确保您正在查看正确的部分。

发现死锁

死锁通常首先表现为 ANR,因为线程卡住了。如果死锁命中系统服务器,看门狗最终会杀死它,导致日志中出现类似于: WATCHDOG KILLING SYSTEM PROCESS的条目。从用户的角度来看,设备会重新启动,尽管从技术上讲,这是运行时重新启动,而不是真正的重新启动。

  • 运行时重新启动中,系统服务器死掉并重新启动;用户看到设备返回启动动画。
  • 重新启动时,内核已经崩溃;用户会看到设备返回到 Google 启动徽标。

要查找死锁,请检查 VM 跟踪部分以了解线程 A 等待线程 B 持有的东西的模式,而线程 B 又等待线程 A 持有的东西。

活动

Activity是一个应用程序组件,它提供用户与之交互的屏幕,以执行诸如拨号、拍照、发送电子邮件等操作。从错误报告的角度来看, Activity是用户可以做的单一的、专注的事情,这使得定位在崩溃期间成为焦点的活动非常重要。活动(通过 ActivityManager)运行流程,因此定位给定活动的所有流程停止和启动也有助于故障排除。

查看重点活动

要查看重点活动的历史记录,请搜索am_focused_activity

查看过程开始

要查看进程启动的历史记录,请搜索Start proc

设备是否抖动?

要确定设备是否在抖动,请在短时间内检查am_proc_diedam_proc_start周围的活动是否异常增加。

记忆

由于 Android 设备通常具有受限的物理内存,因此管理随机存取内存 (RAM) 至关重要。错误报告包含几个内存不足的指标以及提供内存快照的转储状态。

识别内存不足

内存不足会导致系统崩溃,因为它会杀死一些进程以释放内存但继续启动其他进程。要查看内存不足的确凿证据,请检查二进制事件日志中am_proc_diedam_proc_start条目的集中度。

内存不足也会减慢任务切换并阻碍返回尝试(因为用户试图返回的任务已被终止)。如果启动器被杀死,它会在用户触摸主页按钮时重新启动,并且日志显示启动器重新加载其内容。

查看历史指标

二进制事件日志中的am_low_memory条目表示最后一个缓存进程已经死亡。在此之后,系统开始杀死服务。

查看抖动指标

系统抖动(分页、直接回收等)的其他指标包括kswapdkworkermmcqd消耗周期。 (请记住,正在收集的错误报告可能会影响抖动指标。)

ANR 日志可以提供类似的内存快照。

获取内存快照

内存快照是一个转储状态,列出了正在运行的 Java 和本机进程(有关详细信息,请参阅查看总体内存分配)。请记住,快照仅给出特定时刻的状态;在快照之前,系统可能处于更好(或更差)的状态。

广播

应用程序生成广播以在当前应用程序内或向另一个应用程序发送事件。广播接收器订阅特定消息(通过过滤器),使它们能够收听和响应广播。错误报告包含有关已发送广播和未发送广播的信息,以及侦听特定广播的所有接收器的转储系统。

查看历史广播

历史广播是那些已经发送的广播,按时间倒序排列。

摘要部分是最近 300 次前台广播和最近 300 次后台广播的概述。

详细信息部分包含最后 50 个前台广播和最后 50 个后台广播的完整信息,以及每个广播的接收器。接收器具有:

  • BroadcastFilter条目在运行时注册,并且只发送到已经运行的进程。
  • ResolveInfo条目是通过清单条目注册的。如果每个ResolveInfo尚未运行,则 ActivityManager 会启动该进程。

查看活动广播

活动广播是那些尚未发送的广播。队列中的大量数字意味着系统无法以足够快的速度分派广播以跟上。

查看广播监听器

要查看侦听广播的接收器列表,请检查dumpsys activity broadcasts中的接收器解析器表。以下示例显示了所有侦听USER_PRESENT的接收器。

监控争用

监视器争用日志有时可以指示实际的监视器争用,但大多数情况下表明系统负载过大以至于一切都变慢了。您可能会在系统或事件日志中看到由 ART 记录的长监控事件。

在系统日志中:

10-01 18:12:44.343 29761 29914 W art     : Long monitor contention event with owner method=void android.database.sqlite.SQLiteClosable.acquireReference() from SQLiteClosable.java:52 waiters=0 for 3.914s

在事件日志中:

10-01 18:12:44.364 29761 29914 I dvm_lock_sample: [com.google.android.youtube,0,pool-3-thread-9,3914,ScheduledTaskMaster.java,138,SQLiteClosable.java,52,100]

后台编译

编译可能很昂贵并且会加载设备。

下载 Google Play 商店更新时,可能会在后台进行编译。在这种情况下,来自 Google Play 商店应用程序 ( finsky ) 和installd的消息出现在dex2oat消息之前。

当应用程序加载尚未编译的 dex 文件时,也可能在后台进行编译。在这种情况下,您不会看到finskyinstalld日志记录。

叙述

建立问题的叙述(它是如何开始的,发生了什么,系统如何反应)需要一个可靠的事件时间表。您可以使用错误报告中的信息跨多个日志同步时间线并确定错误报告的确切时间戳。

同步时间线

错误报告反映了多个并行时间线:系统日志、事件日志、内核日志以及用于广播、电池统计信息等的多个专用时间线。不幸的是,通常使用不同的时间基准报告时间线。

系统和事件日志时间戳与用户位于同一时区(与大多数其他时间戳一样)。例如,当用户点击主页按钮时,系统日志报告:

10-03 17:19:52.939  1963  2071 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.google.android.googlequicksearchbox/com.google.android.launcher.GEL (has extras)} from uid 1000 on display 0

对于相同的操作,事件日志报告:

10-03 17:19:54.279  1963  2071 I am_focused_activity: [0,com.google.android.googlequicksearchbox/com.google.android.launcher.GEL]

内核 ( dmesg ) 日志使用不同的时基,以自引导加载程序完成后的秒数标记日志项。要将此时间刻度注册到其他时间刻度,请搜索暂停退出暂停进入消息:

<6>[201640.779997] PM: suspend exit 2015-10-03 19:11:06.646094058 UTC
…
<6>[201644.854315] PM: suspend entry 2015-10-03 19:11:10.720416452 UTC

因为内核日志可能不包括挂起时的时间,所以您应该在挂起进入和退出消息之间分段注册日志。此外,内核日志使用 UTC 时区,并且必须调整为用户时区。

确定错误报告时间

要确定何时生成错误报告,首先检查系统日志 (Logcat) 中的dumpstate: begin

10-03 17:19:54.322 19398 19398 I dumpstate: begin

接下来,检查Starting service 'bugreport'消息的内核日志 ( dmesg ) 时间戳:

<5>[207064.285315] init: Starting service 'bugreport'...

向后工作以关联这两个事件,记住同步时间线中提到的注意事项。虽然在启动错误报告后发生了很多事情,但大多数活动并不是很有用,因为获取错误报告的行为会大量加载系统。

力量

事件日志包含屏幕电源状态,其中 0 为屏幕关闭,1 为屏幕开启,2 为键盘保护完成。

错误报告还包含有关唤醒锁的统计信息,这是应用程序开发人员用来指示他们的应用程序需要让设备保持开启的机制。 (有关唤醒锁的详细信息,请参阅PowerManager.WakeLockKeep the CPU on 。)

聚合的唤醒锁定持续时间统计信息跟踪唤醒锁定实际负责保持设备唤醒的时间,包括屏幕打开的时间。此外,如果同时持有多个唤醒锁,则唤醒锁持续时间将分布在这些唤醒锁上。

如需更多关于电源状态可视化的帮助,请使用Battery Historian ,这是一种使用 Android 错误报告文件分析电池消耗者的 Google 开源工具。

套餐

DUMP OF SERVICE package部分包含应用程序版本(和其他有用信息)。

流程

Bug 报告包含大量进程数据,包括启动和停止时间、运行时长、关联服务、 oom_adj分数等。有关 Android 如何管理进程的详细信息,请参阅进程和线程

确定流程运行时间

procstats部分包含有关进程和相关服务已运行多长时间的完整统计信息。如需快速、易于阅读的摘要,请搜索AGGREGATED OVER以查看过去 3 小时或 24 小时的数据,然后搜索Summary:以查看进程列表、这些进程在不同优先级下运行的时间以及它们的 RAM使用格式为 min-average-max PSS/min-average-max USS。

为什么一个进程正在运行?

dumpsys activity processes部分列出了所有当前正在运行的进程,按oom_adj分数排序(Android 通过为进程分配oom_adj值来指示进程重要性,该值可以由 ActivityManager 动态更新)。输出类似于内存快照的输出,但包含有关导致进程运行的原因的附加信息。在下面的示例中,粗体条目表示gms.persistent进程以vis (可见)优先级运行,因为系统进程绑定到其NetworkLocationService

扫描

使用以下步骤来识别执行过多蓝牙低功耗 (BLE) 扫描的应用程序:

  • 查找BluetoothLeScanner的日志消息:
    $ grep 'BluetoothLeScanner' ~/downloads/bugreport.txt
    07-28 15:55:19.090 24840 24851 D BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5
    
  • 在日志消息中找到 PID。在这个例子中,“24840”和“24851”是PID(进程ID)和TID(线程ID)。
  • 找到与 PID 关联的应用程序:
    PID #24840: ProcessRecord{4fe996a 24840:com.badapp/u0a105}
    

    在此示例中,包名称为com.badapp

  • 在 Google Play 上查找包名称以确定负责的应用程序: https ://play.google.com/store/apps/details?id=com.badapp。

注意:对于运行 Android 7.0 的设备,系统会收集 BLE 扫描数据并将这些活动与启动应用程序相关联。有关详细信息,请参阅低功耗 (LE) 和蓝牙扫描