在上篇中从上层使用Log的java接口讲到了liblog中,最终通过socket将要打印的Log交给了logd模块处理,本篇就继续来看一下logd模块内部对Log的处理过程。
Logd的启动
Logd模块是单独跑在一个进程中的,该进程是直接由init进程fork出来的子进程。
shell@M3X:/ $ ps | grep zygote
root 343 1 2137408 86344 poll_sched 0000000000 S zygote64
root 344 1 1579728 75304 poll_sched 0000000000 S zygote
shell@M3X:/ $ ps | grep logd
logd 268 1 27136 3724 sigsuspend 0000000000 S /system/bin/logd
shell@M3X:/ $ ps | grep init
root 1 0 13112 1364 SyS_epoll_ 0000000000 S /init
system 293 1 13316 1644 dev_char_r 0000000000 S /system/bin/ccci_mdinit
system 295 1 12284 1636 dev_char_r 0000000000 S /system/bin/ccci_mdinit
通过ps可以看到logd进程和zygote一样,他们的ppid都是1,而1正是init进程的pid,所以也印证了他们都是由init进程fork出来的结论,当然你也可以去查看一下系统中的init.rc文件,里面也详细描述了启动logd的时机。
Logd启动后的入口是/system/core/logd/main.cpp中的main方法,本文聚焦上层打印Log后Logd的处理过程,因此省略部分代码:
int main(int argc, char *argv[]) {
...
// LogBuffer is the object which is responsible for holding all
// log entries.
logBuf = new LogBuffer(times);
// LogReader listens on /dev/socket/logdr. When a client
// connects, log entries in the LogBuffer are written to the client.
LogReader *reader = new LogReader(logBuf);
if (reader->startListener()) {
exit(1);
}
// LogListener listens on /dev/socket/logdw for client
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
LogListener *swl = new LogListener(logBuf, reader);
// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
if (swl->startListener(600)) {
exit(1);
}
...
}
上面的代码在Logd进程启动后执行,省略了部分初始化工作的代码,这里主看到构造了一个LogBuffer类型的对象logBuf,它的作用是真正存放写入的log。然后构造了一个LogReader类型的对象reader,并将上面构造的logBuf当做参数传给reader,它的作用主要是监听LogBuffer中log的变化或者是否有进程想要读取logd中的log,在有新的log写入时能够被及时通知到,然后可以通过socket通知log的读取方将log取出,通过其startListener()方法开始监听socket是否有请求(比如adb shell logcat)。接下来构造了一个LogListener类型的对象swl,并将r