Android 日志系统
一、原理
Bugreport 日志
Bugreport是一个用于记录和收集Android设备上系统信息、日志和调试信息的工具。系统发生某些问题时,可以通过bugreport吧系统当前时刻点(运行BugReport的时刻)的系统相关的状态和信息保存下来。
Bugreport包含文本(.txt)格式的dumpsys(转储系统)、dumpstate(转储状态)、logcat数据。
1.1 具体收集的信息
-
设备软硬件信息
-
系统日志
-
系统运行状态,如cpu、内存、网络状态等
-
程序崩溃信息,如anr等
1.2 Bugreport产物的命名方式
文件命名形式:
bugreport-[device_name]-[build_id]-[localtime].zip
device_name:属性ro.product.name,默认为UNKNOW_DEVICE
build_id:属性ro.build.id的值,默认为UNKNOW_BUILD
local_time:抓取bugreport时的本地时间
1.3 实现原理:
adb bugreport会调用adbd,让adbd执行bugreportz -p的shell命令。bugreportz调用dumpstate -S,该命令会生成一个*.zip的bugreport文件。生成后,bugreportz会将生成的通知通过STDOUT_FILENO,告知adb。adb收到这个通知后,将对应的文件pull到Host上。

bugreport源码:
packages/modules/adb/client/main.cpp
packages/modules/adb/client/commandline.cpp
当adb识别到bugreport参数时,会通过Dolt函数向adbd发送”bugreportz -v”和”bugreportz -p”命令。执行bugreportz -v,获取bugreportz的版本,一方面是执行版本差异的流程,另一方面是作为Test,测试bugreportz是否可执行。Bugreportz -p调用dumpstate -S。(作用:收集系统当前时刻点的各种信息)
Logcat 日志
Logcat 日志是所有Logcat信息采用字符串形式的转储。其中,包括:System Log、Event Log等。
(1) System Log部分专门用于记录框架方面的信息,与包含所有其他内容的main部分相比,该部分包含更长时间内的记录。
每行都以timestamp PID TID log-level开头。
(2) Event Log中包含将二进制格式转换成了字符串形式的日志消息。在查看Event Log时,可以在这一部分中搜索特定进程ID,以查看相应进程一直在做什么。基本格式是:timestamp PID TID log-level log-tag tag-values。
日志级别包括以下几种:
<1>V:详细,最低严重级别
<2>D:调试
<3>I:信息
<4>W:警告
<5>E:错误
<6>F:严重错误
<7>S:静默(最高优先级,绝不会输出任何内容)
每条消息的前两列格式为:
相关的缓冲区为:
-
main:存储大多数应用日志
-
system:存储源自Android OS的消息
-
crash:存储崩溃日志、每个日志条目都包含一个优先级、一个表示日志来源的标记以及实际的日志消息
-
kernel:内核日志打印
2.1 日志缓冲区大小
O16U上ring buffer大小均为2MB

2.2 日志过滤级别
运行adb logcat显示的日志要经过四个级别的过滤:
编译时过滤:
根据编译设置,某些日志可能会从二进制文件中完全移除
系统属性过滤:
liblog会查询一组系统属性以确定要发送到logd的最低严重级别。如果日志具有MyApp标记,系统会检查以下属性,并且日志应包含最低严重级别的第一个字母
-
log.tag.MyApp
-
persist.log.tag.MyApp
-
log.tag
-
persist.log.tag
应用过滤:
如果未设置任何属性,liblog会使用__android_log_set_minimum_priority设置最低优先级。默认设置为INFO
2.3 logd源码
/system/logging/logd/main.cpp

二、用法
- Bugreport 日志
获取方法
- adb方式
- 数据线连接手机,adb devices 能够识别到手机
- 运行下面这行命令
adb bugreport- console方式
adb root
adb shell
bugreportz -p- Logcat 日志
2.1 过滤表达式
过滤表达式:tag:priority …格式,其中 tag 表示您感兴趣的标记,priority 表示可针对该标记报告的最低优先级。不低于指定优先级的标记的消息会写入日志。在一个过滤表达式中提供任意数量的 tag:priority 规范。一系列规范使用空格分隔。
以下是一个过滤表达式的示例,该表达式会抑制除标记为“ActivityManager”、优先级不低于“信息”的日志消息,以及标记为“MyApp”、优先级不低于“调试”的日志消息以外的所有其他日志消息:
adb logcat ActivityManager:I MyApp:D *:S上述表达式中最后一个元素 *:S 将所有标记的优先级设为“静默”,从而确保系统仅显示标记为“ActivityManager”和“MyApp”的日志消息。使用 :S 可确保日志输出受限于您已明确指定的过滤器。:S 可以让过滤器充当日志输出的“许可名单”。
注意:在某些 shell 中,“*****”字符已被 shell 预留。如果您使用的是此类 shell,请将过滤表达式用引号括起来:adb logcat “ActivityManager:I MyApp:D *:S”

2.2 命令行语法
如需通过 adb shell 运行 logcat,一般用法如下:
[adb] shell logcat [<option>] ... [<filter-spec>] ...
此外,还有一种 adb logcat 的简写形式,但它仅会扩展为 adb shell logcat。
选项
logcat 提供了很多选项。具体有哪些可用选项取决于您使用的设备的操作系统版本。如需查看特定于所用设备的 logcat 帮助,请执行以下命令:
adb logcat --help
请注意,由于 logcat 是面向操作系统开发者和应用开发者的工具(预计应用开发者会使用 Android Studio),因此许多选项只有在取得 root 权限的情况下才可使用。
2.3 控制日志输出格式
除标记和优先级外,日志消息还包含许多元数据字段。您可以修改消息的输出格式,以便它们显示特定的元数据字段。为此,请使用 -v 选项,并指定下列某一受支持的输出格式:
-
brief:显示优先级、标记以及发出消息的进程的 PID。
-
long:显示所有元数据字段,并使用空白行分隔消息。
-
process:仅显示 PID。
-
raw:显示不包含其他元数据字段的原始日志消息。
-
tag:仅显示优先级和标记。
-
thread::旧版格式,显示优先级、PID 以及发出消息的线程的 TID。
-
threadtime(默认值):显示日期、调用时间、优先级、标记、PID 以及发出消息的线程的 TID。
-
time:显示日期、调用时间、优先级、标记以及发出消息的进程的 PID。
启动 logcat 时,您可以使用 -v 选项指定所需的输出格式:
[adb] logcat [-v <format>]以下示例显示了如何生成输出格式为 thread 的消息:
adb logcat -v thread只能使用 -v 选项指定一种输出格式。不过,您可以视需要指定任意数量的有意义的修饰符。logcat 会忽略没有意义的修饰符。
2.4 格式修饰符
格式修饰符会更改 logcat 输出。如要指定格式修饰符,请使用 -v 选项,如下所示:
adb logcat -b all -v color -d每个 Android 日志消息都有一个与之相关联的标记和优先级。您可以将任何格式修饰符与以下任一格式选项进行组合:
-
brief:显示优先级、标记以及发出消息的进程的 PID。
-
long:显示所有元数据字段,并使用空白行分隔消息。
-
process:仅显示 PID。
-
raw:显示不包含其他元数据字段的原始日志消息。
-
tag:仅显示优先级和标记。
-
thread::旧版格式,显示优先级、PID 以及发出消息的线程的 TID。
-
threadtime(默认值):显示日期、调用时间、优先级、标记、PID 以及发出消息的线程的 TID。
-
time:显示日期、调用时间、优先级、标记以及发出消息的进程的 PID。
如要获取以下格式修饰符详细信息,请在命令行中输入 logcat -v —help。
-
color:使用不同的颜色来显示每个优先级。
-
descriptive:显示日志缓冲区事件说明。此修饰符仅影响事件日志缓冲区消息,不会对其他非二进制文件缓冲区产生任何影响。事件说明取自 event-log-tags 数据库。
-
epoch:显示自 1970 年 1 月 1 日以来的时间(以秒为单位)。
-
monotonic:显示自上次启动以来的时间(以 CPU 秒为单位)。
-
printable:确保所有二进制日志记录内容都进行了转义。
-
uid:如果访问权限控制允许,则显示 UID 或记录的进程的 Android ID。
-
usec:显示精确到微秒的时间。
-
UTC:显示世界协调时间 (UTC)。
-
year:将年份添加到显示的时间。
-
zone:将本地时区添加到显示的时间。
2.5 查看备用日志缓冲区
Android 日志记录系统为日志消息保留了多个环形缓冲区,而且并非所有的日志消息都会发送到默认的环形缓冲区。如要查看其他日志消息,您可以使用 -b 选项运行 logcat 命令,以请求查看备用的环形缓冲区。您可以查看下列任意备用缓冲区:
-
radio:查看包含无线装置/电话相关消息的缓冲区。
-
events:查看已经过解译的二进制系统事件缓冲区消息。
-
main:查看主日志缓冲区(默认),不包含系统和崩溃日志消息。
-
system:查看系统日志缓冲区(默认)。
-
crash:查看崩溃日志缓冲区(默认)。
-
all:查看所有缓冲区。
-
default:报告 main、system 和 crash 缓冲区。
以下是 -b 选项的用法:
[adb] logcat [-b <buffer>]以下示例显示了如何查看包含无线装置和电话相关消息的日志缓冲区。
adb logcat -b radio如需为要输出的所有缓冲区指定多个 -b 标记,请输入以下命令:
logcat -b main -b radio -b events指定一个-b标记,后跟缓冲区的逗号分隔列表,例如:
logcat -b main,radio,events2.6 通过代码记录日志
借助 Log 类,您可以在代码中创建日志条目,而这些条目会显示在 logcat 工具中。常用的日志记录方法包括:
-
[Log.v(String, String)](https://developer.android.com/reference/android/util/Log?hl=zh-cn#v(java.lang.String, java.lang.String))(详细)
-
[Log.d(String, String)](https://developer.android.com/reference/android/util/Log?hl=zh-cn#d(java.lang.String, java.lang.String))(调试)
-
[Log.i(String, String)](https://developer.android.com/reference/android/util/Log?hl=zh-cn#i(java.lang.String, java.lang.String))(信息)
-
[Log.w(String, String)](https://developer.android.com/reference/android/util/Log?hl=zh-cn#w(java.lang.String, java.lang.String))(警告)
-
[Log.e(String, String)](https://developer.android.com/reference/android/util/Log?hl=zh-cn#e(java.lang.String, java.lang.String))(错误)
2.7 小米内部的日志打印函数及输出位置
Slog

输出位置:/dev/log/main,有/data/local/log目录的,可以保存3-4天的log(可以使用adb logcat命令查看)
Alog

输出位置:与slog一致,也可以使用adb logcat来查看

三、参考文献
官方文档:Logcat 命令行工具