Android中 logd 详解

Android中 logd 详解logd 是 AndroidL 版本提出来的概念 其作用是保存 Android 运行期间的 log 日志

大家好,欢迎来到IT知识分享网。

文章出处:Android中 logd 详解

请转载的朋友标明出处,请支持原创~~ 

0. 前言

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

源码基于:Android P

1. 架构

Android中 logd 详解

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() 接口。

2. 源码剖析

先来看下 __android_log_write()

LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag, const char* msg) { return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg); }

调用 __android_log_buf_write()

LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) { struct iovec vec[3]; char tmp_tag[32]; ... ... vec[0].iov_base = (unsigned char*)&prio; vec[0].iov_len = 1; vec[1].iov_base = (void*)tag; vec[1].iov_len = strlen(tag) + 1; vec[2].iov_base = (void*)msg; vec[2].iov_len = strlen(msg) + 1; return write_to_log(bufID, vec, 3); }

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

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

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

static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) { int ret, save_errno = errno; __android_log_lock(); if (write_to_log == __write_to_log_init) { ret = __write_to_log_initialize(); if (ret < 0) { __android_log_unlock(); if (!list_empty(&__android_log_persist_write)) { __write_to_log_daemon(log_id, vec, nr); } errno = save_errno; return ret; } write_to_log = __write_to_log_daemon; } __android_log_unlock(); ret = write_to_log(log_id, vec, nr); errno = save_errno; return ret; }

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

 write_transport_for_each(node, &__android_log_transport_write) { if (node->logMask & i) { ssize_t retval; retval = (*node->write)(log_id, &ts, vec, nr); if (ret >= 0) { ret = retval; } } }

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

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

LIBLOG_HIDDEN void __android_log_config_write() { if (__android_log_transport & LOGGER_LOCAL) { extern struct android_log_transport_write localLoggerWrite; __android_log_add_transport(&__android_log_transport_write, &localLoggerWrite); } if ((__android_log_transport == LOGGER_DEFAULT) || (__android_log_transport & LOGGER_LOGD)) { #if (FAKE_LOG_DEVICE == 0) extern struct android_log_transport_write logdLoggerWrite; extern struct android_log_transport_write pmsgLoggerWrite; __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite); __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite); #else extern struct android_log_transport_write fakeLoggerWrite; __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite); #endif } ... ...

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

LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = { .node = { &logdLoggerWrite.node, &logdLoggerWrite.node }, .context.sock = -EBADF, .name = "logd", .available = logdAvailable, .open = logdOpen, .close = logdClose, .write = logdWrite, };

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

3. logd 在initrc中

Android中 logd 详解

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

4. logd.main()

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

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

5. 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对象。相关代码如下:

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

6. 保存log

  • 创建LogBuffer对象,在classLogBuffer类中,定义了一个list容器,保存了指向LogBufferElement对象的指针,创建LogBuffer对象时在其构造函数中会调用LogBuffer::init()函数初始化各log域(如main/system/kernel/crash等)的大小。
  • 创建LogListener对象并开始监听
LogListener *swl = newLogListener(logBuf, reader); // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value if(swl->startListener(600)) { exit(1); }
  • 在startListener函数中创建线程,线程注册函数为SocketListener::threadStart;
  • 执行runListener函数,如果socket监听到数据,则执行onDataAvailable函数进行处理;
  • 调用logbuf->log(LogBuffer::log),这个函数很重要,新建一个LogBufferElement对象(用于保存log),调用mLogElements.insert将LogBufferElement加入list容器,实现log的保存。

7. 读取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为准。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/145401.html

(0)
上一篇 2024-11-24 16:00
下一篇 2024-11-24 16:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信