Logcat源码分析(三)

来源:互联网 发布:a星算法 定位 编辑:程序博客网 时间:2024/05/03 17:45
三、读取日志设备文件
读取日志设备文件内容的readLogLines()函数也在logcat.cpp中,只是它是定义在Android命名空间中。所以要以Android::readLogLines(devices)方式调用。
static void readLogLines(log_device_t* devices)  
{  
    log_device_t* dev;  
    int max = 0;  
    int ret;  
    int queued_lines = 0;  
    bool sleep = true;  
  
    int result;  
    fd_set readset;  
  
    for (dev=devices; dev; dev = dev->next) {  
        if (dev->fd > max) {  
            max = dev->fd;  
        }  
    }  
  
    while (1) {  
        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);  
 
        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);  
                    if (ret < 0) {  
                        if (errno == EINTR) {  
                            delete entry;  
                            goto next;  
                        }  
                        if (errno == EAGAIN) {  
                            delete entry;  
                            break;  
                        }  
                        perror("logcat read");  
                        exit(EXIT_FAILURE);  
                    }  
                    else if (!ret) {  
                        fprintf(stderr, "read: Unexpected EOF!\n");  
                        exit(EXIT_FAILURE);  
                    }  
  
                    entry->entry.msg[entry->entry.len] = '\0';  
  
                    dev->enqueue(entry);  
                    ++queued_lines;  
                }  
            }  
  
            if (result == 0) {  
                // we did our short timeout trick and there's nothing new   
                // print everything we have and wait for more data   
                sleep = true;  
                while (true) {  
                    chooseFirst(devices, &dev);  
                    if (dev == NULL) {  
                        break;  
                    }  
                    if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {  
                        printNextEntry(dev);  
                    } else {  
                        skipNextEntry(dev);  
                    }  
                    --queued_lines;  
                }  
  
                // the caller requested to just dump the log and exit   
                if (g_nonblock) {  
                    exit(0);  
                }  
            } else {  
                // print all that aren't the last in their list   
                sleep = false;  
                while (g_tail_lines == 0 || queued_lines > g_tail_lines) {  
                    chooseFirst(devices, &dev);  
                    if (dev == NULL || dev->queue->next == NULL) {  
                        break;  
                    }  
                    if (g_tail_lines == 0) {  
                        printNextEntry(dev);  
                    } else {  
                        skipNextEntry(dev);  
                    }  
                    --queued_lines;  
                }  
            }  
        }  
next:  
        ;  
    }  
}  
由于可能同时打开了多个日志设备文件,这里使用select函数来同时监控哪个文件当前可读:
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);  
如果result >= 0,就表示有日志设备文件可读或者超时。接着,用一个for语句检查哪个设备文件可读,即FD_ISSET(dev->fd, &readset)是否为true,如果为true,表明可读,就要进一步通过read函数将日志读出,注意,每次只读出一条日志记录:
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);  
               if (ret < 0) {  
                   if (errno == EINTR) {  
                       delete entry;  
                       goto next;  
                   }  
                   if (errno == EAGAIN) {  
                       delete entry;  
                       break;  
                   }  
                   perror("logcat read");  
                   exit(EXIT_FAILURE);  
               }  
               else if (!ret) {  
                   fprintf(stderr, "read: Unexpected EOF!\n");  
                   exit(EXIT_FAILURE);  
               }  
  
               entry->entry.msg[entry->entry.len] = '\0';  
  
               dev->enqueue(entry);  
               ++queued_lines;  
           }  
       }   
调用read函数之前,先创建一个日志记录项entry,接着调用read函数将日志读到entry->buf中,最后调用dev->enqueue(entry)将日志记录加入到日志队例中去。同时,把当前的日志记录数保存在queued_lines变量中。
原创粉丝点击