4、内核日志分析:dmesg命令详解、内核日志级别、常见内核错误解读

好,咱们进入内核日志的世界。说实话,做Android系统层开发,如果看不懂dmesg,那就像医生看不懂X光片。很多疑难杂症,比如系统突然重启、死机、外设失灵,根因往往就藏在内核日志里。今天我就带你把它彻底搞明白。

4.1 dmesg命令详解:不只是敲个命令那么简单

dmesg 这个命令,说白了就是用来读取内核环形缓冲区(kernel ring buffer)的。内核在运行过程中,会不断往这个缓冲区里写消息,比如驱动加载、硬件中断、内存分配失败等等。我们用 dmesg 就能把这些消息倒出来看。

基本用法很简单,但有几个参数我建议你记牢:

# 查看所有内核日志
dmesg

# 实时监控内核日志(类似 logcat -v time)
dmesg -w

# 只看最后20条
dmesg | tail -20

# 按人类可读的时间戳显示
dmesg -T

# 清除内核环形缓冲区(谨慎使用!)
dmesg -c

我个人习惯,在抓取问题现场时,一定会先执行 dmesg -T > /data/dmesg_$(date +%Y%m%d_%H%M%S).log。为什么?因为 -T 参数能把内核启动以来的秒数转换成可读的时间,这样你才能和logcat里的时间对上号。

小技巧: 如果设备已经死机或重启了,你可以在下次开机后立刻执行 dmesg,因为内核环形缓冲区在重启后不会被清空(除非断电)。上次崩溃前的日志往往还在里面。

4.2 内核日志级别:一眼看出消息的紧急程度

内核日志有8个级别,从0到7,数字越小越紧急。我刚开始接触时也记不住,后来总结了个口诀:「越小的数字,越要命的错误」。

级别 名称 含义 常见场景
0 KERN_EMERG 紧急事件,系统不可用 内核panic、硬件故障
1 KERN_ALERT 必须立即处理 严重内存错误
2 KERN_CRIT 临界条件 驱动崩溃、IO错误
3 KERN_ERR 错误条件 设备初始化失败
4 KERN_WARNING 警告 资源不足、降级运行
5 KERN_NOTICE 正常但重要 挂载文件系统
6 KERN_INFO 信息性消息 驱动版本、硬件信息
7 KERN_DEBUG 调试信息 函数调用跟踪

你在dmesg输出里会看到类似 <3> 这样的前缀,那就是日志级别。比如 <3>[ 12.345] mmc0: error -110,说明这是一个KERN_ERR级别的错误。

重点: 排查问题时,我建议先用 dmesg | grep -E "<0>|<1>|<2>|<3>" 过滤出级别0-3的日志。这些才是真正需要关注的「硬伤」。

4.3 常见内核错误:panic、oops、watchdog

这三个词,做系统层的工程师听到都会心头一紧。我来逐个拆解。

4.3.1 Kernel Panic:最严重的系统崩溃

Kernel Panic,说白了就是内核遇到了无法恢复的错误,只能选择「自杀」——直接挂起整个系统。你会在屏幕上看到一堆调用栈,最后一行通常是 Kernel panic - not syncing: ...

我在项目中遇到过最典型的一次:某个低端设备在播放视频时频繁panic。最后定位到是GPU驱动在特定分辨率下访问了非法内存地址。嗯,这里要注意,panic日志里的PC指针(Program Counter)和LR寄存器(Link Register)是最关键的线索。

[  123.456] Kernel panic - not syncing: Fatal exception
[  123.457] CPU: 2 PID: 1234 Comm: mediaserver Tainted: P
[  123.458] Hardware name: Qualcomm Technologies, Inc. MSMxxxx
[  123.459] Call trace:
[  123.460]  [<ffffff800808c000>] dump_backtrace+0x0/0x1a0
[  123.461]  [<ffffff800808c1a0>] show_stack+0x20/0x30
[  123.462]  [<ffffff80086a5a10>] __schedule_bug+0x60/0x70
警告: 不要只看panic的最后一句话。前面的调用栈(Call trace)才是真正的「案发现场」。我曾经见过有人只盯着「not syncing」看了半天,完全忽略了上面那个 __schedule_bug 才是根因。

4.3.2 Kernel Oops:内核的「轻伤」

Oops比Panic轻一些。内核在遇到Oops时,会尝试继续运行,但系统已经处于不稳定状态。你想想看,内核的某个关键数据结构被破坏了,它还在硬撑着,这就像一个人腿断了还在走路——随时可能倒下。

Oops日志里通常会包含寄存器值、堆栈内容、以及出错的指令地址。我建议你重点关注 Unable to handle kernel NULL pointer dereferenceUnable to handle kernel paging request 这类描述。说白了,就是内核访问了一个不该访问的地址。

[  234.567] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010
[  234.568] Mem abort info:
[  234.569]   ESR = 0x96000046
[  234.570]   EC = 0x25: DABT (current EL), IL = 32 bits
[  234.571]   SET = 0, FnV = 0
[  234.572]   EA = 0, S1PTW = 0
[  234.573] Data abort info:
[  234.574]   ISV = 0, ISS = 0x00000046
[  234.575]   CM = 0, WnR = 1

这里有个避坑指南:我曾经在分析一个Oops时,看到 NULL pointer dereference 就以为是空指针问题。结果查了半天,发现是某个驱动在释放内存后没有把指针置NULL,导致野指针被再次使用。所以,遇到Oops,不仅要看地址,还要看是谁触发了这次访问。

4.3.3 Watchdog:系统的「看门狗」

Watchdog,直译就是看门狗。它是个硬件或软件定时器,内核需要定期去「喂狗」(重置定时器)。如果超过一定时间没喂狗,看门狗就会认为系统卡死了,然后强制重启。

常见的watchdog日志长这样:

[  345.678] watchdog: BUG: soft lockup - CPU#0 stuck for 22s!
[  345.679] Modules linked in: ...
[  345.680] CPU: 0 PID: 5678 Comm: kworker/u16:2
[  345.681] Call trace:
[  345.682]  [<ffffff80080a1234>] __do_softirq+0x100/0x200

为什么会发生soft lockup?说白了,就是某个CPU核心在22秒内没有切换任务,一直卡在某个中断处理或内核线程里。我遇到过最离谱的一次,是某个WiFi驱动在特定条件下进入了死循环,导致整个CPU被锁死。嗯,这里要注意,watchdog日志里的 stuck for 22s 这个时间是可以配置的,默认一般是20秒左右。

4.4 Kernel Log与Logcat的关联分析

这是实战中最关键的一环。很多同学只会单独看logcat或单独看dmesg,但真正的系统级问题,往往需要把两者结合起来。

我的做法是这样的:

  1. 时间对齐:先用 dmesg -T 把内核时间转换成系统时间,然后和logcat里的时间戳对比。注意,logcat用的是 YYYY-MM-DD HH:MM:SS.mmm 格式,而dmesg -T输出的是 [Mon Jan 1 12:34:56 2024] 格式,需要手动对齐。
  2. 寻找关联点:比如logcat里看到 E/Netd( 1234): Unable to connect to socket,那你就去dmesg里搜同一时间附近的网络驱动错误。我遇到过很多次,logcat里报的是应用层错误,根因其实是内核里的WiFi驱动挂了。
  3. 关注关键事件:系统重启前,logcat里通常会有 I/ServiceManager( 567): service 'xxx' died 之类的日志,而dmesg里则会有 Kernel panicwatchdog 的记录。把这两个时间点对上,就能确定是谁先出问题。
实战案例: 有一次客户反馈手机频繁重启。logcat里只看到 E/AndroidRuntime: Process com.android.phone died,看起来像是应用崩溃。但我习惯性地看了dmesg,发现每次重启前都有 watchdog: BUG: soft lockup - CPU#3 stuck for 22s!,而且卡住的位置都在同一个modem驱动里。最后定位到是基带固件的一个bug,在特定信号环境下导致内核死锁。如果只看logcat,这个问题永远查不出来。

最后,我建议你养成一个习惯:每次抓取logcat时,顺手把dmesg也抓下来。这两个日志就像人的「言行」——logcat是说的话(应用层行为),dmesg是身体状态(内核层健康)。只有两者结合,才能做出准确的诊断。