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

如果为负数,即size < 0,就表示出错了,退出程序。

接着验证日志缓冲区可读内容的大小,即调用Android::getLogReadableSize函数:

/* returns the readable size of the log's ring buffer (that is, amount of the log consumed) */   static int getLogReadableSize(int logfd)   {       return ioctl(logfd, LOGGER_GET_LOG_LEN);   }  

       如果返回负数,即readable < 0,也表示出错了,退出程序。

接下去的printf语句,就是输出日志缓冲区的大小以及可读日志的大小到控制台去了。

继续看下看代码,如果执行logcat命令的目的是清空日志或者获取日志的大小信息,则现在就完成使命了,可以退出程序了:

if (getLogSize) {       return 0;   }   if (clearLog) {       return 0;   }  

        否则,就要开始读取设备文件的日志记录了:

 

android::readLogLines(devices);  

       至此日志设备文件就打开并且初始化好了,下面,我们继续分析从日志设备文件读取日志记录的操作,即readLogLines函数。

三. 读取日志设备文件。

读取日志设备文件内容的函数是readLogLines函数:

 

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;              }          }         

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwjfgs.html