> 文档中心 > Android源码分析-logcat源码分析,以及main,radio,system等log文件,包括select的多路复用的运用

Android源码分析-logcat源码分析,以及main,radio,system等log文件,包括select的多路复用的运用


logcat简介:

logcat用于输出日志到屏幕上,也可以将日志重定向到文件中。本篇主要分析logcat源码,顺便说一下logcat的典型用法。

logcat本身是一个可执行程序,需要依赖于adb命令执行,或者说,需要在adb shell命令行运行。
例如:

adb logcat > 1.log //将日志输出到1.log文件中。

adb shell

logcat -b main. // 输出类型为main的日志

-b ,指定要查看的日志缓冲区,是一个可选项。可以是system,events,radio,main。默认值是system和main 。可选值为:

system, events , radio, main

可以用-help来列出logcat的使用方法:

logcat -help

结果如下: 

 其余常用的选项是:

-c 清楚屏幕上的日志.   

例如,logcat -c

logcat源码分析:

编译:
logat源码主要分布在: 

system/core/logcat/logcat.cpp
system/core/include/cutils/logger.h

看Android.mk文件:

可见,使用了liblog库,编译出来的结果是可执行程序logcat。

我们从logcat.cpp的main函数开始分析。

核心代码如下:

int main(int argc, char argv){    ......//1. 参数check和解析    g_logformat = android_log_format_new();    if (argc == 2 && 0 == strcmp(argv[1], "--test")) { logprint_run_tests(); exit(0);    }    if (argc == 2 && 0 == strcmp(argv[1], "--help")) { android::show_help(argv[0]); exit(0);    }   // 参数的继续处理    for (;;) { int ret; ret = getopt(argc, argv, "cdt:gsQf:r::n:v:b:B"); if (ret next = new log_device_t(strdup("/dev/"LOGGER_LOG_SYSTEM), false, 's');     android::g_devCount++; }    }//dev = devices;    while (dev) { dev->fd = open(dev->device, mode);......//3.读取一行android::readLogLines(devices);}

分析:

1)根据输入的参数,进行相应的分析和处理:

例如,输入--help,就调用

android::show_help(argv[0]);

//显示help信息。

然后进入for无限循环。在for循环中,进一步进行参数处理。包括getopt中的这些值。

 ret = getopt(argc, argv, "cdt:gsQf:r::n:v:b:B");

函数用于过滤参数中是否包含cdt:gsQf:r::n:v:b:B中的值,并且返回这个值。

对于res的处理:

这个for循环也相对容易理解。有兴趣的同学可以继续看源代码。

2)对devices的分析:

devices的类型定义在logger.h中,如下:

#define LOGGER_LOG_MAIN"log/main"#define LOGGER_LOG_RADIO"log/radio"#define LOGGER_LOG_EVENTS"log/events"#define LOGGER_LOG_SYSTEM"log/system"

可见,logcat -b后面的参数对应于文件系统中的某一个(几个)文件。

3)readLines函数的实现:

实现原理,实现一个无限循环,采用select多路复用,从

devices

中获取数据,这里的devices就是前面提到的

system, events , radio, main

,核心代码片段如下:

 多路复用select: 监听devices设备,超时时间设置为5ms。将结果通过read函数读取到内存中,即读取到queued_entry_t相关的内存中。

queued_entry_t数据结构的定义:
struct log_device_t {    char* device;    bool binary;    int fd;    bool printed;    char label;    queued_entry_t* queue;    log_device_t* next;    log_device_t(char* d, bool b, char l) { device = d; binary = b; label = l; queue = NULL; next = NULL; printed = false;    }    void enqueue(queued_entry_t* entry) { if (this->queue == NULL) {     this->queue = entry; } else {     queued_entry_t e = &this->queue;     while (*e && cmp(entry, *e) >= 0) {  e = &((*e)->next);     }     entry->next = *e;     *e = entry; }    }};

这是一个队列,用链表实现的。

附:多路复用select的使用:

Linux系统中IO多路复用select函数的使用,及其在Android系统中的运用_liranke的博客-CSDN博客


K歌软件