4.4.7. Log 系统介绍
4.4.7.1. Linux log 系统简介
Linux 的
日志
缓冲区 :日志缓冲区(log buffer)是 日志 系统 的 核心 组件。 日志
写入 :通过printk、printk_deferred、devkmsg_write、dev_printk_emit等接口 将 日志 写入 日志 缓冲区。 日志
提取 :通过注册 的 控制台(console)、 /dev/kmsg以及syslogd来提取 日志 信息。
这

log buffer
在 Linux 系统
log buffer 作为__LOG_BUF_LEN 的
// kernel/printk.c
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) // 即 2 的 CONFIG_LOG_BUF_SHIFT 次幂
static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
而 __LOG_BUF_LEN 受 CONFIG_LOG_BUF_SHIFT 影响,CONFIG_LOG_BUF_SHIFT 在 kernel config 中

可以CONFIG_LOG_BUF_SHIFT 大小CONFIG_LOG_BUF_SHIFT,然后
需要CONFIG_LOG_BUF_SHIFT 的
# init/Kconfig
config LOG_BUF_SHIFT
int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
range 12 25
default 17
depends on PRINTK
help
Select the minimal kernel log buffer size as a power of 2.
The final size is affected by LOG_CPU_MAX_BUF_SHIFT config
parameter, see below. Any higher size also might be forced
by "log_buf_len" boot parameter.
Examples:
17 => 128 KB
16 => 64 KB
15 => 32 KB
14 => 16 KB
13 => 8 KB
12 => 4 KB
log 写入接口
printk 函数
printk 是 Linux 内核printf 类似,但printk 是
1) printk 基本
printk 是 Linux 内核
int printk(const char *fmt, ...);
fmt:格式化字符串,类似 于 printf的格式化 字符串。 后续
的 参数:与 格式化 字符串 相对 应 的 数据。
printk 的printf 相似,但是
2)printk 的
printk 支持
KERN_EMERG(0):紧急事件消息,通常 用于 系统 崩溃 或 严重错误。这些 消息 会 立即 打印,并 可能 触发 系统 重启。 KERN_ALERT(1):警报消息,表示 需要 立即 处理 的 严重 系统 问题。 KERN_CRIT(2):严重错误消息,通常 用于 严重 的 硬件 或 软件 操作 失败。 KERN_ERR(3):错误消息,表示 需要 进一步 调试 或 处理 的 系统 错误,驱动程序 常用 此 级别 报告 硬件 错误。 KERN_WARNING(4):警告消息,表示 可能 存在 但 通常 不会 导致系统 崩溃 的 问题。 KERN_NOTICE(5):通知消息,表示 正在 执行 的 重要 操作,但 不 属于 错误 或 警告,常用 于 安全 相关 提示。 KERN_INFO(6):提示信息,表示正常 的 操作 或 状态 变更,例如 驱动程序 启动 时 打印 的 硬件 信息。 KERN_DEBUG(7):调试信息,用于开发 过程 中 输出 详细 的 调试信息。
示例:
printk(KERN_INFO "Device initialized successfully.\n");
printk(KERN_ERR "Failed to allocate memory for device.\n");
printk(KERN_DEBUG "Debugging device register read.\n");
如default_message_loglevel,默认KERN_WARNING 级别
// kernel/include/linux/printk.h
#define default_message_loglevel (console_printk[1])
/* printk's without a loglevel use this.. */
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT
// kernel/kernel/printk/printk.c
int console_printk[4] = {
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */
CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
};
default_message_loglevel 的MESSAGE_LOGLEVEL_DEFAULT ,而 MESSAGE_LOGLEVEL_DEFAULT 是

MESSAGE_LOGLEVEL_DEFAULT 的
# lib/Kconfig.debug
config MESSAGE_LOGLEVEL_DEFAULT
int "Default message log level (1-7)"
range 1 7
default "4"
help
Default log level for printk statements with no specified priority.
This was hard-coded to KERN_WARNING since at least 2.6.10 but folks
that are auditing their logs closely may want to set it to a lower
priority.
Note: This does not affect what message level gets printed on the console
by default. To change that, use loglevel=<x> in the kernel bootargs,
or pick a different CONSOLE_LOGLEVEL_DEFAULT configuration value.
3)printk 的
printk 函数printk,并且
但是,printk 的logbuf_lock)来printk。
4)动态
内核printk 的/sys/kernel/debug/dynamic_debug/control 文件
echo "file drivers/net/* +p" > /sys/kernel/debug/dynamic_debug/control
这会drivers/net/ 目录
要dynamic_debug/control 文件-p。示例
echo "file drivers/net/* -p" > /sys/kernel/debug/dynamic_debug/control
5)printk 的
有时,日志
printk_once:确保某个 日志 只 打印 一次,无论 函数 被 调用 多少 次。这 适用 于 只 需要 打印 一次 的 错误信息。 printk_once("This error message will be printed only once.\n");
printk_ratelimited:限制日志 输出 的 频率。默认 情况 下,内核 每 5 秒 最 多 打印 10 次 相同 的 错误信息。这 对于 那些 重复 触发 的 错误 非常 有用,能够 减少 日志 的 冗余 输出。 printk_ratelimited("Resource usage high, please check.\n");
驱动中常用的日志接口
内核struct device)进行
在
dev_err、dev_warn、dev_info、dev_dbg
这struct device 结构dev(设备
dev_errdev_err(dev, fmt, ...)用于打印 错误信息,通常 在 设备 操作 失败 或者 发生 严重错误 时 使用。此 函数 会 将 错误信息 输出 到 系统日志 中,供 开发人员 进行 问题 排查。 示例:
dev_err(dev, "Failed to initialize device: %d\n", ret);
dev_warndev_warn(dev, fmt, ...)用于打印 警告 信息,适用 于 非 致命 的 错误 或 异常 情形,提示 系统 存在 潜在 问题 但 不 影响 设备 的 继续 运行。 示例:
dev_warn(dev, "Device is running low on resources\n");
dev_infodev_info(dev, fmt, ...)用于打印 常规 信息 或 状态 报告。适用 于 设备 初始化、状态 变更 等 较为 普通 的 日志 输出。 示例:
dev_info(dev, "Device initialized successfully\n");
dev_dbgdev_dbg(dev, fmt, ...)用于打印 调试信息,适合 开发 和 调试 阶段 使用,提供 详细 的 设备 操作 信息。注意, dev_dbg一般默认 会 被 禁用,因此 它 仅 在 调试模式 下 有效。 示例:
dev_dbg(dev, "Reading register value: 0x%X\n", value);
上述
关联性
强:这些 接口 与 设备 结构 体 dev 绑定,能够 清晰 地 记录 哪个 设备 发生 了 什么 事件,方便 调试 和 排查 问题。 日志
级别 区分 明确:根据 不同 的 日志 级别(错误、警告、信息、调试),可以 有效 地 控制 日志 的 详细 程度。 便于
扩展 与 维护:使用 这些 设备 相关 的 接口,可以 保证 日志 格式 的 一致性,增强 代码 的 可维护性。
无设备结构时使用的接口
在pr_err、pr_warn、pr_info、pr_debug。
pr_err(fmt, ...):用于输出 错误信息。 示例:
pr_err("Memory allocation failed\n");
pr_warn(fmt, ...):用于输出 警告 信息。 示例:
pr_warn("The configuration value is set to the default\n");
pr_info(fmt, ...):用于输出 普通 信息。 示例:
pr_info("Kernel module loaded successfully\n");
pr_debug(fmt, ...):用于输出 调试信息,适合 开发阶段。 示例:
pr_debug("Debugging internal state: %d\n", state);
pr_debug 和 dev_dbg 等
echo "file drivers/mmc/host/* +p" > /sys/kernel/debug/dynamic_debug/control
应用程序 log 接口
推荐
使用 ALOG 的 接口,对应 的 打印 级别 有 ALOGV、 ALOGD、 ALOGI、 ALOGW、 ALOGE、 ALOGV_TAG、 ALOGD_TAG、 ALOGI_TAG、 ALOGW_TAG、 ALOGE_TAG、 ALOGF_TAG。 使用 ALOG* 接口
时,各个 模块 在 输出 Log 时,可以 通过 定义 LOG_TAG 宏来 打印 自身 模块 名, logcat 支持 使用 tag 筛选 日志。其 可 通过 Makefile 传入,如: DLOG_TAG=camera;或者 在 代码 开头 声明。 使用 ALOG*_TAG 接口
时,各个 模块 在 输出 Log 时,可以 通过 第一个 参数 来 打印 自身 模块 名, logcat 支持 使用 tag 筛选 日志。 log 系统
支持 1 个 2MB 的 log_main 缓冲区, 1 个 256KB 的 log_radio、 log_system 和 log_event 和 缓冲区,建议 使用 log_main 缓冲区。 当 bufID 是 LOG_ID_RADIO 时,日志
保存 到 log_radio 缓冲区, bufID 是 LOG_ID_SYSTEM 时,日志 保存 到 log_system 缓冲区,默认 则 是 log_main 缓冲区。
代码
完整
#define LOG_TAG "alog_test"
#include <stdio.h>
#include <logging.h>
int main(int argc, char *argv[])
{
printf("\n logcat test !!!!!!!!!!!!!!!\n");
if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
logprint_run_tests();
exit(0);
}
if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
android::show_help(argv[0]);
exit(0);
}
printf("\n LogV LogD test start!!! \n");
ALOGV("**************************ALOGV test start***************************");
ALOGV("**************************1***************************");
ALOGV("**************************2***************************");
ALOGV("**************************3***************************");
ALOGV("**************************4***************************");
ALOGV("**************************5***************************");
ALOGV("**************************ALOGV test end ***************************");
ALOGD("**************************ALOGV test start***************************");
ALOGD("**************************1***************************");
ALOGD("**************************2***************************");
ALOGD("**************************3***************************");
ALOGD("**************************4***************************");
ALOGD("**************************5***************************");
ALOGD("**************************ALOGV test end ***************************");
RLOGV("**************************RLOGV test log_radio start***************************");
RLOGD("**************************1*****************************************************");
RLOGE("**************************RLOGV test log_radio end******************************");
SLOGV("**************************SLOGV test log_system start***************************");
SLOGD("**************************2*****************************************************");
SLOGE("**************************RLOGV test log_system end**************************** *");
printf("\n LogV LogD write test success!!! \n");
return 0;
}
测试
# ./logtest
不设置过滤:
# logcat
logcat test start !!!
--------- beginning of /dev/log_main
V/alog_test(21590): *ALOG test start*
D/alog_test(21590): ********1********
I/alog_test(21590): ********2********
W/alog_test(21590): ********3********
E/alog_test(21590): ********4********
V/tag (21590): ********1********
D/tag (21590): ********1********
I/tag (21590): ********2********
W/tag (21590): ********3********
E/tag (21590): ********4********
F/tag (21590): ********1********
V/alog_test(21590): *ALOG test end***
设置过滤 -s *:F
# logcat -s *:F
logcat test start !!!
--------- beginning of /dev/log_main
F/tag (21590): ********1********
设置过滤 -s *:E
# logcat -s *:E
logcat test start !!!
--------- beginning of /dev/log_main
E/alog_test(21590): ********4********
E/tag (21590): ********4********
F/tag (21590): ********1********
设置过滤 -s tag:E
# logcat -s tag:E
logcat test start !!!
--------- beginning of /dev/log_main
E/tag (21590): ********4********
F/tag (21590): ********1********
切换缓存区为 log_radio:
logcat test start !!!
--------- beginning of /dev/log_radio
V/ ( 1319): **************************RLOGV test log_radio start***************************
D/ ( 1319): **************************1*****************************************************
E/ ( 1319): **************************RLOGV test log_radio end******************************
切换缓存区为 log_system:
logcat test start !!!
--------- beginning of /dev/log_system
V/ ( 1319): **************************SLOGV test log_system start***************************
D/ ( 1319): **************************2*****************************************************
E/ ( 1319): **************************RLOGV test log_system end**************************** *
logcat 命令
| 参数 | 描述 | |
|---|---|---|
| 1 | -b <buffer> |
加载 |
| 2 | -c |
清除-g 查看 |
| 3 | -d |
将 |
| 4 | -f <filename> |
将 log 输出<文件名>,默认 |
| 5 | -g |
打印 |
| 6 | -n <count> |
设置<count>,默认值-r 选项 |
| 7 | -r <kbytes> |
每<kbytes> 时-f 选项 |
| 8 | -s |
设置 |
| 9 | -v <format> |
设置 |
log 提取
在 Linux 系统console、/dev/kmsg 和 syslogd 提取
Console(控制台)
console 是
一般console 有 uart、net、pstore,但是
控制台
实时
显示 :控制台输出 是 直接 显示 在 终端 上 的,通常 用于 用户 交互式 的 系统诊断。 内核
消息 :通过printk()等函数 输出 的 内核 日志 信息 会 被 发送到 控制台。控制台 显示 的 日志 包括 启动 过程 中 的 内核 日志、硬件 信息、错误信息 等。 多
控制台 :Linux 支持支持 多个 虚拟 控制台(如 /dev/tty1到/dev/tty6)。用户可以 在 这些 虚拟 终端 中 查看 日志 信息,或者 通过 dmesg命令查看 内核 环形 缓冲区 中 的 日志。 控制台
日志 :内核级别 允许 用户 设置 不同 的 日志 级别 来 控制 哪些 信息 输出 到 控制台。可以 通过 内核 启动 参数 或者 运行 时 修改 console_loglevel变量来 配置 输出 的 详细 程度。
控制台
在dmesg 命令
先
root@buildroot:~# cat /proc/sys/kernel/printk
6 4 1 6
这console_loglevel、default_message_loglevel、minimum_console_loglevel 以及 default_console_loglevel。
console_loglevel:控制台使用 的 日志 级别; default_message_loglevel:调用 printk() 未指定日志 级别 时 使用 的 日志 级别; minimum_console_loglevel:允许设置 的 控制台 日志 级别(console_loglevel)最小值; default_console_loglevel:系统启动时 使用 的 日志 级别。
通常default_console_loglevel 和 console_loglevel 为 4 的
在
1) 修改 proc/sys/kernel/printk
echo "8" > /proc/sys/kernel/printk
上述8,显示
2)dmesg 命令
dmesg 是
dmesg -n <value> 和 echo x > proc/sys/kernel/printk 能够
dmesg -n 7
dmesg 命令
| 选项 | 描述 |
|---|---|
-C, --clear |
清空 |
-c, --read-clear |
读取 |
-D, --console-off |
禁用 |
-E, --console-on |
启用 |
-F, --file <file> |
使用 |
-f, --facility <list> |
限制 |
-H, --human |
显示 |
-J, --json |
使用 JSON 输出 |
-k, --kernel |
显示 |
-L, --color[=<when>] |
启用 |
-l, --level <list> |
限制 |
-n, --console-level <level> |
设置 |
-P, --nopager |
不 |
-p, --force-prefix |
强制 |
-r, --raw |
打印 |
--noescape |
不 |
-S, --syslog |
强制 |
-s, --buffer-size <size> |
设置 |
-u, --userspace |
显示 |
-w, --follow |
等待 |
-W, --follow-new |
等待 |
-x, --decode |
解码 |
-d, --show-delta |
显示 |
-e, --reltime |
显示 |
-T, --ctime |
显示 |
-t, --notime |
不 |
--time-format <format> |
使用 |
--since <time> |
显示 |
--until <time> |
显示 |
-h, --help |
显示 |
-V, --version |
显示 |
支持
| 设施 | 描述 |
|---|---|
kern |
内核 |
user |
随机 |
mail |
邮件系统 |
daemon |
系统 |
auth |
安全/授权 |
syslog |
syslogd 生成 |
lpr |
打印机 |
news |
网络新闻 |
支持
| 级别 | 描述 |
|---|---|
emerg |
系统 |
alert |
必须 |
crit |
严重 |
err |
错误 |
warn |
警告 |
notice |
正常 |
info |
信息性 |
debug |
调试 |
/dev/kmsg
/dev/kmsg 是 Linux 中
/dev/kmsg 的
查看
内核 : 可以日志 通过 cat命令查看 /dev/kmsg中的 日志: sudo cat /dev/kmsg
该
命令 将 输出 内核 日志 的 内容,包括 通过 printk()打印的 所有 日志 信息。 cat /dev/kmsg和dmesg -w的执行 效果 相似,它们 都 用于 实时 显示 内核 日志。 写入
内核 : 可以日志 使用 echo 命令 将 消息 写入 内核 日志。例如: echo "Custom log message from user space" | sudo tee /dev/kmsg dmesg | tail -n 5
许多rsyslog 或 systemd-journald)会/dev/kmsg 文件
注意,与 dmesg 不同, 第一次sudo cat /proc/kmsg 打印sudo cat /proc/kmsg 时,则
syslogd
syslogd(System Log Daemon)是
syslogd 的
1980年代
初:syslog 出现,作为 Unix 系统日志 的 基础,syslogd 守护 进程 负责 处理 日志。 1983年:syslog 被
引入 到 BSD 4.2 Unix 系统 中,成为 标准化 的 日志 管理工具。 1990年代:syslogd 在 Unix 和 Linux 系统
中 得到 广泛应用,并 开始 支持 远程 日志 转发。 2000年代:rsyslog 作为 syslogd 的
增强 版本,提供 了 更 多功能,如 高性能、日志 加密、数据库 集成 等。 2010年代:systemd 作为
现代 Linux 系统 的 核心 组件,逐步 取代 了 传统 的 syslogd,引入 了 systemd-journald,但 依然 兼容 传统 的 syslog 协议。
syslogd 配置
内核/etc/syslog-startup.conf 文件
# This configuration file is used by the busybox syslog init script,
# /etc/init.d/syslog[.busybox] to set syslog configuration at start time.
DESTINATION=file # log destinations (buffer file remote)
LOGFILE=/userdata/log/kernel/message # where to log (file)
REMOTE=loghost:514 # where to log (syslog remote)
REDUCE=no # reduce-size logging
DROPDUPLICATES=no # whether to drop duplicate log entries
BUFFERSIZE=64 # size of circular buffer [kByte]
FOREGROUND=no # run in foreground (don't use!)
#LOGLEVEL=5 # local log level (between 1 and 8)
下面
DESTINATION=file含义:定义
日志 的 目标 地点,可以 是 file(日志文件)、 buffer(环形缓冲区)或 remote(远程 syslog 服务器)。解释:此
配置 项 设置 了 日志 记录 的 目标 为 文件。这 意味着 日志 将 被 写入 指定 的 文件,而 不是 仅 存在 内存 缓冲区 或 通过 网络 发送到 远程 服务器。
LOGFILE=/userdata/log/kernel/message含义:指定
日志 文件 的 路径。 解释:这个
配置 项 设置 了 日志 文件 的 存储 路径 为 /userdata/log/kernel/message。系统将 在 此 文件 中 存储 日志 信息。如果 DESTINATION配置为 file,则该 文件 是 实际 的 日志 输出 文件。
REMOTE=loghost:514含义:指定
远程 syslog 服务器 的 地址 和 端口。 解释:如果
选择 DESTINATION=remote,则日志 将 被 发送到 指定 的 远程 主机。在 这里,日志 将 被 发送到 loghost主机的 514 端口(默认 的 syslog 端口)。此项 配置 可能 用于 将 日志 信息 转发 到 集中管理 的 远程 日志 服务器。
REDUCE=no含义:是否
减少 日志 的 大小。 解释:这个
选项 决定 是否 进行 日志 压缩 或 其他 方式 减少 日志 的 大小。设置 为 no表示不 压缩 日志,日志 将 按 原样 存储。
DROPDUPLICATES=no含义:是否
丢弃 重复 的 日志 条目。 解释:该
选项 控制 是否 在 日志 中 丢弃 重复 的 条目。 no表示不 丢弃 重复 条目,因此 日志 中 可能 包含 相同 的 日志 消息 多次。
BUFFERSIZE=64含义:环形
缓冲区 的 大小(以 KB 为 单位)。 解释:指定
用于 存储 日志 的 环形 缓冲区 的 大小,这里 设置 为 64KB。环形 缓冲区 是 一个 有限 大小 的 缓冲区,用于 临时 存储 日志 数据,缓冲区 满 时会 覆盖 最 旧 的 日志 条目。
FOREGROUND=no含义:是否
在 前台 运行 syslog。解释:设置
为 no表示syslog将在 后台 运行,而 不是 在 前台 运行。通常 情况 下,后台 运行 服务 不会 阻塞 终端,而 前台 运行 服务 则 会 占用 终端 并 输出 日志。
#LOGLEVEL=5含义:设置
本地 日志 级别(1 到 8),和 printk的日志 级别 一致。 解释:这
一行 被 注释 掉 了,因此 没有 被 启用。 LOGLEVEL配置项 允许 设置 本地 日志 的 详细 级别,数值 从 1 到 8,数字 越大,日志 输出 越 详细。通常,级别 5 表示“警告”级别 的 日志,显示 重要 的 警告 和 错误信息。
/etc/syslog-startup.conf 最终/etc/init.d/S91syslogd 脚本
syslogd 日志
配置/etc/syslog-startup.conf 并syslogd 或 klogd 后,一般/userdata/log/kernel/message 中。
下面
root@buildroot:~# cat /userdata/log/kernel/message
Jan 1 00:00:04 buildroot kern.debug kernel: [ 0.140925] dr-power-domain 31030000.power-controller: Looking up bpu-supply from device tree
Jan 1 00:00:04 buildroot kern.info kernel: [ 0.141973] horizon-aon-pinctrl 31040000.aon_iomuxc: Initialized D-Robotics pinctrl driver
Jan 1 00:00:04 buildroot kern.err kernel: [ 0.144257] (NULL device *): no horizon,gpio-banks in node /soc/disp_apb/disp_iomuxc@3e0a0054
……
Jan 1 00:51:52 buildroot user.notice ptp4l: [3112.607] selected local clock 8ea1d5.fffe.4ca67d as best master
Jan 1 00:51:55 buildroot kern.debug kernel: [ 3115.366849] sdhci-dwcmshc 35040000.sdhci: dwcmshc_runtime_resume
Jan 1 00:51:55 buildroot kern.debug kernel: [ 3115.366971] sdhci-dwcmshc 35040000.sdhci: Get fixed-drv-type: 2
/userdata/log/kernel/message 文件
<timestamp> <hostname> <level> <label>: [duration] <message>
以
Jan 1 00:51:52 buildroot user.notice ptp4l: [3112.607] selected local clock 8ea1d5.fffe.4ca67d as best master
timestamp (时间
戳) :Jan 1 00:51:52,日志消息 的 记录时间,通常 包括 月份( MMM)、日期(dd)和时间( hh:mm:ss)。hostname (主机名):
buildroot,产生该 日志 消息 的 主机名。 level (日志
级别) :user.notice,表示日志 消息 的 级别,这里 表示 这是 一条 来自 用户 的 notice 级别 信息。 label (标签):
ptp4l,表示产生 该 日志 的 进程、服务 或 系统 组件 的 名称,这里 表示 消息 来自 PTP 时间 同步 守护 进程。 duration (持续时间):
[3112.607],它表示 在 系统启动 后 持续 的 第 3112.607 秒 打印 的 该 日志。 message (消息
内容) :selected local clock 8ea1d5.fffe.4ca67d as best master,日志消息 的 具体内容。
有关 syslogd 的
4.4.7.2. log 目录结构
log 分区
本
| log 类型 | 存储 |
单个 log 大小 | 是否 |
内容 | |
|---|---|---|---|---|---|
| 基础 |
kernel | /userdata/log/kernel | 2M | 否 | 内核 log 信息 |
| pstore | /userdata/log/pstore | 最大3M | 否 | 内核 crash 的 log 信息 | |
| coredump | /userdata/log/coredump | 未 |
否 | 应用 crash 的 log 信息 | |
| remoteproc | /userdata/log/dsp | 2M | 否 | DSP 输出 |
|
| uboot | /userdata/log/uboot | 4KB | 否 | uboot 输出 |
|
| reset | /userdata/log/reset_reason.txt | 1M | 否 | 记录 |
|
| /userdata/log/reset_count.txt | 4KB | 否 | 记录 |
||
| ALOG 系统 | ALOG | /userdata/log/usr | 2M | 否 | 应用 |
log 分区内容说明
Kernel log
内核 log:通过 klogd 和 syslogd 转存
到 /userdata/log/kernel 目录 下 pstore log:当
内核 crash 重启 时,移动 /sys/fs/pstore 目录 日志 到 /userdata/log/pstore 目录 下,记录 系统 panic 前后 的 内核 日志
启动
原因 log reset-reason.txt 信息
介绍 COLD_BOOT: 掉电上电 UBOOT_RESET: uboot 下中的 重启 PANIC:发生了 panic WATCHDOG: 触发了 watchdog REBOOT_CMD: kernel 下的 reboot 命令
reset_count.txt:当前
系统 重启 次数
remoteproc log
dsp:ADSP 输出
的 log 信息
ALOG 系统
使用 ALOG 的
接口 打印 的 log 信息 应用软件
推荐 使用 ALOG 接口
应用 crash log
coredump:储存
进程 运行 时 在 突然 崩溃 的 那一刻 的 一个 内存 快照,会 把 进程 此刻 内存、寄存器 状态、运行 堆栈 等 信息 转储 保存 在 该 目录 文件 中
4.4.7.3. log 管理
log 进程
log 进程信息说明
板端 log 进程
运行 信息 # ps -aux | grep log root 817 0.0 0.2 3852 2764 ? S 00:00 0:00 /bin/bash /usr/bin/hobot-log start root 826 0.0 0.0 3008 332 ? S 00:00 0:02 /sbin/syslogd -n -O /userdata/log/kernel/message -s 2048 -b 99 root 892 0.0 0.0 2724 332 ? S 00:00 0:00 /usr/hobot/bin/hrut_remoteproc_log -b dsp -f /userdata/log/dsp/message -r 2048 -n 50 root 896 0.0 0.1 5088 1756 ? S 00:00 0:00 /usr/hobot/bin/logcat -v time -f /userdata/log/usr/message -r2048 -n 100 root 900 0.0 0.0 3008 308 ? S 00:00 0:01 /sbin/klogd -n
kernel: klogd+syslogd
获取
内核 记录 的 消息,将 消息 数据 转存 成 文件。
usr: ALOG(libalog.so)+logcat
通过 ALOG 接口
向 log buffer 写入 log 信息,logcat 从 log buffer 中 提取 数据 到 文件 中。
remoteproc_log:hrut_remoteproc_log 进程
log 记录:通过 remoteproc 节点
获取 ADSP 的 log 信息,将 其 写入 文件 中。 log 管控:根据
输入 参数 中 的 log 文件大小 和 数量 限制 去 管控 log 的 存储空间。
日志
管理:hobot-log log 记录:记录 reset,pstore,uboot 的 log 信息。
log 管理:定期
将 原始 log 文件 转存 成 固定 格式文件,管控 各个 分区 目录 的 存储空间,超过 固定 容量 会 进行 删除,删除 时间 比较 早 产生 的 文件。
log 进程启动顺序说明
挂载/etc/init.d/ 目录
S90log_daemon
S91syslogd
S92hobot_log_start
S92klogd
执行
|- etc/init.d/S90log_daemon
|- /usr/bin/hobot-log first //转储上次启动的日志信息
|- record_reset_count(shell function)
|- system_config(shell function)
|- wait_for_timesync(shell function)
|- record_reset_reason(shell function)
|- set_pstore(shell function)
|- set_uboot(shell function)
|- check_first_log(shell function)
|- /usr/bin/hobot-log
|- check_log(shell function, major cycle)
|- /etc/init.d/S91syslogd
|- /sbin/syslogd -n $SYSLOG_ARGS
|- /etc/init.d/S92hobot_log_start
|- /usr/bin/hrut_remoteproc_log -b dsp
|- logcat -v time
|- /etc/init.d/S92klogd
|- /sbin/klogd -n $KLOGD_ARGS
log 管理方式
log 的/usr/bin/hobot-log 脚本
hobot-log 脚本简介
hobot-log 脚本
log 生成:
系统
每次 启动 时去 转存 log,log 文件 命名 格式 如下 X5_Uboot-count-time.Log:当
系统启动 时,将 uboot log 转存 到 /userdata/log/uboot/archive目录下 X5_Pstore-count-time(文件夹):当
系统启动 时,如果 检测 到 上次 系统 是 异常 重启,则 创建 该 格式 文件夹,并 将 对应 的 异常 log 信息 记录 到 该 文件夹 下
系统
运行 过程 中 每10分钟 去 转存 log,文件 转存 到 各个 模块 的 archive 目录 下,log 文件 命名 格式 如下: X5_Kernel-count-time_<inode>.Log
X5_Usr-count-time_<inode>.Log
X5_Bl31-count-time_<inode>.Log
X5_Dsp0-count-time_<inode>.Log
X5_Dsp1-count-time_<inode>.Log
X5_Mcore-count-time_<inode>.Log
log 文件
命名 格式 解析 示例: 以 /userdata/log/kernel/archive目录中 的 日志 文件 X5_Kernel-0003-2022_05_01_08_01_00_131599.Log为例进行 说明。 命名
说明: [board]_[module]-[count]-[time]_<inode>.Logboard: X5
module: Kernel, Usr, Dsp, Uboot, Pstore。首字母
大写 count: 4位
数字,0000到9999,示例 中 代表 第3次 重启 time:如2022_05_01_08_01_00
inode:如131599。正常
情况 下 没有,只有 当 出现 同一时间 转存 多个 文件 命名 存在 重合 时,加入 inode 节点 来 做 区分
容量
管控: 一
开始 划分 不同 的 log 目录 空间 容量,每10分钟 针对 指定 的 目录 容量 去 检索 空间,如果 容量 超过,将会 按照 文件 生成 时间 排序,删除 产生 时间 比较 早 的 文件 hobot-log
管理
着 usr、kernel、remoteproc_log、pstore、uboot 的 空间,对应 的 数量 限制 由 内部 参数 设定。 其中,每个 类型 日志 文件大小 说明 见 log 分区,usr、kernel、pstore、uboot 日志 文件系统 默认 的 数量 限制 为100个,dsp 日志 文件系统 默认 的 数量 限制 为50个。 hobot-log脚本中 相关 内容 定义 如下: ROTATESIZE=2048 #KB ROTATEGENS_KER=100 ROTATEGENS_USR=100 ROTATEGENS_REMOTE=50 ROTATEGENS_CHIP=50 ROTATEGENS_ALL=$((${ROTATEGENS_REMOTE} + ${ROTATEGENS_KER} + ${ROTATEGENS_USR} + ${ROTATEGENS_CHIP})) ROTATESIZE_BYTES=$((${ROTATESIZE} * 1024)) PSTORE_LOGMAX=100
通过
这样 的 配置 可以 实现 日志 轮换,当 日志 文件 达到 一定 大小(当前 设定值 为 2048KB)时,系统 会 将 当前 的 日志 文件 重命名,并 创建 一个 新 的 日志 文件 来 继续 记录 新 的 日志 消息。并且 限制 了 保存 的 总 文件 数量,在 达到 设置 的 文件 数量 上限 会 根据 时间 戳 顺序 删除 最早 日志,这样 可以 防止 日志 文件 无限 增长,占用 过多 的 磁盘空间。 hrut_remoteproc_log:
log 的
大小 和 数量 也 是 由 进程 自身 管理 的,对应 的 参数 配置 是 hobot-log 中 去 设置 的
用户定制 log 系统
日志
命名 修改 在 hobot-log 中
修改,具体 的 修改 功能 逻辑 是 check_log函数实现 的 $1:log 产生
的 原始 目录 $2:log 根据
原始 文件 去 转存 的 目录 $3:log 文件
命名 的 前缀 $4:log 文件
命名 的 后缀 $5:log 文件
的 限制 的 最大 数量 #$1 origin log dir #$2 save log dir #$3 filename prefix #$4 filename suffix #$5 maximum log count function check_log() { local origin_dir="$1" local save_dir="$2" local prefix="$3" local suffix="$4" local log_cnt_max="$5" local save_log_dir max_file_size file_name time_type_name file_repeat file_inod
check_log函数的 目的 是 检查 日志 目录 中 是否 有 符合 特定 规则 的 日志 文件,并 根据 设定 的 日志 轮换 策略 处理 这些 日志 文件。
具体
使用 范例 在
start函数中 描述 新增 的 日志 文件,使用 check_log 第3,4,5个 参数 来 去 定义 log 的 文件 命名 格式 以及 限制 log 的 文件 数量 function start() { LOG_EXE_FLAG=1 record_reset_count while true; do check_log ${KER_ORI_LOG_DIR} ${KER_SAVE_LOG_DIR} "${SOC}_Kernel-${RESET_COUNT}-" ".Log" ${ROTATEGENS_KER} check_log ${USR_ORI_LOG_DIR} ${USR_SAVE_LOG_DIR} "${SOC}_Usr-${RESET_COUNT}-" ".Log" ${ROTATEGENS_USR} check_log ${DSP0_ORI_LOG_DIR} ${DSP0_SAVE_LOG_DIR} "${SOC}_Dsp-${RESET_COUNT}-" ".Log" ${ROTATEGENS_REMOTE} check_log ${BL31_ORI_LOG_DIR} ${BL31_SAVE_LOG_DIR} "${SOC}_Bl31-${RESET_COUNT}-" ".Log" ${ROTATEGENS_REMOTE} check_log ${CHIP_ORI_LOG_DIR} ${CHIP_SAVE_LOG_DIR} "${SOC}_Chip-${RESET_COUNT}-" ".Log" ${ROTATEGENS_CHIP} check_log_cnt_with_keyword ${CORE_DUMP_LOG_DIR} "adsp" 20 check_log_dir_size ${CORE_DUMP_LOG_DIR} ${CORE_DUMP_LOG_DIR_SIZE} sleep 600 done }
每个
check_log的参数 说明: 源目录
和 :每个保存 目录 调用 都 有 两个 目录 参数,分别 代表 原始 日志 文件 的 存放 位置 和 目标 日志 保存 的 位置。例如, KER_ORI_LOG_DIR表示内核 日志 的 原始 目录, KER_SAVE_LOG_DIR表示保存 的 目标目录。 日志
文件名 :模板 "${SOC}_Kernel-${RESET_COUNT}-" ".Log"是日志 文件名 的 前缀(SOC 和 RESET_COUNT 是 变量,通常 表示 系统 信息 和 重启 次数)。这 将 生成 一个 唯一 的 日志 文件名。 旋转
次数(例如 :该ROTATEGENS_KER)参数 控制 日志 文件 的 旋转 次数 或 数量 限制,用于 控制 日志 文件 的 大小 或 备份 数量。不同 的 日志 目录 会 有 不同 的 旋转 设置。
另外,最后
的 sleep 600,每次循环 结束 后, start()函数会 等待600秒(即10分钟)。这 意味着 每10分钟 执行 一次 上述 的 日志 检查和 管理 操作。
log 进程
的 裁剪 可以
通过 控制 init.d 中 log 启动 脚本,增删 log 进程 启动。 推荐
有 新 的 开发 功能 加入 时,也 通过 init.d 中 的 S92hobot_log_start shell 脚本 中 集成。
log 回读
log-service demo 会
针对 log 的 分区 目录 每隔 一段时间 进行 文件 上传,此 过程 不去 压缩 log。
pstore
pstore(Persistent Store)是 Linux 内核
pstore 具有
持久
化 :pstore 可以存储 将 重要 的 内核 调试信息(如 Oops 信息、内核 崩溃 日志 等)保存 到 持久 存储设备 中,这样 即使 系统 重启 后,依然 可以 获取 到 崩溃 时 的 信息。 多种
存储介质 :pstore 支持支持 多种 存储介质,例如,内存(通过 内存 的 某些 区域)、闪存(如 eMMC、NAND 闪存 等)、以及 其他 内存 设备(如 SPI Flash、NVRAM)。 内核
崩溃 :当信息 记录 内核 发生 崩溃 时,pstore 可以 将 崩溃 的 堆栈 信息、寄存器 状态、内核 错误信息 等 保存 下来,供 后续 调试 分析。 支持
多种 :pstore 不仅崩溃 场景 支持 内核 崩溃(Oops),还 可以 用于 记录 其它 类型 的 错误信息,如 内存 泄漏、硬件 错误 等。
pstore 的机制
pstore 本质/sys/fs/pstore 目录
root@buildroot:~# cat /proc/mounts |grep "^pstore"
pstore /sys/fs/pstore pstore rw,relatime 0 0
当/sys/fs/pstore 目录
root@buildroot:/sys/fs/pstore# ls
console-ramoops-0 dmesg-ramoops-0 sched-ramoops-0
console-ramoops-0:该文件 通常 存储系统 崩溃 时 控制台 输出 的 日志(例如 内核 panic 信息、错误 消息、调试信息 等)。 dmesg-ramoops-0:该文件 通常 存储 内核 启动 后 的 日志 信息,包括 硬件 检测、驱动 加载、系统启动 期间 发生 的 错误 或 警告 等。 sched-ramoops-0:该文件 通常 存储 的 是 调度 器(scheduler)相关 的 日志 信息,记录 内核 调度 器 在 崩溃 时 的 状态。
配置 pstore
在
# kernel/arch/arm64/boot/dts/hobot/x5-memory.dtsi
ramoops@A4080000 {
compatible = "ramoops";
reg = <0x0 0xA4080000 0x0 0x00040000>;
console-size = <0x8000>;
pmg-size = <0x8000>;
ftrace-size = <0x8000>;
sched-size = <0x8000>;
record-size = <0x4000>;
ecc-size = <0x0>;
};
ramoops@A4080000 { ... }这是
一个 设备 节点,定义 了 一个 名为 ramoops的设备,节点 的 地址 是 A4080000。这个节点 表明 系统 有 一个 ramoops设备,它位于 物理 内存地址 0xA4080000处。
compatible = "ramoops";这
行 定义 了 设备 与 ramoops驱动的 兼容性。这里,它 表明 该 设备 使用 ramoops驱动,ramoops是一种 用于 保存 内核 崩溃 信息(如 控制台 输出、调度 信息 等)的 机制。
reg = <0x0 0xA4080000 0x0 0x00040000>;这是
设备 的 地址 和 大小 配置,格式 为 <base address size>。 -0x0:表示地址 空间 的 起始 地址(通常 为 0,表示 物理地址)。 - 0xA4080000:表示设备 的 起始 物理地址,这里 为 0xA4080000。 -0x0:表示偏移量(通常 为 0)。 - 0x00040000:表示设备 的 内存 区域 大小,这里 是 0x00040000,即 256 KB。这
表示 设备 ramoops的内存 区域 从 0xA4080000地址开始,占用 256 KB 大小。
console-size = <0x8000>;这
行 配置 了 控制台 日志 缓冲区 的 大小。 console-size指定了 保存 内核 控制台 日志 的 内存 区域 大小,单位 为 字节。 0x8000:表示 32 KB 的大小。意味着 ramoops将为 控制台 日志 分配 32 KB 的 内存空间。
pmg-size = <0x8000>;pmg-size指定了 保存 内核 panic信息的 内存 区域 大小。 0x8000:表示 32 KB 大小。意味着ramoops将为 内核 panic 信息 分配 32 KB 的 内存空间。
ftrace-size = <0x8000>;ftrace-size配置了 ftrace(内核的 追踪 功能)日志 的 缓冲区 大小。 0x8000:表示 32 KB 大小。意味着ramoops将为 内核 的 ftrace追踪日志 分配 32 KB 的 内存空间。
sched-size = <0x8000>;sched-size配置了 内核 调度 器 日志 的 缓冲区 大小。 0x8000:表示 32 KB 大小。意味着ramoops将为 内核 调度 器 相关 的 信息(如 任务调度 日志)分配 32 KB 的 内存空间。
record-size = <0x4000>;record-size配置了 记录 日志 的 内存 区域 大小。 0x4000:表示 16 KB 大小。意味着ramoops将为 记录 崩溃 信息 的 日志 区域 分配 16 KB 的 内存空间。
ecc-size = <0x0>;ecc-size配置了 ECC(错误 更正 码)日志 的 区域 大小。 0x0:表示没有 为 ECC 分配内存。也就是说,在 此 配置 中 没有 为 ECC 错误 记录 预留 内存 区域。
要

注意,这里/sys/fs/pstore 里/sys/fs/pstore 里
<*> Log panic/oops to a RAM buffer
掉电/userdata/log/pstore/ 里
在
root@buildroot:~# dmesg | grep "ramoops"
[ 0.114818] printk: console [ramoops-1] enabled
[ 0.114822] pstore: Registered ramoops as persistent store backend
[ 0.114827] ramoops: using 0x40000@0xa4080000, ecc: 0
pstore 日志的转存
在hobot-log 脚本/sys/fs/pstore 里/userdata/log/pstore/ 目录set_pstore 函数:
#pstore log information
PSTORE_FS=$(cat /proc/mounts |grep "^pstore" |awk '{print $2}')
PSTORE_LOG=${LOG_SOURCE_DIR}/pstore
PSTORE_LOGMAX=100
function set_pstore()
{
if [ -n "${PSTORE_FS}" ] && [ ! -e ${PSTORE_LOG}/disable ]; then
if [ "$(ls -A ${PSTORE_FS})" == "" ];then
return 0
fi
local UBOOTCMD=$(cat /proc/cmdline| sed 's/ /\n/g' | grep -i hobotboot.reason)
local BOOTREASON=$(echo ${UBOOTCMD#*=})
if [ "${BOOTREASON}" == "COLD_BOOT" ] || [ "${BOOTREASON}" == "UBOOT_RESET" ] || [ "${BOOTREASON}" == "WATCHDOG" ] || [ "${BOOTREASON}" == "REBOOT_CMD" ]; then
return 0
fi
local pstore_log_date=$(date +%Y_%m_%d_%H_%M_%S)
local pstore_log_dir="${PSTORE_LOG}/${SOC}_Pstore-${RESET_COUNT_NOW}-${pstore_log_date}"
mkdir -p ${pstore_log_dir}
output "pstore log to ${pstore_log_dir}"
cp ${PSTORE_FS}/* ${pstore_log_dir}/
/usr/hobot/bin/hrut_sched_log_parse ${PSTORE_FS}/sched-ramoops-0 > ${pstore_log_dir}/sched-ramoops-0
change_file_time ${pstore_log_dir}
local pstore_log_cnt=$(ls -l ${PSTORE_LOG} | grep "^d" | wc -l)
while [ ${pstore_log_cnt} -gt ${PSTORE_LOGMAX} ]; do
local deldir_name=$(ls -ltr ${PSTORE_LOG} | grep "^d" | head -n 1 | awk '{print $9}')
rm -rf ${PSTORE_LOG}/${deldir_name}
pstore_log_cnt=$(ls -l ${PSTORE_LOG} | grep "^d" | wc -l)
done
sync
fi
}
set_pstore 函数PANIC (不能COLD_BOOT、UBOOT_RESET、WATCHDOG、REBOOT_CMD)的pstore_log_dir 目录(/userdata/log/pstore/),并
转存/userdata/log/pstore/ 会
root@buildroot:/userdata/log/pstore# ls
X5_Pstore-0074-1970_01_01_00_00_03 X5_Pstore-0075-1970_01_01_00_00_03
每次 panic 都/sys/fs/pstore 目录
root@buildroot:/userdata/log/pstore/X5_Pstore-0075-1970_01_01_00_00_03# ls
console-ramoops-0 dmesg-ramoops-0 sched-ramoops-0
pstore 使用示例
在
# 触发 panic
echo c > /proc/sysrq-trigger
# 查看 pstore 日志
cat /sys/fs/pstore/console-ramoops-0
# 或者查看转存到 /userdata/log/pstore/ 目录下的最新的一个子目录中的日志
cd /userdata/log/pstore/X5_Pstore-0075-1970_01_01_00_00_03/console-ramoops-0
4.4.7.4. log debug
log 调试注意点
调试
时 大量 日志 可以 单独 保存,防止 丢失,方便 查看: 内核
日志: dmesg -w > /userdata/dmesg.log &。ALOG 日志:
logcat -v time -f /userdata/logcat.log &。
每个
转存 周期(10min)内 产生 超过 rotate 数量 的 日志 会 造成 日志 丢失: 首先
应 只 输出 必要 的 日志。 如果
输出 较 多 log,在 设置 rotate 的 数量 时候,要 考虑 好 所 需 大小。
不要
在 串口、ssh 窗口 实时 查看 日志。可能 会 发现 丢 日志,原因 是 输出 慢,覆盖 导致。如果 必须,建议 ssh 窗口 实时 查看 日志。 比如
使用 logcat 在 串口 实时 查看 输出,内核 若 输出 “logcat lost message”,则 说明 有 日志 丢失。
日志
写入 存储设备 保存。考虑 到 存储设备 的 寿命 有限 和 大量 存储 日志 对 IO/CPU 性能 的 影响,应 只 输出 必要 的 日志,正式 版本 不 应 输出 大量 调试 日志: 比如
当 存储设备 是 eMMC(64GB、MLC、3000次 擦写)时,若 每分钟 写入 10MB 日志,则 连续 工作 十年 消耗27%寿命,考虑 写入 放大,消耗 更 多。
死机情况如何保存有效日志记录
在
出现 系统 panic 死机 的 时候,pstore 的 机制 是 可以 将 发生 panic 的 内核 log 信息 存储 到 pstore 的 目录 中 的,但 需要 注意 BL31 的 panic 信息 没法 保存。 关于 panic 的
具体 原因 可以 去 系统 稳定性 排查 指南 中 去 按照 指导 进一步 分析。
有效获取问题时刻日志
在 log 分区
中 的 文件 的 命 名字 段 中 包含 对应 log 文件 的 最后 修改 时间 的 信息,可以 去 文件 中 查找 问题 时刻 的 log。 如果
在 当前 机器 中 对应 的 log 没有 对应 的 文件,可能 出现 问题 时刻 的 log 已经 被 覆盖 了,可以 去 云端 中 获取 上传 的 log,寻找 对应 文件名 的 log 去 分析 问题。
4.4.7.5. 记录 AB/BAK 异常切换原因
介绍
目前,启动
miniboot 中
的 BL3x 被 corrupted(BAK 切换) misc 分区
中 记录 AB 信息 的 区域 被 corrupted(包含 misc 分区 为空 的 情况,切换 到 A) Uboot 被 corrupted(AB 切换)
boot 被 corrupted(AB 切换)
system 被 corrupted(即 dm-verity 失败,AB 切换)
当
另外hbre/hbutils/utility/pc_tools/hrut_switch_reason.py
hrut_switch_reason 工具使用
板端工具
root@buildroot:~# hrut_switch_reason -h
Usage: hrut_switch_reason [misc_path] <--current|--all>
misc_path: misc partition or file path (default: /dev/block/platform/by-name/misc)
--current: The reason for the last abnormal switch
--all: The reason for the all abnormal switch
example: hrut_switch_reason --all
misc_file:可选 参数。指定 dump 出 的 misc 分区 文件 路径。如果 为空,默认 路径 是 misc 的 分区 节点 /dev/block/platform/by-name/misc,如果要 指定 路径,必须 作为 第一个 参数 <–current|–all>:必选参数。 –current表示打印 上次 启动 失败 的 原因; –all表示打印 所有 启动 失败 的 原因,共10次
PC工具
❯ ./hrut_switch_reason.py -h
Usage: ./hrut_switch_reason.py <misc_file> <--current|--all>
misc_file:必选参数。指定 dump出的 misc分区文件 路径 <–current|–all>:必选参数。 –current表示打印 上次 启动 失败 的 原因; –all表示打印 所有 启动 失败 的 原因,共10次
使用示例
# 板端工具
root@buildroot:~# hrut_switch_reason --current # 打印上次启动失败原因
dm-verity corruped
root@buildroot:~# hrut_switch_reason --all # 打印全部启动失败原因
All Reasons (From the latest to the oldest):
1: dm-verity corruped
2: misc broken
3: unused
4: unused
5: unused
6: unused
7: unused
8: unused
9: unused
10: unused
# PC工具
❯ ./hrut_switch_reason.py ~/misc_file --current # 打印上次启动失败原因
miniboot corruped
❯ ./hrut_switch_reason.py ~/misc_file --all # 打印全部启动失败原因
All Reasons (From the latest to the oldest):
1: miniboot corruped
2: miniboot corruped
3: miniboot corruped
4: uboot corruped
5: uboot corruped
6: dm-verity corruped
7: boot corruted
8: boot corruted
9: dm-verity corruped
10: misc broken
测试用例构造
测试 misc 分区 corrupted 可以
mmc
# system corrupted (dm-verity) 需要开启AVB验证
mount / -o rw,remount
echo 132 > ~/test
sync
# boot corrupted 需要开启AVB验证
dd if=/dev/random of=/dev/block/platform/by-name/boot_a bs=1 count=4
# uboot corrupted
dd if=/dev/random of=/dev/block/platform/by-name/uboot_a bs=1 count=4
# miniboot中的bl3x corrupted
dd if=/dev/random of=/dev/block/platform/by-name/miniboot seek=262144 bs=1 count=512
flash
# system corrupted (dm-verity)
# flash 上不支持 dm-verity
# boot corrupted 需要开启AVB验证
# uboot cmd 执行
mtd write boot_a ${kernel_addr} 0 0x1000
# uboot corrupted
mtd write uboot_a ${kernel_addr} 0 0x1000
# miniboot 中的 bl3x corrupted
mtd write miniboot ${kernel_addr} 0x40000 0x1000
通过 cmdline 查看
Uboot 也
root@buildroot:~# cat /proc/cmdline
console=ttyS0,921600n8 root=/dev/mmcblk0p13 ro rootwait hobotboot.slot_suffix=_b hobotboot.reason=WATCHDOG hobotboot.medium=MMC hobotboot.mode=normal hobotboot.ab_switch_reason=dm-verity-corruted pmic_type=single-pmic
以下
console=ttyS0,921600n8:这个参数 指定 了 系统 的 控制台 输出 到 哪个 串行 端口。ttyS0 是 串行 端口 的 名称,921600是 波特率,n8 表示 没有 奇偶校验 位(no parity),8个 数据位。 root=/dev/mmcblk0p13:这个参数 指定 了 系统 的 根 文件系统 所在 的 设备 和 分区。这里 指定 的 是 /dev/mmcblk0 设备 的 第13个 分区(p13)。 ro:这个参数 表示 根 文件系统 以 只读 模式 挂载。 rootwait:这个参数 告诉 内核 在 启动 过程 中 等待 根 文件系统 设备 准备 好。这 通常 用于 网络 启动 或 USB 启动,其中 根 文件系统 设备 可能 需要 一些 时间 才能 准备 好。 hobotboot.slot_suffix=_b:这是一个 特定 于 某个 系统 的 参数,表示 启动 时 使用 的 slot(插槽)后缀 是 _b。 hobotboot.reason=WATCHDOG:这个参数 表示 启动 原因 是 由于 看门狗(WATCHDOG)触发 的。看门狗 是 一种 硬件 或 软件 机制,用于 检测 系统 是否 在 正常 运行,如果 系统 停止 响应,看门狗 可以 触发 重启。 hobotboot.medium=MMC:这个参数 表示 启动 介质 是 多媒体卡(MMC)。 hobotboot.mode=normal:这个参数 表示 启动 模式 是 正常 的 启动 模式。 hobotboot.ab_switch_reason=dm-verity-corruted:这个参数 表示 AB 切换(可能 是 指 双系统 切换)的 原因 是 dm-verity 校验 失败。dm-verity 是 一种 用于 验证 启动 分区 完整性 的 技术,如果 校验 失败,可能 意味着 启动 分区 被 篡改 或 损坏。 pmic_type=single-pmic:这个参数 表示 电源 管理 集成电路(PMIC)的 类型 是 单 PMIC。
cmdline 中hobotboot.ab_switch_reason。
通过系统 log 查看
在/userdata/log/reset_reason.txt。例如
root@buildroot:~# cat /userdata/log/reset_reason.txt
1970-01-01-00-00-08: UBOOT_RESET misc-broken LNX6.1.83_PL5.1_V1.0.11_20240912-1542 0000
其中 misc-broken 表示misc 分区