Android日志系统Logcat源代码简要分析

上传人:飞*** 文档编号:43781341 上传时间:2018-06-07 格式:DOCX 页数:22 大小:58.11KB
返回 下载 相关 举报
Android日志系统Logcat源代码简要分析_第1页
第1页 / 共22页
Android日志系统Logcat源代码简要分析_第2页
第2页 / 共22页
Android日志系统Logcat源代码简要分析_第3页
第3页 / 共22页
Android日志系统Logcat源代码简要分析_第4页
第4页 / 共22页
Android日志系统Logcat源代码简要分析_第5页
第5页 / 共22页
点击查看更多>>
资源描述

《Android日志系统Logcat源代码简要分析》由会员分享,可在线阅读,更多相关《Android日志系统Logcat源代码简要分析(22页珍藏版)》请在金锄头文库上搜索。

1、 在前面两篇文章 Android 日志系统驱动程序 Logger 源代码分析和 Android 应用程序框架层和系统运行库层日志系统源代码中,介绍了 Android 内核空间层、系统运行库层和应用程序框架层日志系统相关的源代码,其中,后一篇文章着重介绍了日志的写入操作。为了描述完整性,这篇文章着重介绍日志的读取操作,这就是我们在开发 Android 应用程序时,经常要用到日志查看工具 Logcat 了。Logcat 工具内置在 Android 系统中,可以在主机上通过 adb logcat 命令来查看模拟机上日志信息。Logcat 工具的用法很丰富,因此,源代码也比较多,本文并不打算完整地介绍

2、整个 Logcat 工具的源代码,主要是介绍 Logcat 读取日志的主线,即从打开日志设备文件到读取日志设备文件的日志记录到输出日志记录的主要过程,希望能起到一个抛砖引玉的作用。Logcat 工具源代码位于 system/core/logcat 目录下,只有一个源代码文件logcat.cpp,编译后生成的可执行文件位于 out/target/product/generic/system/bin目录下,在模拟机中,可以在/system/bin 目录下看到 logcat 工具。下面我们就分段来阅读 logcat.cpp 源代码文件。一. Logcat 工具的相关数据结构。这些数据结构是用来保存从

3、日志设备文件读出来的日志记录:view plain1.struct queued_entry_t 2. union 3. unsigned char bufLOGGER_ENTRY_MAX_LEN + 1 _attribute_(aligned(4); 4. struct logger_entry entry _attribute_(aligned(4); 5. ; 6. queued_entry_t* next; 7. 8. queued_entry_t() 9. next = NULL; 10. 11. ; 12. 13. struct log_device_t 14. char* dev

4、ice; 15. bool binary; 16. int fd; 17. bool printed; 18. char label; 19. 20. queued_entry_t* queue; 21. log_device_t* next; 22. 23. log_device_t(char* d, bool b, char l) 24. device = d; 25. binary = b; 26. label = l; 27. queue = NULL; 28. next = NULL; 29. printed = false; 30. 31. 32. void enqueue(que

5、ued_entry_t* entry) 33. if (this-queue = NULL) 34. this-queue = entry; 35. else 36. queued_entry_t* e = 37. while (*e 39. 40. entry-next = *e; 41. *e = entry; 42. 43. 44. ; 其中,宏 LOGGER_ENTRY_MAX_LEN 和 struct logger_entry 定义在system/core/include/cutils/logger.h 文件中,在 Android 应用程序框架层和系统运行库层日志系统源代码分析一文有

6、提到,为了方便描述,这里列出这个宏和结构体的定义:view plain1.struct logger_entry 2. _u16 len; /* length of the payload */ 3. _u16 _pad; /* no matter what, we get 2 bytes of padding */ 4. _s32 pid; /* generating processs pid */ 5. _s32 tid; /* generating processs tid */ 6. _s32 sec; /* seconds since Epoch */ 7. _s32 nsec; /

7、* nanoseconds */ 8. char msg0; /* the entrys payload */ 9.; 10. 11. #define LOGGER_ENTRY_MAX_LEN (4*1024) 从结构体 struct queued_entry_t 和 struct log_device_t 的定义可以看出,每一个 log_device_t 都包含有一个 queued_entry_t 队列,queued_entry_t 就是对应从日志设备文件读取出来的一条日志记录了,而 log_device_t 则是对应一个日志设备文件上下文。在 Android 日志系统驱动程序 Logger

8、 源代码分析一文中,我们曾提到,Android 日志系统有三个日志设备文件,分别是/dev/log/main、/dev/log/events 和/dev/log/radio。每个日志设备上下文通过其 next 成员指针连接起来,每个设备文件上下文的日志记录也是通过 next 指针连接起来。日志记录队例是按时间戳从小到大排列的,这个 log_device_t:enqueue 函数可以看出,当要插入一条日志记录的时候,先队列头开始查找,直到找到一个时间戳比当前要插入的日志记录的时间戳大的日志记录的位置,然后插入当前日志记录。比较函数 cmp 的定义如下:view plain1.static int

9、 cmp(queued_entry_t* a, queued_entry_t* b) 2. int n = a-entry.sec - b-entry.sec; 3. if (n != 0) 4. return n; 5. 6. return a-entry.nsec - b-entry.nsec; 7. 为什么日志记录要按照时间戳从小到大排序呢?原来,Logcat 在使用时,可以指定一个参数-t ,可以指定只显示最新 count 条记录,超过 count 的记录将被丢弃,在这里的实现中,就是要把排在队列前面的多余日记记录丢弃了,因为排在前面的日志记录是最旧的,默认是显示所有的日志记录。在下面

10、的代码中,我们还会继续分析这个过程。二. 打开日志设备文件。Logcat 工具的入口函数 main,打开日志设备文件和一些初始化的工作也是在这里进行。main 函数的内容也比较多,前面的逻辑都是解析命令行参数。这里假设我们使用 logcat 工具时,不带任何参数。这不会影响我们分析 logcat 读取日志的主线,有兴趣的读取可以自行分析解析命令行参数的逻辑。分析完命令行参数以后,就开始要创建日志设备文件上下文结构体 struct log_device_t 了:view plain1.if (!devices) 2. devices = new log_device_t(strdup(“/dev

11、/“LOGGER_LOG_MAIN), false, m); 3. android:g_devCount = 1; 4. int accessmode = 5. (mode 7. / only add this if its available 8. if (0 = access(“/dev/“LOGGER_LOG_SYSTEM, accessmode) 9. devices-next = new log_device_t(strdup(“/dev/“LOGGER_LOG_SYSTEM), false, s); 10. android:g_devCount+; 11. 12. 由于我们假设使用

12、 logcat 时,不带任何命令行参数,这里的 devices 变量为NULL,因此,就会默认创建/dev/log/main 设备上下文结构体,如果存在/dev/log/system 设备文件,也会一并创建。宏 LOGGER_LOG_MAIN 和LOGGER_LOG_SYSTEM 也是定义在 system/core/include/cutils/logger.h 文件中:view plain1.#define LOGGER_LOG_MAIN “log/main“ 2.#define LOGGER_LOG_SYSTEM “log/system“ 我们在 Android 日志系统驱动程序 Logg

13、er 源代码分析一文中看到,在Android 日志系统驱动程序 Logger 中,默认是不创建/dev/log/system 设备文件的。往下看,调用 setupOutput()函数来初始化输出文件:view plain1.android:setupOutput(); setupOutput()函数定义如下:view plain1.static void setupOutput() 2. 3. 4. if (g_outputFileName = NULL) 5. g_outFD = STDOUT_FILENO; 6. 7. else 8. struct stat statbuf; 9. 10.

14、 g_outFD = openLogFile (g_outputFileName); 11. 12. if (g_outFD 选项,日志内容就输出到 filename 文件中,否则,就输出到标准输出控制台去了。再接下来,就是打开日志设备文件了:view plain1.dev = devices; 2.while (dev) 3. dev-fd = open(dev-device, mode); 4. if (dev-fd device, strerror(errno); 7. exit(EXIT_FAILURE); 8. 9. 10. if (clearLog) 11. int ret; 12. ret = android:clearLog(dev-fd); 13. if (ret) 14. perror(“ioctl“); 15. exit(EXIT_

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号