本文主要是介绍解读Android LOG机制的实现:(5)获取LOG的应用程序LogCat,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
解读Android LOG机制的实现:(5)获取LOG的应用程序LogCat
田海立@CSDN
2011/07/27
Android提供的LOG机制的实现贯穿了Java,JNI,本地c/c++实现以及LINUX内核驱动等Android的各个层次,并且简单明晰,是一个相当不错的解读案例。本系列文章针对LOG机制的内部实现机理进行解读,本文是本系列的第五篇,解读应用程序LogCat如何通过对设备文件的open()/select()/read()来获取LOG信息。
从前文知道,LOG被写入到了驱动的节点,那如何获取这些LOG信息并呈现出来的呢?ANDROID里是有个叫LogCat的应用程序被用来获取LOG信息。LogCat不仅从设备节点处获取LOG,并且还提供了很多选项供用户来过滤、控制输出格式等。本文只讲解如何获取LOG部分,相关的LogCat的使用方式,可参考Android的Logcat命令详解。
LogCat是在文件system/core/logcat/logcat.cpp中实现的。
从Logger设备驱动的实现知道,Log的读取是阻塞的操作,亦即,有数据可用,读出数据;否则,读操作会被BLOCK,相应的读进程也会被挂起等待。下面看应用程序LogCat中如何实现读的,这可能需要不断回头与写操作和驱动实现结合来看。
看具体实现之前,先看一个logcat中定义的重要的结构体log_device_t。其中的重要的成员在后面用到的时候再具体解释。
一、打开设备节点
Android的Logcat命令详解的命令参数-b <buffer>知道,logcat是可以通过参数来指定对哪个buffer(main/radio/event)进行操作的。Logcat的b参数解析的地方,是通过传递进来的参数(main/radio/event)来创建了一个上面的结构变量,而这些结构通过log_device_t.next链接起来。
if (devices) {dev = devices;while (dev->next) {dev = dev->next;}dev->next = new log_device_t(buf, binary, optarg[0]);} else {devices = new log_device_t(buf, binary, optarg[0]);}
而创建实例的时候的参数被保留了下来,用于后续操作。
<buf>是由LOG_FILE_DIR和optarg(-b参数)组合在一起的(为:“/dev/log/main”,“/dev/log/event”或“/dev/log/radio”),保留在device: char*;
<binary>保留在binary: bool;
<optarg[0]>是-b参数的第一个字符,保存在label: char中。
好了,下面就有了打开设备节点时的参数:
dev->fd = open(dev->device, mode);
dev->device根据-b的参数可能为“/dev/log/main”,“/dev/log/event”或“/dev/log/radio”;
mode缺省时为O_RDONLY,读取。只要在运行logcat时,用了-c参数清除log时才以O_WRONLY打开。
而打开文件的文件操作符保存在log_device_t的fd域中,用于后续的操作。
获取Log的操作都是在readLogLines(log_device_t* devices)中实现的。
因为logcat可能会同时操作多个Buffer,而read()会阻塞读取进程,对其他Buffer的读取就不能进行,所以这里用select()来判断可读取的Buffer。
二、select选取可读取的Buffer
Logcat把log_device_t中的所有的buffer的文件操作符dev->fd,都放在readset中[line#7],做为select()的里的<readfds: fd_set*>读参数,来获取可读取的Buffer。这样当任何一个Buffer上有LOG数据时,select()都会返回。当然等待过程中也忽略掉其他signal的影响。相应的代码如下:
fd_set readset; do {timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.FD_ZERO(&readset);for (dev=devices; dev; dev = dev->next) {FD_SET(dev->fd, &readset);}result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);} while (result == -1 && errno == EINTR);
三、读LOG操作
select()返回之后,通过循环判定dev->fd是否在readset里被设置(FD_ISSET)[line#3],知道哪个log buffer里已经有数据了。
if (result >= 0) {for (dev=devices; dev; dev = dev->next) {if (FD_ISSET(dev->fd, &readset)) {queued_entry_t* entry = new queued_entry_t();/* NOTE: driver guarantees we read exactly one full entry */ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);//…
通过read()读取[line#6]已经有数据的LOG Buffer的文件操作符dev->fd就可得到新到来的log了。
应用程序logcat中已经获取了LOG信息,接下来对数据的处理就都可以在这里进行了,可以过滤,写文件,格式化输入等操作。详细的logcat的命令参数可参见Android的Logcat命令详解。
【本系列文章】
解读Android LOG机制的实现:(1)LOG的实现架构
解读LOG机制的实现架构。
解读Android LOG机制的实现:(2)Java域输出LOG
解读Android的Java程序中如何输出LOG信息到LOG的体系中。
解读Android LOG机制的实现:(3)JNI及NATIVE域写设备文件
解读android.util.Log的JNI实现,以及在c/c++的本地实现中如何操作设备文件写Log信息。
解读Android LOG机制的实现:(4)LOG设备驱动logger
解读LINUX内核中的设备驱动Logger中实现。Logger是Android为Linux写的一个MISC类型驱动,用循环队列实现了读者/写者。Logger是整个LOG机制实现的核心。
解读Android LOG机制的实现:(5)获取LOG程序LogCat
解读应用程序LogCat如何通过对设备文件的open()/select()/read()来获取LOG信息。
解读Android LOG机制的实现:(6)c/c++域使用LOG
解读Android的c/c++程序中如何使用LOG机制记录LOG信息。
这篇关于解读Android LOG机制的实现:(5)获取LOG的应用程序LogCat的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!