【无标题】

前言

logd 是Android L版本提出来的概念,其作用是保存Android运行期间的log(日志)。在Android L之前,log由kernel的ring buffer 保存,在Android L之后,log保存在用户空间。

 

代码基于版本:Android P

 

架构

log系统大概分三个部分:

  • 上层接口。例如ALOGD、log.d、Slog.d等
  • liblog 
  • logd

在Android framework中有Log.java、Slog.java等文件提供了上层应用使用的接口,在native或jni代码中会使用liblog/include/log/log.h中定义的宏接口ALOGD、ALOGE等接口,但是最终都是通过liblog中logger_write.cpp下的__android_log_write接口。

 

先来看下__android_log_write:


   
   
  1. LIBLOG_ABI_PUBLIC int __android_log_write( int prio, const char* tag,
  2. const char* msg) {
  3. return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
  4. }

调用__android_log_buf_write():


   
   
  1. LIBLOG_ABI_PUBLIC int __android_log_buf_write( int bufID, int prio,
  2. const char* tag, const char* msg) {
  3. struct iovec vec[ 3];
  4. char tmp_tag[ 32];
  5. ...
  6. ...
  7. vec[ 0].iov_base = ( unsigned char*)&prio;
  8. vec[ 0].iov_len = 1;
  9. vec[ 1].iov_base = ( void*)tag;
  10. vec[ 1].iov_len = strlen(tag) + 1;
  11. vec[ 2].iov_base = ( void*)msg;
  12. vec[ 2].iov_len = strlen(msg) + 1;
  13. return write_to_log(bufID, vec, 3);
  14. }

调用到的是write_to_log(),而在初始化的时候write_log_log指向的是__write_to_log_init():


   
   
  1. static int (*write_to_log)(log_id_t, struct iovec* vec,
  2. size_t nr) = __write_to_log_init;

logger_write.c 中这个函数很重要,所有的源头都是从这里开始的,最终会调用__write_to_log_daemon:


   
   
  1. static int __write_to_log_init( log_id_t log_id, struct iovec* vec, size_t nr) {
  2. int ret, save_errno = errno;
  3. __android_log_lock();
  4. if (write_to_log == __write_to_log_init) {
  5. ret = __write_to_log_initialize();
  6. if (ret < 0) {
  7. __android_log_unlock();
  8. if (! list_empty(&__android_log_persist_write)) {
  9. __write_to_log_daemon(log_id, vec, nr);
  10. }
  11. errno = save_errno;
  12. return ret;
  13. }
  14. write_to_log = __write_to_log_daemon;
  15. }
  16. __android_log_unlock();
  17. ret = write_to_log(log_id, vec, nr);
  18. errno = save_errno;
  19. return ret;
  20. }

在__write_to_log_daemon中进行一些初始化、过滤、判断等,最终会调用到transport中的write:


   
   
  1. write_transport_for_each(node, &__android_log_transport_write) {
  2. if (node->logMask & i) {
  3. ssize_t retval;
  4. retval = (*node->write)(log_id, &ts, vec, nr);
  5. if (ret >= 0) {
  6. ret = retval;
  7. }
  8. }
  9. }

这里的write函数最终调用我们先不看,下面会解释。

这里transport在初始化的时候形成了一个list,详细看__write_to_log_initialize()中调用__android_log_config_write():


   
   
  1. LIBLOG_HIDDEN void __android_log_config_write() {
  2. if (__android_log_transport & LOGGER_LOCAL) {
  3. extern struct android_log_transport_write localLoggerWrite;
  4. __android_log_add_transport(&__android_log_transport_write,
  5. &localLoggerWrite);
  6. }
  7. if ((__android_log_transport == LOGGER_DEFAULT) ||
  8. (__android_log_transport & LOGGER_LOGD)) {
  9. #if (FAKE_LOG_DEVICE == 0)
  10. extern struct android_log_transport_write logdLoggerWrite;
  11. extern struct android_log_transport_write pmsgLoggerWrite;
  12. __android_log_add_transport(&__android_log_transport_write,
  13. &logdLoggerWrite);
  14. __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite);
  15. #else
  16. extern struct android_log_transport_write fakeLoggerWrite;
  17. __android_log_add_transport(&__android_log_transport_write,
  18. &fakeLoggerWrite);
  19. #endif
  20. }
  21. ...
  22. ...

对于使用LOGD来说,最终使用到的是logdLoggerWrite:


   
   
  1. LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
  2. .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
  3. .context.sock = -EBADF,
  4. .name = "logd",
  5. .available = logdAvailable,
  6. .open = logdOpen,
  7. .close = logdClose,
  8. .write = logdWrite,
  9. };

所以对于logd来说__write_to_log_daemon最终调用的write就是这里的logdwrite,具体请查看logd_writer.c源码。

 

logd 在initrc中

可以看到logd会通过3个socket进行通信、管理。而且指启动一次。

 

logd.main()

在system/core/lodgd/main.cpp文件的main函数中,创建了LogBuffer、LogReader、LogListener和CommandListener四个对象:

  • LogBuffer用于管理log;
  • LogReader用于将log传递给logcat;
  • LogListener用于监听是否有log写入logd;
  • CommandListener用于监听是否有命令发送给logd。

 

Logd-reinit 进程

Logd-reinit 进程在启动时,会给logd进程发送reinit命令,logd在收到命令后,会重新初始化LogBuffer。

在system/core/lodgd/main.cpp文件的main函数中会创建一个线程用于监测是否有reinit请求

if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) {
   
   

在reinit_thread_start函数中,会重新初始化各个log区的大小,以及其他参数的初始化,但不会重新生成LogBuffer对象。相关代码如下:


   
   
  1. // Anything that reads persist.<property>
  2. if (logBuf) {
  3. logBuf-> init();
  4. logBuf-> initPrune( nullptr);
  5. }

 

保存log

  • 创建LogBuffer对象,在classLogBuffer类中,定义了一个list容器,保存了指向LogBufferElement对象的指针,创建LogBuffer对象时在其构造函数中会调用LogBuffer::init()函数初始化各log域(如main/system/kernel/crash等)的大小。
  • 创建LogListener对象并开始监听

   
   
  1. LogListener *swl = newLogListener(logBuf, reader);
  2. // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
  3. if(swl-> startListener( 600)) {
  4. exit( 1);
  5. }
  • 在startListener函数中创建线程,线程注册函数为SocketListener::threadStart;
  • 执行runListener函数,如果socket监听到数据,则执行onDataAvailable函数进行处理;
  • 调用logbuf->log(LogBuffer::log),这个函数很重要,新建一个LogBufferElement对象(用于保存log),调用mLogElements.insert将LogBufferElement加入list容器,实现log的保存。

 

读取log

可通过logcat工具获取logd log,logcat 相关代码所在路径:system/core/logcat

通过logcat获取的log,并不完全是按照log分类来打印的,如在KERNEL log中可能存在MAIN log。

logcat实现的大部分函数都在logcat/logcat.cpp文件中,其中__logcat函数是最重要的函数,其负责logcat 输入参数的解析以及log的处理。

logcat 最终读取log通过liblog/logd_reader.c 中的logdRead函数实现。此函数负责打开/dev/logdr,并通过socket获取log。

 

至于代码中的log级别等信息这里就暂不做解释了,以liblog下log.h为准。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值