android 6.0 logcat机制(二)logcat从logd中获取log保存到文件中

来源:互联网 发布:回归分析 数据标准化 编辑:程序博客网 时间:2024/05/21 09:31

这篇博客分析的是logcat是如何获取logd中的log,然后写入文件。


一、设置保存log文件的路径

在手机刚开机的时候,会有类似如下命令执行

/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log



/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log

/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log

我们先看下logcat的如何对这个命令的实现的,在其main函数中,对f命令的实现如下:

[java] view plain copy
  1. case 'f':  
  2.     if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {  
  3.         tail_time = lastLogTime(optarg);  
  4.     }  
  5.     // redirect output to a file  
  6.     g_outputFileName = optarg;  

把文件名保存在g_outputFileName了,然后在main函数后面会调用setupOutput函数,我们来看下这个函数:

[java] view plain copy
  1. static void setupOutput()  
  2. {  
  3.   
  4.     if (g_outputFileName == NULL) {  
  5.         g_outFD = STDOUT_FILENO;  
  6.   
  7.     } else {  
  8.         if (set_sched_policy(0, SP_BACKGROUND) < 0) {  
  9.             fprintf(stderr, "failed to set background scheduling policy\n");  
  10.         }  
  11.   
  12.         struct sched_param param;  
  13.         memset(¶m, 0, sizeof(param));  
  14.         if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {  
  15.             fprintf(stderr, "failed to set to batch scheduler\n");  
  16.         }  
  17.   
  18.         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {  
  19.             fprintf(stderr, "failed set to priority\n");  
  20.         }  
  21.   
  22.         g_outFD = openLogFile (g_outputFileName);//得到了fd  
  23.   
  24.         if (g_outFD < 0) {  
  25.             logcat_panic(false"couldn't open output file");  
  26.         }  
  27.   
  28.         struct stat statbuf;  
  29.         if (fstat(g_outFD, &statbuf) == -1) {  
  30.             close(g_outFD);  
  31.             logcat_panic(false"couldn't get output file stat\n");  
  32.         }  
  33.   
  34.         if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {  
  35.             close(g_outFD);  
  36.             logcat_panic(false"invalid output file stat\n");  
  37.         }  
  38.   
  39.         g_outByteCount = statbuf.st_size;  
  40.     }  
  41. }  

在这个函数中把文件的fd获取到了,是g_outFD。

最后我们可以在printBinary函数中往这个文件中写值。

[java] view plain copy
  1. void printBinary(struct log_msg *buf)  
  2. {  
  3.     size_t size = buf->len();  
  4.   
  5.     TEMP_FAILURE_RETRY(write(g_outFD, buf, size));  
  6. }  

也可以通过processBuffer来往文件写log。我们最后应该是通过processBuffer来写log的。

也就是上面的命令最终会把log保存在/data/local/log/logcat-radio.log文件下,当然这只是radio的log。


二、logcat获取logd中的log

而我们再看logcat的main最后是一个死循环,一直调用android_logger_list_read来从logd中获取log,然后再打印。

[java] view plain copy
  1. while (1) {  
  2.     struct log_msg log_msg;  
  3.     log_device_t* d;  
  4.     int ret = android_logger_list_read(logger_list, &log_msg);//调用android_logger_list_read获取log  
  5.   
  6.     if (ret == 0) {  
  7.         logcat_panic(false"read: unexpected EOF!\n");  
  8.     }  
  9.   
  10.     if (ret < 0) {  
  11.         if (ret == -EAGAIN) {  
  12.             break;  
  13.         }  
  14.   
  15.         if (ret == -EIO) {  
  16.             logcat_panic(false"read: unexpected EOF!\n");  
  17.         }  
  18.         if (ret == -EINVAL) {  
  19.             logcat_panic(false"read: unexpected length.\n");  
  20.         }  
  21.         logcat_panic(false"logcat read failure");  
  22.     }  
  23.   
  24.     for(d = devices; d; d = d->next) {  
  25.         if (android_name_to_log_id(d->device) == log_msg.id()) {  
  26.             break;  
  27.         }  
  28.     }  
  29.     if (!d) {  
  30.         g_devCount = 2// set to Multiple  
  31.         d = &unexpected;  
  32.         d->binary = log_msg.id() == LOG_ID_EVENTS;  
  33.     }  
  34.   
  35.     if (dev != d) {  
  36.         dev = d;  
  37.         maybePrintStart(dev, printDividers);  
  38.     }  
  39.     if (g_printBinary) {  
  40.         printBinary(&log_msg);  
  41.     } else {  
  42.         processBuffer(dev, &log_msg);  
  43.     }  
  44. }  
  45.   
  46. android_logger_list_free(logger_list);  
  47.   
  48. return EXIT_SUCCESS;  

打印的话就是通过之前传进来的文件,写log到该文件的fd。


android_logger_list_read函数就是通过socket连接logd获取log。

[java] view plain copy
  1. int android_logger_list_read(struct logger_list *logger_list,  
  2.                              struct log_msg *log_msg)  
  3. {  
  4.     int ret, e;  
  5.     struct logger *logger;  
  6.     struct sigaction ignore;  
  7.     struct sigaction old_sigaction;  
  8.     unsigned int old_alarm = 0;  
  9.   
  10.     if (!logger_list) {  
  11.         return -EINVAL;  
  12.     }  
  13.   
  14.     if (logger_list->mode & ANDROID_LOG_PSTORE) {  
  15.         return android_logger_list_read_pstore(logger_list, log_msg);  
  16.     }  
  17.   
  18.     if (logger_list->mode & ANDROID_LOG_NONBLOCK) {  
  19.         memset(&ignore, 0, sizeof(ignore));  
  20.         ignore.sa_handler = caught_signal;  
  21.         sigemptyset(&ignore.sa_mask);  
  22.     }  
  23.   
  24.     if (logger_list->sock < 0) {  
  25.         char buffer[256], *cp, c;  
  26.   
  27.         int sock = socket_local_client("logdr",  
  28.                                        ANDROID_SOCKET_NAMESPACE_RESERVED,  
  29.                                        SOCK_SEQPACKET);  
  30.         if (sock < 0) {  
  31.             if ((sock == -1) && errno) {  
  32.                 return -errno;  
  33.             }  
  34.             return sock;  
  35.         }  
上面logdr就是logcat到logd的socket。


三、总结

3.1 开3个进程保存不同log

我们手机上会开3个logcat进程来保存log,这3个进程会一直开着就是上面的死循环来不断保存log。

/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log



/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log

/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log


3.2 kernel相关log

另外kernel的log是通过log_read_kern.c中的函数来实现的,而写的话通过logd_write_kern.c来实现的。

是通过节点来实现,而不是通过socket到logd实现的

节点:

dev/log/main

dev/log/radio

dev/log/system

dev/log/events


下篇博客我们主要说下logd是如何处理logcat的请求读log的。


原文地址: http://blog.csdn.net/kc58236582/article/details/51075591

原创粉丝点击