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博客