Android 7系统日志(二)logd守护进程—启动、初始化与Socket通信.md

📅 2026/7/1 16:50:17
Android 7系统日志(二)logd守护进程—启动、初始化与Socket通信.md
系列目录第一篇全景图与架构概览| 第二篇logd守护进程—启动、初始化与Socket通信 | 第三篇liblog库—日志写入的完整链路 | 第四篇日志写入接口—Java层与Native层 | 第五篇日志读取—logcat源码深度分析 | 第六篇日志缓冲区管理—容量、裁剪与统计机制 | 第七篇实战调试与常见问题分析一、logd 的定位回顾第一篇的六层架构logd 处于核心管理层。所有日志写入汇入 logd读取也由 logd 提供。本篇聚焦启动时机、初始化流程、四个 Socket 的创建与工作机制。源码入口system/core/logd/main.cpp、LogListener.cpp、LogReader.cpp、CommandListener.cpp、logd.rc二、启动时机init.rc 中的 logd servicelogd 是 Android 中启动最早的服务之一。在system/core/rootdir/init.rcservicelogd /system/bin/logd class core socket logd stream 0666 logd logd socket logdr seqpacket 0666 logd logd socket logdw dgrampasscred 0222 logd logdfile/proc/kmsg rfile/dev/kmsg w user logd group logd system package_info readproc关键点class core属于最先启动的服务类别在surfaceflinger之前user logd以受限用户身份运行安全隔离Socket 由 init 进程在 fork 前创建logd 通过ANDROID_SOCKET_xxx环境变量继承 fd三、三个 Socket 的详细解析3.1 logdw — 日志写入通道socket logdw dgrampasscred 0222 logd logd属性值设计理由类型dgram(SOCK_DGRAM)天然消息边界一条 send() 一条日志选项passcredSCM_CREDENTIALS 获取发送方 UID/PID内核保证无法伪造权限0222任何人可写不可读3.2 logdr — 日志读取通道socket logdr seqpacket 0666 logd logdseqpacket(SOCK_SEQPACKET)保证有序和完整性保持消息边界权限0666允许 logcat 等工具连接读取3.3 logd — 控制命令通道socket logd stream 0666 logd logdstream(SOCK_STREAM)命令长度不定需双向通信用换行分隔命令处理clear、getLogSize、setLogSize、getStatistics等命令四、main() 入口源码分析// system/core/logd/main.cpp核心逻辑 注释intmain(intargc,char*argv[]){// 阶段1参数解析-L 读取 pstore 中的历史日志// 阶段2获取 init 传下来的 Socket fdintfdDmesgandroid_get_control_file(/dev/kmsg);// 阶段3初始化 Socket 监听intdw_fdandroid_get_control_socket(logdw);LogListener*listenernewLogListener(logbuf);// 注册到 SocketListener绑定 dw_fdintdr_fdandroid_get_control_socket(logdr);LogReader*readernewLogReader(logbuf);intd_fdandroid_get_control_socket(logd);CommandListener*cmdnewCommandListener(logbuf);// 阶段4创建五个独立的 LogBufferlogbuf[LOG_ID_MAIN]newLogBuffer();logbuf[LOG_ID_SYSTEM]newLogBuffer();logbuf[LOG_ID_EVENTS]newLogBuffer();logbuf[LOG_ID_RADIO]newLogBuffer();logbuf[LOG_ID_CRASH]newLogBuffer();// 阶段5初始化内核日志转发LogKlog → /proc/kmsg// 阶段6进入 epoll 主循环while(1){// epoll_wait 等待任一 Socket 事件}}核心设计epoll 事件驱动。四个 Socket fd 注册到 epoll有事件才唤醒处理高频日志写入也不过度消耗 CPU。五、LogListener — 日志写入的接收端// system/core/logd/LogListener.cpp关键逻辑classLogListener:publicSocketListener{LogBuffer*logbuf;boolonDataAvailable(SocketClient*cli){// 1. recvmsg() 从 logdw 读取数据charbuffer[sizeof(android_log_header_t)LOGGER_ENTRY_MAX_PAYLOAD];// 2. 通过 SCM_CREDENTIALS 获取发送方的真实 UID/PIDstructucred*cred;// 内核填入无法伪造// 3. 解析日志头android_log_header_t*header(android_log_header_t*)buffer;char*msgbuffersizeof(android_log_header_t);// 4. 按 log_id 路由到对应 LogBufferlogbuf[header-id].log(cred-uid,// 来自 SCM_CREDENTIALS可信cred-pid,header-tid,header-tv_sec,header-tv_nsec,msg,header-len);}};SCM_CREDENTIALS 的信任根UID/PID 由 Linux 内核保证调用方无法伪造为后续裁剪策略提供可靠基础。log_id 路由header-id直接映射到logbuf数组索引LOG_ID_MAIN0, RADIO1, EVENTS2, SYSTEM3, CRASH4。六、LogReader — 日志读取的服务端logcat 进程 logd 端 (LogReader) ───────────────────────────────────────────────────── socket connect(logdr) → 发送控制命令 → accept() 新连接 → 进入读取循环 → 收到命令 → 创建 LogReaderThread → recv(logdr) 等待 → LogReaderThread: → 收到日志 → 格式化为文本 while (客户端未关闭) { → 输出到 stdout LogBuffer-next(pos) → 取出一条日志 → send(logdr, client) }每个 logcat 连接对应一个LogTimes对象记录客户端关心的缓冲区、读取位置等状态。七、CommandListener — 控制命令// system/core/logd/CommandListener.cppCommandListener::CommandListener(LogBuffer*buf):FrameworkListener(getLogSocket()){registerCmd(newClearCmd(buf));// clear → logcat -cregisterCmd(newGetSizeCmd(buf));// getLogSize → logcat -gregisterCmd(newSetSizeCmd(buf));// setLogSize → 动态调整缓冲区大小registerCmd(newGetStatisticsCmd());// getStatistics → logcat -S}日志清除clear id本质是向 logd socket 发送命令清空指定 LogBuffer。八、内核日志转发LogKloglogd 通过/proc/kmsg读取内核日志并转发到logbuf[LOG_ID_KERNEL]内核级别Android 映射KERN_EMERG/ALERT/CRITANDROID_LOG_FATALKERN_ERRANDROID_LOG_ERRORKERN_WARNINGANDROID_LOG_WARNKERN_NOTICE/INFOANDROID_LOG_INFOKERN_DEBUGANDROID_LOG_DEBUG九、epoll 事件循环全景logd 主循环 (epoll_wait) │ ┌──────────┬────────┼────────┬──────────┐ ▼ ▼ ▼ ▼ ▼ logdw logdr logd /proc/kmsg (其他) LogListener LogReader Cmd LogKlog .onData() .onData() .runCmd() .onData() │ │ │ │ ▼ ▼ ▼ ▼ LogBuffer LogBuffer 缓冲区 LogBuffer .log() .next() 操作/统计 .log()十、本篇小结logd 由 init 的class core机制在早期拉起三个 Socketlogdw/logdr/logd由 init 预创建logd 继承 fddgrampasscred的 logdw 设计一条 send 一条日志 内核保证的 UID 信任epoll 事件驱动模型保证高频场景下的低 CPU 消耗LogListener → LogBuffer.log() → LogReader → logcat 形成完整闭环下一篇将深入liblog 库逐函数拆解从__android_log_buf_write()到 Socket send 的完整调用链。