系列目录第一篇全景图与架构概览| 第二篇logd守护进程—启动、初始化与Socket通信 | 第三篇liblog库—日志写入的完整链路 | 第四篇日志写入接口—Java层与Native层 | 第五篇日志读取—logcat源码深度分析 | 第六篇日志缓冲区管理—容量、裁剪与统计机制 | 第七篇实战调试与常见问题分析一、为什么要系统学习 Android 日志模块每个 Android 开发者的第一行调试代码几乎都是Log.d(TAG, hello world)。这个简单的 API 调用背后藏着一个从 Java 层到 Native 层、跨进程通信、缓冲区管理、裁剪策略逐层堆叠的精密系统。当你遇到以下问题时单纯依赖logcat的简单用法是不够的“日志丢失”为什么有些Log.d明明执行了logcat却看不到是缓冲区满了还是被 chatty 机制合并了“日志延迟”大量日志输出时为什么 logcat 的显示总是慢半拍“内核日志缺失”dmesg和logcat显示的日志各自来自哪里它们之间有什么关系“SELinux 限制”为什么某些 Native 进程的日志打不出来“崩溃日志取证”进程 crash 后还没来得及写入 logd 的日志去哪了pstore 机制如何兜底本系列以AOSP 7android-7.1.2_r36为基准从Log.d()一直走到 logd 守护进程的缓冲区逐层拆解 Android 日志子系统。二、宏观架构六层模型┌──────────────────────────────────────────────────────┐ │ 应用层 / 框架层 │ │ Log.d() / Log.e() → android.util.Log │ │ Slog.d() / Slog.e() → android.util.Slog │ │ EventLog.writeEvent() → android.util.EventLog │ ├──────────────────────────────────────────────────────┤ │ JNI 桥接层 │ │ android_util_Log.cpp → println_native() │ ├──────────────────────────────────────────────────────┤ │ Native liblog 库 │ │ __android_log_buf_write() → logdWrite() │ ├──────────────────────────────────────────────────────┤ │ Socket 传输层 │ │ /dev/socket/logdw (写入) │ │ /dev/socket/logdr (读取) │ │ /dev/socket/logd (控制) │ ├──────────────────────────────────────────────────────┤ │ logd 守护进程 │ │ LogListener → LogBuffer → LogReader │ │ main / system / events / radio / crash / kernel │ ├──────────────────────────────────────────────────────┤ │ 内核层 │ │ /dev/kmsg / pstore (ramoops) │ └──────────────────────────────────────────────────────┘从环形缓冲区到logd 守护进程的演进在 Android 5.0 之前日志直接依赖内核logger驱动每个缓冲区对应一个/dev/log/main、/dev/log/system等设备节点应用程序和 logcat 通过write()/read()系统调用直接操作。缺陷内核态管理太重——缓冲区策略写死在内核修改困难无法按 UID/PID 差异化裁剪扩展新缓冲区必须改内核驱动从 Android 5.0 起引入 logd 守护进程将日志管理完全移到用户态。Android 7 中这套架构已成熟稳定——日志的写入、存储、裁剪、读取全部由 logd 负责通信方式从设备节点改为 Unix domain socket。三、核心组件三剑客3.1 logd — 日志管家守护进程logd 是整个日志系统的大脑由 init 在系统启动早期拉起# system/core/logd/logd.rcservicelogd /system/bin/logd socket logd stream 0666 logd logd# 控制命令通道socket logdr seqpacket 0666 logd logd# 日志读取通道socket logdw dgram 0222 logd logd# 日志写入通道group root system readproc内部维护七个 LogBuffer对应log_id_t枚举缓冲区默认大小用途典型生产者main256KB应用层日志Log.d()、ALOGD()system256KB系统框架日志Slog.d()events256KB系统事件二进制EventLog.writeEvent()radio256KB无线通信日志Rlog.d()crash256KB崩溃日志系统服务 crashsecurity256KBSELinux 审计日志LogAudit线程写入kernel256KB内核日志LogKlog从/dev/kmsg读取多个核心工作线程logd 进程 ├── LogListener 线程 → 监听 logdw接收日志写入 ├── LogReader 线程 → 监听 logdr服务 logcat 读取 ├── CommandListener → 监听 logd处理控制命令 ├── LogAudit 线程 → 监听 NETLINK_AUDIT处理 SELinux 审计日志 └── LogKlog 线程 → 从 /dev/kmsg 读取内核日志3.2 liblog — 日志读写库连接日志生产者与 logd 的桥梁所有日志接口最终都调用它。system/core/liblog/ ├── logger_write.c // 对外接口__android_log_buf_write() ├── logger_read.c // 读端核心 ├── logd_writer.c // logd 通道写实现logdWrite ├── pmsg_writer.c // pstore 内核兜底 ├── logd_reader.c // 读取接口 └── event_tag_map.c // events 日志 tag 映射核心设计传输器抽象——正常路径走logd_writersocket → logd内核 panic 时走pmsg_writer/dev/pmsg0兜底。3.3 logcat — 日志读取工具Android 7 中 logcat 是单个 C 文件system/core/logcat/logcat.cpp通过 socketlogdr连接 logd指定缓冲区、过滤条件后循环读取按-v参数格式化输出到 stdout。四、七大日志缓冲区4.1 main最常用的缓冲区。应用层Log.d()、Native 层ALOGD()写入纯文本格式。4.2 system系统框架专用Slog.d()写入。记录 AMS、WMS 等系统级日志。普通应用无写入权限。4.3 events二进制格式的事件缓冲区。通过EventLog.writeEvent()写入用于记录am_proc_start、am_anr、binder_sample等系统关键事件。logcat -b events时会解码为可读文本。4.4 radio无线通信日志Rlog.d()写入用于调试 modem、RIL 等问题。4.5 crashAndroid 7 新增专门存储系统服务崩溃日志注意应用层 crash 走 tombstone不走这里。4.6 securitySELinux 审计日志缓冲区。存储 SELinux 权限检查拒绝事件由LogAudit线程从 NETLINK_AUDIT socket 读取后写入。4.7 kernellogd 通过KernelLogger从/dev/kmsg读取内核环形缓冲区日志并转发。dmesg可直接查看logcat -b kernel查看 logd 转发的版本。五、一次日志写入的宏观路径以Log.d(MyTag, hello)为例T0 APP 调用 Log.d(MyTag, hello) ↓ T1 Log.java → println_native(LOG_ID_MAIN, DEBUG, MyTag, hello) ↓ (JNI 调用) T2 android_util_Log.cpp → println_native() ↓ 解析参数拿到 bufID LOG_ID_MAIN ↓ 调用 __android_log_buf_write(bufID, ...) T3 liblog/logger_write.c → __android_log_buf_write() ↓ 格式化日志头android_log_header_t ↓ 依次调用每个 transport 的 write() ├── logdWrite() → socket send(logdw, ...) │ ↓ │ ┌────────────────────────────────────────┐ │ │ logd 守护进程 │ │ │ LogListener 线程 → recv(logdw) │ │ │ → 解析日志头 │ │ │ → LogBuffer-log() 写入环形缓冲区 │ │ │ → LogReader 通知等待中的客户端 │ │ └────────────────────────────────────────┘ │ └── pmsgWrite() → /dev/pmsg0 (panic 兜底)关键数据结构logger_entry_v4Socket 传输使用二进制 header 文本消息体的格式。Android 7 中使用的版本是logger_entry_v4源码路径system/core/include/log/logger.hstructlogger_entry_v4{uint16_tlen;/* 消息体长度 */uint16_thdr_size;/* header 大小 */int32_tpid;/* 写日志的进程 PID */uint32_ttid;/* 写日志的线程 ID */uint32_tsec;/* 时间戳秒 */uint32_tnsec;/* 时间戳纳秒 */uint32_tlid;/* log_idmain/system/events 等 */uint32_tuid;/* 写日志的进程 UID */charmsg[0];/* 消息体柔性数组 */}__attribute__((__packed__));六、一次日志读取的宏观路径以adb shell logcat -v time MyTag:* *:S为例T0 adb shell logcat -v time MyTag:* *:S ↓ T1 logcat/logcat.cpp → main() ↓ 解析 -b → log_ids [LOG_ID_MAIN] ↓ 解析 -v → 格式 FORMAT_TIME ↓ 解析过滤 → MyTag:*, default:silent T2 创建 android_logger_list ↓ socket 连接 logdr T3 发送控制命令tail / logid T4 while (1) { android_logger_list_read() ← 阻塞读取 ↓ (logd 端) LogReader 线程 │ 从 LogBuffer 取出下一条日志 │ socket send(logdr) → 回传 ▼ 应用过滤条件 ↓ 匹配 → formatBuf() 格式化输出 ↓ 不匹配 → 跳过 }七、关键源码文件索引logd 守护进程文件说明system/core/logd/main.cpplogd 入口、参数解析system/core/logd/LogBuffer.cpp环形缓冲区实现system/core/logd/LogBufferElement.h日志条目数据结构system/core/logd/LogListener.cpp监听 logdw socketsystem/core/logd/LogReader.cpp监听 logdr socketsystem/core/logd/CommandListener.cpp监听 logd socket控制命令system/core/logd/LogStatistics.cppUID/PID/TAG 维度统计system/core/logd/LogKlog.cpp内核日志转发system/core/logd/LogAudit.cppSELinux 审计日志liblog 库文件说明system/core/liblog/logger_write.c__android_log_buf_write()system/core/liblog/logger_read.c读取接口system/core/liblog/logd_writer.clogd 通道写实现system/core/liblog/pmsg_writer.cpstore 兜底system/core/include/log/log.hALOGD 等宏system/core/include/log/logger.h核心结构体logcat 工具文件说明system/core/logcat/logcat.cpp命令行解析、读取、格式化Java 层文件说明frameworks/base/core/java/android/util/Log.java应用层日志接口frameworks/base/core/java/android/util/Slog.java系统框架日志接口frameworks/base/core/java/android/util/EventLog.java事件日志接口frameworks/base/core/jni/android_util_Log.cppLog.java 的 JNI 实现八、各篇预告篇目聚焦第二篇logd 启动流程、四个 Socket 的创建与权限、LogListener/LogReader 线程初始化第三篇liblog 写入链路的逐函数剖析__android_log_buf_write→logd_dgram_write第四篇Java 层四大接口Log/Slog/EventLog/Rlog和 Native 层宏ALOGD等的源码第五篇logcat 的参数解析、缓冲区选择、过滤匹配、格式化输出第六篇LogBuffer 环形数据结构、按 UID 裁剪策略、LogStatistics 统计第七篇日志丢失/不输出/延迟的根因排查结合 bugreport、tombstone 的综合调试
Android 7系统日志(一):全景图与架构概览
发布时间:2026/6/30 16:34:10
系列目录第一篇全景图与架构概览| 第二篇logd守护进程—启动、初始化与Socket通信 | 第三篇liblog库—日志写入的完整链路 | 第四篇日志写入接口—Java层与Native层 | 第五篇日志读取—logcat源码深度分析 | 第六篇日志缓冲区管理—容量、裁剪与统计机制 | 第七篇实战调试与常见问题分析一、为什么要系统学习 Android 日志模块每个 Android 开发者的第一行调试代码几乎都是Log.d(TAG, hello world)。这个简单的 API 调用背后藏着一个从 Java 层到 Native 层、跨进程通信、缓冲区管理、裁剪策略逐层堆叠的精密系统。当你遇到以下问题时单纯依赖logcat的简单用法是不够的“日志丢失”为什么有些Log.d明明执行了logcat却看不到是缓冲区满了还是被 chatty 机制合并了“日志延迟”大量日志输出时为什么 logcat 的显示总是慢半拍“内核日志缺失”dmesg和logcat显示的日志各自来自哪里它们之间有什么关系“SELinux 限制”为什么某些 Native 进程的日志打不出来“崩溃日志取证”进程 crash 后还没来得及写入 logd 的日志去哪了pstore 机制如何兜底本系列以AOSP 7android-7.1.2_r36为基准从Log.d()一直走到 logd 守护进程的缓冲区逐层拆解 Android 日志子系统。二、宏观架构六层模型┌──────────────────────────────────────────────────────┐ │ 应用层 / 框架层 │ │ Log.d() / Log.e() → android.util.Log │ │ Slog.d() / Slog.e() → android.util.Slog │ │ EventLog.writeEvent() → android.util.EventLog │ ├──────────────────────────────────────────────────────┤ │ JNI 桥接层 │ │ android_util_Log.cpp → println_native() │ ├──────────────────────────────────────────────────────┤ │ Native liblog 库 │ │ __android_log_buf_write() → logdWrite() │ ├──────────────────────────────────────────────────────┤ │ Socket 传输层 │ │ /dev/socket/logdw (写入) │ │ /dev/socket/logdr (读取) │ │ /dev/socket/logd (控制) │ ├──────────────────────────────────────────────────────┤ │ logd 守护进程 │ │ LogListener → LogBuffer → LogReader │ │ main / system / events / radio / crash / kernel │ ├──────────────────────────────────────────────────────┤ │ 内核层 │ │ /dev/kmsg / pstore (ramoops) │ └──────────────────────────────────────────────────────┘从环形缓冲区到logd 守护进程的演进在 Android 5.0 之前日志直接依赖内核logger驱动每个缓冲区对应一个/dev/log/main、/dev/log/system等设备节点应用程序和 logcat 通过write()/read()系统调用直接操作。缺陷内核态管理太重——缓冲区策略写死在内核修改困难无法按 UID/PID 差异化裁剪扩展新缓冲区必须改内核驱动从 Android 5.0 起引入 logd 守护进程将日志管理完全移到用户态。Android 7 中这套架构已成熟稳定——日志的写入、存储、裁剪、读取全部由 logd 负责通信方式从设备节点改为 Unix domain socket。三、核心组件三剑客3.1 logd — 日志管家守护进程logd 是整个日志系统的大脑由 init 在系统启动早期拉起# system/core/logd/logd.rcservicelogd /system/bin/logd socket logd stream 0666 logd logd# 控制命令通道socket logdr seqpacket 0666 logd logd# 日志读取通道socket logdw dgram 0222 logd logd# 日志写入通道group root system readproc内部维护七个 LogBuffer对应log_id_t枚举缓冲区默认大小用途典型生产者main256KB应用层日志Log.d()、ALOGD()system256KB系统框架日志Slog.d()events256KB系统事件二进制EventLog.writeEvent()radio256KB无线通信日志Rlog.d()crash256KB崩溃日志系统服务 crashsecurity256KBSELinux 审计日志LogAudit线程写入kernel256KB内核日志LogKlog从/dev/kmsg读取多个核心工作线程logd 进程 ├── LogListener 线程 → 监听 logdw接收日志写入 ├── LogReader 线程 → 监听 logdr服务 logcat 读取 ├── CommandListener → 监听 logd处理控制命令 ├── LogAudit 线程 → 监听 NETLINK_AUDIT处理 SELinux 审计日志 └── LogKlog 线程 → 从 /dev/kmsg 读取内核日志3.2 liblog — 日志读写库连接日志生产者与 logd 的桥梁所有日志接口最终都调用它。system/core/liblog/ ├── logger_write.c // 对外接口__android_log_buf_write() ├── logger_read.c // 读端核心 ├── logd_writer.c // logd 通道写实现logdWrite ├── pmsg_writer.c // pstore 内核兜底 ├── logd_reader.c // 读取接口 └── event_tag_map.c // events 日志 tag 映射核心设计传输器抽象——正常路径走logd_writersocket → logd内核 panic 时走pmsg_writer/dev/pmsg0兜底。3.3 logcat — 日志读取工具Android 7 中 logcat 是单个 C 文件system/core/logcat/logcat.cpp通过 socketlogdr连接 logd指定缓冲区、过滤条件后循环读取按-v参数格式化输出到 stdout。四、七大日志缓冲区4.1 main最常用的缓冲区。应用层Log.d()、Native 层ALOGD()写入纯文本格式。4.2 system系统框架专用Slog.d()写入。记录 AMS、WMS 等系统级日志。普通应用无写入权限。4.3 events二进制格式的事件缓冲区。通过EventLog.writeEvent()写入用于记录am_proc_start、am_anr、binder_sample等系统关键事件。logcat -b events时会解码为可读文本。4.4 radio无线通信日志Rlog.d()写入用于调试 modem、RIL 等问题。4.5 crashAndroid 7 新增专门存储系统服务崩溃日志注意应用层 crash 走 tombstone不走这里。4.6 securitySELinux 审计日志缓冲区。存储 SELinux 权限检查拒绝事件由LogAudit线程从 NETLINK_AUDIT socket 读取后写入。4.7 kernellogd 通过KernelLogger从/dev/kmsg读取内核环形缓冲区日志并转发。dmesg可直接查看logcat -b kernel查看 logd 转发的版本。五、一次日志写入的宏观路径以Log.d(MyTag, hello)为例T0 APP 调用 Log.d(MyTag, hello) ↓ T1 Log.java → println_native(LOG_ID_MAIN, DEBUG, MyTag, hello) ↓ (JNI 调用) T2 android_util_Log.cpp → println_native() ↓ 解析参数拿到 bufID LOG_ID_MAIN ↓ 调用 __android_log_buf_write(bufID, ...) T3 liblog/logger_write.c → __android_log_buf_write() ↓ 格式化日志头android_log_header_t ↓ 依次调用每个 transport 的 write() ├── logdWrite() → socket send(logdw, ...) │ ↓ │ ┌────────────────────────────────────────┐ │ │ logd 守护进程 │ │ │ LogListener 线程 → recv(logdw) │ │ │ → 解析日志头 │ │ │ → LogBuffer-log() 写入环形缓冲区 │ │ │ → LogReader 通知等待中的客户端 │ │ └────────────────────────────────────────┘ │ └── pmsgWrite() → /dev/pmsg0 (panic 兜底)关键数据结构logger_entry_v4Socket 传输使用二进制 header 文本消息体的格式。Android 7 中使用的版本是logger_entry_v4源码路径system/core/include/log/logger.hstructlogger_entry_v4{uint16_tlen;/* 消息体长度 */uint16_thdr_size;/* header 大小 */int32_tpid;/* 写日志的进程 PID */uint32_ttid;/* 写日志的线程 ID */uint32_tsec;/* 时间戳秒 */uint32_tnsec;/* 时间戳纳秒 */uint32_tlid;/* log_idmain/system/events 等 */uint32_tuid;/* 写日志的进程 UID */charmsg[0];/* 消息体柔性数组 */}__attribute__((__packed__));六、一次日志读取的宏观路径以adb shell logcat -v time MyTag:* *:S为例T0 adb shell logcat -v time MyTag:* *:S ↓ T1 logcat/logcat.cpp → main() ↓ 解析 -b → log_ids [LOG_ID_MAIN] ↓ 解析 -v → 格式 FORMAT_TIME ↓ 解析过滤 → MyTag:*, default:silent T2 创建 android_logger_list ↓ socket 连接 logdr T3 发送控制命令tail / logid T4 while (1) { android_logger_list_read() ← 阻塞读取 ↓ (logd 端) LogReader 线程 │ 从 LogBuffer 取出下一条日志 │ socket send(logdr) → 回传 ▼ 应用过滤条件 ↓ 匹配 → formatBuf() 格式化输出 ↓ 不匹配 → 跳过 }七、关键源码文件索引logd 守护进程文件说明system/core/logd/main.cpplogd 入口、参数解析system/core/logd/LogBuffer.cpp环形缓冲区实现system/core/logd/LogBufferElement.h日志条目数据结构system/core/logd/LogListener.cpp监听 logdw socketsystem/core/logd/LogReader.cpp监听 logdr socketsystem/core/logd/CommandListener.cpp监听 logd socket控制命令system/core/logd/LogStatistics.cppUID/PID/TAG 维度统计system/core/logd/LogKlog.cpp内核日志转发system/core/logd/LogAudit.cppSELinux 审计日志liblog 库文件说明system/core/liblog/logger_write.c__android_log_buf_write()system/core/liblog/logger_read.c读取接口system/core/liblog/logd_writer.clogd 通道写实现system/core/liblog/pmsg_writer.cpstore 兜底system/core/include/log/log.hALOGD 等宏system/core/include/log/logger.h核心结构体logcat 工具文件说明system/core/logcat/logcat.cpp命令行解析、读取、格式化Java 层文件说明frameworks/base/core/java/android/util/Log.java应用层日志接口frameworks/base/core/java/android/util/Slog.java系统框架日志接口frameworks/base/core/java/android/util/EventLog.java事件日志接口frameworks/base/core/jni/android_util_Log.cppLog.java 的 JNI 实现八、各篇预告篇目聚焦第二篇logd 启动流程、四个 Socket 的创建与权限、LogListener/LogReader 线程初始化第三篇liblog 写入链路的逐函数剖析__android_log_buf_write→logd_dgram_write第四篇Java 层四大接口Log/Slog/EventLog/Rlog和 Native 层宏ALOGD等的源码第五篇logcat 的参数解析、缓冲区选择、过滤匹配、格式化输出第六篇LogBuffer 环形数据结构、按 UID 裁剪策略、LogStatistics 统计第七篇日志丢失/不输出/延迟的根因排查结合 bugreport、tombstone 的综合调试