Android日志系统Logcat源代码简要分析Android日志系统Logcat源代码简要分析
在前面篇文章两 Android 日志系统统统程序 Logger 源代统分析和 Android 统用程序架统和系统行统统日志系统源代统框运中~介统了Android内运核空统统、系统行统统和统用程序架统日志系统相统的源代统~其中~后一篇文章着重介统了日志的入操作。统了框写
描述完整性~统篇文章着重介统日志的统取操作~统就是我统在统统Android统用程序统~统常要用到日志统看工具Logcat了。
Logcat工具置在内Android系统中~可以在主机上通统adb logcat命令...
Android日志系统Logcat源代码简要分析
在前面篇文章两 Android 日志系统统统程序 Logger 源代统分析和 Android 统用程序架统和系统行统统日志系统源代统框运中~介统了Android内运核空统统、系统行统统和统用程序架统日志系统相统的源代统~其中~后一篇文章着重介统了日志的入操作。统了框写
描述完整性~统篇文章着重介统日志的统取操作~统就是我统在统统Android统用程序统~统常要用到日志统看工具Logcat了。
Logcat工具置在内Android系统中~可以在主机上通统adb logcat命令统来看模统机上日志信息。Logcat工具的用法富~因此~源代统也比统多~本文不很丰并
打算完整地介统整个Logcat工具的源代统~主要是介统Logcat统取日志的主统~即从打统日志统统文件到统取日志统统文件的日志统统到统出日志统统的主要统程~希望能起到一个抛统引玉的作用。
Logcat工具源代统位于system/core/logcat目统下~只有一源代统文件个logcat.cpp~统统后生成的可统行文件位于out/target/product/generic/system/bin目统下~在模统机中~可以在/system/bin目统下看到logcat工具。下面我统就分段统统来logcat.cpp源代统文件。
一. Logcat工具的相统据统。数构
统些据统是用保存日志统统文件统出的日志统统,数构来从来
view plain
1.struct queued_entry_t {
2. union {
3. unsigned char buf[LOGGER_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* device;
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(queued_entry_t* entry) {
33. if (this->queue == NULL) {
34. this->queue = entry;
35. } else {
36. queued_entry_t** e = &this->queue;
37. while (*e && cmp(entry, *e) >= 0) {
38. e = &((*e)->next);
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 统用程序架统和系统行统统框运日志系统源代统分析一文有提到~统了方便描述~统里列出统宏和统的定统,个构体view plain
1.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 process's pid */
5. __s32 tid; /* generating process's tid */
6. __s32 sec; /* seconds since Epoch */
7. __s32 nsec; /* nanoseconds */
8. char msg[0]; /* the entry's 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 源代统分析一文中~我统曾提到~Android日志系统有三日志统统文件~分统是个/dev/log/main、/dev/log/events和/dev/log/radio。
每日志统统上下文通统其个next成统指统统接起~每统统文件上下文的日志统统来个
也是通统next指统统接起。日志统统统例是按统统小到大排列的~统来戳从个
log_device_t::enqueue函可以看出~要入一日志统统的统候~先统列统统始统数当插条找~
直到到一统统比前要入的日志统统的统统大的日志统统的位置~然后入统前找个戳当插戳插当
日志统统。比统函数cmp的定统如下,
view plain
1.static int 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的统统被统~将弃在统里的统统中~就是要把排在统列前面的多余日统统统统了~因统排在前面的日志统统是弃
最的~默统是统示所有的日志统统。在下面的代统中~我统统统统分析统统程。旧会个
二. 打统日志统统文件。
Logcat工具的入口函数main~打统日志统统文件和一些初始化的工作也是在统里统行。main函的容也比统多~前面的统统都是解析命令行。统里假统我统使数内参数
用logcat工具统~不统任何。统不影我统分析参数会响logcat统取日志的主统~有统趣的统取可以自行分析解析命令行的统统。参数
分析完命令行以后~就统始要统建日志统统文件上下文统参数构体struct log_device_t了,
view plain
1.if (!devices) {
2. devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, 'm');
3. android::g_devCount = 1;
4. int accessmode =
5. (mode & O_RDONLY) ? R_OK : 0
6. | (mode & O_WRONLY) ? W_OK : 0;
7. // only add this if it's 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.}
由于我统假统使用logcat统~不统任何命令行~统里的参数devices统量统NULL~因此~就默统统建会/dev/log/main统统上下文统~如果存在构体/dev/log/system
统统文件~也一统建。宏会并LOGGER_LOG_MAIN和LOGGER_LOG_SYSTEM也是定统在system/core/include/cutils/logger.h文件中,
view plain
1.#define LOGGER_LOG_MAIN "log/main"
2.#define LOGGER_LOG_SYSTEM "log/system"
我统在 Android 日志系统统统程序 Logger 源代统分析一文中看到~在Android
日志系统统统程序Logger中~默统是不统建/dev/log/system统统文件的。
往下看~统用setupOutput()函初始化统出文件,数来
view plain
1.android::setupOutput();
setupOutput()函定统如下,数view plain
1.static void setupOutput()
2.{
3.
4. if (g_outputFileName == NULL) {
5. g_outFD = STDOUT_FILENO;
6.
7. } else {
8. struct stat statbuf;
9.
10. g_outFD = openLogFile (g_outputFileName);
11.
12. if (g_outFD < 0) {
13. perror ("couldn't open output file");
14. exit(-1);
15. }
16.
17. fstat(g_outFD, &statbuf);
18.
19. g_outByteCount = statbuf.st_size;
20. }
21.}
如果我统在统行logcat命令统~指定了-f 统统~日志容就统出到内filename文件中~否统~就统出到统准统出控制台去了。
再接下~就是打统日志统统文件了,来
view plain
1.dev = devices;
2.while (dev) {
3. dev->fd = open(dev->device, mode);
4. if (dev->fd < 0) {
5. fprintf(stderr, "Unable to open log device '%s': %s\n",
6. dev->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_FAILURE);
16. }
17. }
18.
19. if (getLogSize) {
20. int size, readable;
21.
22. size = android::getLogSize(dev->fd); 23. if (size < 0) {
24. perror("ioctl");
25. exit(EXIT_FAILURE);
26. }
27.
28. readable = android::getLogReadableSize(dev->fd);
29. if (readable < 0) {
30. perror("ioctl");
31. exit(EXIT_FAILURE);
32. }
33.
34. printf("%s: ring buffer is %dKb (%dKb consumed), "
35. "max entry is %db, max payload is %db\n", dev->device, 36. size / 1024, readable / 1024, 37. (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
38. }
39.
40. dev = dev->next;
41.}
如果统行logcat命令的目的是空日志~清即clearLog统true~统统用
android::clearLog函统行空日志操作,数来清view plain
1.static int clearLog(int logfd)
2.{
3. return ioctl(logfd, LOGGER_FLUSH_LOG); 4.}
统里是通统统准的文件函数ioctl函统行日志空操作~具可以考数来清体参
logger统统程序的统统。
如果统行logcat命令的目的是统取日志存统的大小~内冲区即getLogSize统
true~通统统用android::getLogSize函统统,数
view plain
1./* returns the total size of the log's ring buffer */
2.static int getLogSize(int logfd)
3.{
4. return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE); 5.}
如果统统~数即size < 0~就示出统了~退出程序。
接着统统日志统可统容的大小~统用冲区内即android::getLogReadableSize函
数,
view plain
1./* returns the readable size of the log's ring buffer (that is, amount of the log consumed) */
2.static int getLogReadableSize(int logfd)
3.{
4. return ioctl(logfd, LOGGER_GET_LOG_LEN);
5.}
如果返回统~数即readable < 0~也表示出统了~退出程序。
接下去的printf统句~就是统出日志统的大小以及可统日志的大小到控制冲区
台去了。
统统看下看代统~如果统行logcat命令的目的是空日志或者统取日志的大小清信息~统统在就完成使命了~可以退出程序了,
view plain
1.if (getLogSize) {
2. return 0;
3.}
4.if (clearLog) {
5. return 0;
6.}
否统~就要统始统取统统文件的日志统统了,view plain
1.android::readLogLines(devices);
至此日志统统文件就打统且初始化好了~下面~我统统统分析日志统统文件统取并从
日志统统的操作~即readLogLines函。数
三. 统取日志统统文件。
统取日志统统文件容的函是内数readLogLines函,数view plain
1.static void readLogLines(log_device_t* devices)
2.{
3. log_device_t* dev;
4. int max = 0;
5. int ret;
6. int queued_lines = 0;
7. bool sleep = true;
8.
9. int result;
10. fd_set readset;
11.
12. for (dev=devices; dev; dev = dev->next) {
13. if (dev->fd > max) {
14. max = dev->fd;
15. }
16. }
17.
18. while (1) {
19. do {
20. timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR. 21. FD_ZERO(&readset);
22. for (dev=devices; dev; dev = dev->next) { 23. FD_SET(dev->fd, &readset); 24. }
25. result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
26. } while (result == -1 && errno == EINTR); 27.
28. if (result >= 0) {
29. for (dev=devices; dev; dev = dev->next) { 30. if (FD_ISSET(dev->fd, &readset)) { 31. queued_entry_t* entry = new queued_entry_t(); 32. /* NOTE: driver guarantees we read exactly one full entry */ 33. ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
34. if (ret < 0) {
35. if (errno == EINTR) { 36. delete entry;
37. goto next;
38. }
39. if (errno == EAGAIN) { 40. delete entry;
41. break;
42. }
43. perror("logcat read");
44. exit(EXIT_FAILURE);
45. }
46. else if (!ret) {
47. fprintf(stderr, "read: Unexpected EOF!\n");
48. exit(EXIT_FAILURE);
49. }
50.
51. entry->entry.msg[entry->entry.len] = '\0';
52.
53. dev->enqueue(entry);
54. ++queued_lines;
55. }
56. }
57.
58. if (result == 0) {
59. // we did our short timeout trick and there's nothing new
60. // print everything we have and wait for more data
61. sleep = true;
62. while (true) {
63. chooseFirst(devices, &dev); 64. if (dev == NULL) {
65. break;
66. }
67. if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
68. printNextEntry(dev); 69. } else {
70. skipNextEntry(dev); 71. }
72. --queued_lines;
73. }
74.
75. // the caller requested to just dump the log and exit 76. if (g_nonblock) {
77. exit(0);
78. }
79. } else {
80. // print all that aren't the last in their list
81. sleep = false;
82. while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
83. chooseFirst(devices, &dev); 84. if (dev == NULL || dev->queue->next == NULL) {
85. break;
86. }
87. if (g_tail_lines == 0) { 88. printNextEntry(dev); 89. } else {
90. skipNextEntry(dev); 91. }
92. --queued_lines;
93. }
94. }
95. }
96.next:
97. ;
98. }
99.}
由于可能同统打统了多日志统统文件~统里使用个select函同统统控文数来哪个
件前可统,当view plain
1.do {
2. timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR. 3. FD_ZERO(&readset);
4. for (dev=devices; dev; dev = dev->next) {
5. FD_SET(dev->fd, &readset);
6. }
7. result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
8.} while (result == -1 && errno == EINTR);
如果result >= 0~就表示有日志统统文件可统或者超统。接着~用一个for统句统统统统文件可统~哪个即FD_ISSET(dev->fd, &readset)是否统true~如果统true~表明可统~就要统一步通统read函日志统出~注意~每次只统出一日志统统,数将条view plain
1.for (dev=devices; dev; dev = dev->next) {
2. if (FD_ISSET(dev->fd, &readset)) {
3. queued_entry_t* entry = new queued_entry_t();
4. /* NOTE: driver guarantees we read exactly one full entry */
5. ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
6. if (ret < 0) {
7. if (errno == EINTR) {
8. delete entry;
9. goto next;
10. }
11. if (errno == EAGAIN) {
12. delete entry;
13. break;
14. }
15. perror("logcat read");
16. exit(EXIT_FAILURE);
17. }
18. else if (!ret) {
19. fprintf(stderr, "read: Unexpected EOF!\n");
20. exit(EXIT_FAILURE);
21. }
22.
23. entry->entry.msg[entry->entry.len] = '\0';
24.
25. dev->enqueue(entry);
26. ++queued_lines;
27. }
28. }
统用read函之前~先统建一日志统统统数个entry~接着统用read函日志统数将到entry->buf中~最后统用dev->enqueue(entry)将日志统统加入到日志统例中去。同统~把前的日志统统保存在当数queued_lines统量中。
统统统一步统理日志,
view plain
1.if (result == 0) {
2. // we did our short timeout trick and there's nothing new
3. // print everything we have and wait for more data
4. sleep = true;
5. while (true) {
6. chooseFirst(devices, &dev); 7. if (dev == NULL) {
8. break;
9. }
10. if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
11. printNextEntry(dev); 12. } else {
13. skipNextEntry(dev); 14. }
15. --queued_lines;
16. }
17.
18. // the caller requested to just dump the log and exit
19. if (g_nonblock) {
20. exit(0);
21. }
22.} else {
23. // print all that aren't the last in their list
24. sleep = false;
25. while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
26. chooseFirst(devices, &dev); 27. if (dev == NULL || dev->queue->next == NULL) {
28. break;
29. }
30. if (g_tail_lines == 0) { 31. printNextEntry(dev); 32. } else {
33. skipNextEntry(dev); 34. }
35. --queued_lines;
36. }
37.}
如果result == 0~表明是等待超统了~目前有新的日志可统~统统候就要先没
统理之前已统统出的日志。统用来chooseFirst统统日志统列不统空~且日志统列中的第一个
日志统统的统统统最小的统统~先统出最的日志,戳即旧view plain
1.static void chooseFirst(log_device_t* dev, log_device_t** firstdev) {
2. for (*firstdev = NULL; dev != NULL; dev = dev->next) {
3. if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0)
) {
4. *firstdev = dev;
5. }
6. }
7.}
如果存在统统的日志统统~接着判日志统统是统统统统是统出。前面我统统统~如果统断弃
行logcat命令统~指定了参数-t ~那统就只统示最新的会count条它统统~其的旧将弃统统被统统,view plain
1.if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
2. printNextEntry(dev);
3.} else {
4. skipNextEntry(dev);
5.}
g_tail_lines表示统示最新统统的~如果统条数0~就表示全部统示。如果g_tail_lines == 0或者queued_lines <= g_tail_lines~就表示统日志统统统统统出~否统条
就要统了。每统理完一日志统统~弃条queued_lines就减1~统统~最新的g_tail_lines就可以统出出了。来
如果result > 0~表明有新的日志可统~统统候的统理方式与result == 0的情况来不同~因统统统候统有新的日志可统~所以就不能先急着统理之前已统统出的日志。统里~分统情考统~如果能统置了只统示最新的两况g_tail_lines条并当统统~且前已统统出来条数的日志统统已统超统g_tail_lines~就要统~剩下的先不统理~等到下次再统理弃来~如果有统统统示最新的没g_tail_lines条即统统~g_tail_lines == 0~统统情就和况result
== 0的情统理方式一统~先统理所有已统统出的日志统统~再统入下一次循统。希望统者况
可以好好统段代统,体会
view plain
1.while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
2. chooseFirst(devices, &dev);
3. if (dev == NULL || dev->queue->next == NULL) {
4. break;
5. }
6. if (g_tail_lines == 0) {
7. printNextEntry(dev);
8. } else {
9. skipNextEntry(dev);
10. }
11. --queued_lines;
12.}
统日志统统的函弃数skipNextEntry统统如下,view plain
1.static void skipNextEntry(log_device_t* dev) {
2. maybePrintStart(dev);
3. queued_entry_t* entry = dev->queue;
4. dev->queue = entry->next;
5. delete entry;
6.}
统里只是统统地跳统日志统列统~统统就把最的日志统了。旧弃
printNextEntry函统理日志统出~下一统中统统分析。数
四. 统出日志统统文件的容。内
前面的分析中看出~最统日志统统文件容的统出是通统从内printNextEntry函数统行的,
view plain
1.static void printNextEntry(log_device_t* dev) { 2. maybePrintStart(dev);
3. if (g_printBinary) {
4. printBinary(&dev->queue->entry); 5. } else {
6. processBuffer(dev, &dev->queue->entry); 7. }
8. skipNextEntry(dev);
9.}
g_printBinary统true统~以二统制方式统出日志容到指定的文件中,内view plain
1.void printBinary(struct logger_entry *buf) 2.{
3. size_t size = sizeof(logger_entry) + buf->len; 4. int ret;
5.
6. do {
7. ret = write(g_outFD, buf, size); 8. } while (ret < 0 && errno == EINTR); 9.}
我统统注g_printBinary统false的情~统用况processBuffer统一步统理,view plain
1.static void processBuffer(log_device_t* dev, struct logger_entry *buf) 2.{
3. int bytesWritten = 0;
4. int err;
5. AndroidLogEntry entry;
6. char binaryMsgBuf[1024];
7.
8. if (dev->binary) {
9. err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
10. binaryMsgBuf, sizeof(binaryMsgBuf)); 11. //printf(">>> pri=%d len=%d msg='%s'\n",
12. // entry.priority, entry.messageLen, entry.message);
13. } else {
14. err = android_log_processLogBuffer(buf, &entry);
15. }
16. if (err < 0) {
17. goto error;
18. }
19.
20. if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
21. if (false && g_devCount > 1) {
22. binaryMsgBuf[0] = dev->label;
23. binaryMsgBuf[1] = ' ';
24. bytesWritten = write(g_outFD, binaryMsgBuf, 2);
25. if (bytesWritten < 0) {
26. perror("output error");
27. exit(-1);
28. }
29. }
30.
31. bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
32.
33. if (bytesWritten < 0) {
34. perror("output error");
35. exit(-1);
36. }
37. }
38.
39. g_outByteCount += bytesWritten;
40.
41. if (g_logRotateSizeKBytes > 0
42. && (g_outByteCount / 1024) >= g_logRotateSizeKBytes
43. ) {
44. rotateLogs();
45. }
46.
47.error:
48. //fprintf (stderr, "Error processing record\n");
49. return;
50.}
当dev->binary统true~日志统统统是二统制形式~不同于我统在 Android 日志
系统统统程序 Logger 源代统分析 一文中提到的常统格式,
struct logger_entry | priority | tag | msg
统里我统不统注统统情~有统趣的统者可以自已分析况~
android_log_processBinaryLogBuffer函定统在数system/core/liblog/logprint.c文件中~的作用是一二统制形式的日志统统统统统它将条ASCII形式~保存在并entry参数中~它的原型统,
view plain
1./**
2. * Convert a binary log entry to ASCII form.
3. *
4. * For convenience we mimic the processLogBuffer API. There is no
5. * pre-defined output length for the binary data, since we're free to format 6. * it however we choose, which means we can't really use a fixed-size buffer 7. * here.
8. */
9.int android_log_processBinaryLogBuffer(struct logger_entry *buf,
10. AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
11. int messageBufLen);
通常情下~况dev->binary统false~统用android_log_processLogBuffer函
数将日志统统由logger_entry格式统统统AndroidLogEntry格式。logger_entry格式在在
Android 日志系统统统程序 Logger 源代统分析一文中已统有统统描述~统里不述~
AndroidLogEntry统定统在构体system/core/include/cutils/logprint.h中,view plain
1.typedef struct AndroidLogEntry_t { 2. time_t tv_sec;
3. long tv_nsec;
4. android_LogPriority priority; 5. pid_t pid;
6. pthread_t tid;
7. const char * tag;
8. size_t messageLen;
9. const char * message;
10.} AndroidLogEntry;
android_LogPriority是一枚统统型~定统在个
system/core/include/android/log.h文件中,view plain
1./*
2. * Android log priority values, in ascending priority order.
3. */
4.typedef enum android_LogPriority { 5. ANDROID_LOG_UNKNOWN = 0, 6. ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ 7. ANDROID_LOG_VERBOSE,
8. ANDROID_LOG_DEBUG,
9. ANDROID_LOG_INFO,
10. ANDROID_LOG_WARN,
11. ANDROID_LOG_ERROR,
12. ANDROID_LOG_FATAL,
13. ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */ 14.} android_LogPriority;
android_log_processLogBuffer定统在system/core/liblog/logprint.c文件中,view plain
1./**
2. * Splits a wire-format buffer into an AndroidLogEntry
3. * entry allocated by caller. Pointers will point directly into buf 4. *
5. * Returns 0 on success and -1 on invalid wire format (entry will be
6. * in unspecified state)
7. */
8.int android_log_processLogBuffer(struct logger_entry *buf,
9. AndroidLogEntry *entry)
10.{
11. size_t tag_len;
12.
13. entry->tv_sec = buf->sec;
14. entry->tv_nsec = buf->nsec;
15. entry->priority = buf->msg[0];
16. entry->pid = buf->pid;
17. entry->tid = buf->tid;
18. entry->tag = buf->msg + 1;
19. tag_len = strlen(entry->tag);
20. entry->messageLen = buf->len - tag_len - 3;
21. entry->message = entry->tag + tag_len + 1;
22.
23. return 0;
24.}
统合logger_entry统中日志统的格式定统;构体struct logger_entry | priority |
tag | msg,~统函直统~不再累述。个数很
统用完android_log_processLogBuffer函后~日志统统的具信息就保存数体
在本地统量entry中了~接着统用android_log_shouldPrintLine函判统统日志数来断条统统是否统统统出。
在分析android_log_shouldPrintLine函之前~我统先了解据统数数构
AndroidLogFormat~统统统统定统在个构体system/core/liblog/logprint.c文件中,view plain
1.struct AndroidLogFormat_t {
2. android_LogPriority global_pri;
3. FilterInfo *filters;
4. AndroidLogPrintFormat format;
5.};
AndroidLogPrintFormat也是定统在system/core/liblog/logprint.c文件中,view plain
1.typedef struct FilterInfo_t {
2. char *mTag;
3. android_LogPriority mPri;
4. struct FilterInfo_t *p_next;
5.} FilterInfo;
因此~可以看出~AndroidLogFormat统定统了日志统统统范。在构体logcat.c
文件中~定统了统量view plain
1.static AndroidLogFormat * g_logformat;
统统量是在个main函里面统行分配的,数view plain
1.g_logformat = android_log_format_new();
在main函里面~在分析数logcat命令行统~参数会将g_logformat统行初始化~有统趣的统者可以自行分析。
回到android_log_shouldPrintLine函中~定统在数它
system/core/liblog/logprint.c文件中,
view plain
1./**
2. * returns 1 if this log line should be printed based on its priority
3. * and tag, and 0 if it should not
4. */
5.int android_log_shouldPrintLine (
6. AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
7.{
8. return pri >= filterPriForTag(p_format, tag);
9.}
统函判在个数断p_format中根据tag统~到统统的找pri统~如果返回的来pri统小于等于统统统的参数来pri统~那统就表示统日志统统可以统出。我统看条来filterPriForTag
函的统统,数view plain
1.static android_LogPriority filterPriForTag(
2. AndroidLogFormat *p_format, const char *tag)
3.{
4. FilterInfo *p_curFilter;
5.
6. for (p_curFilter = p_format->filters
7. ; p_curFilter != NULL
8. ; p_curFilter = p_curFilter->p_next
9. ) {
10. if (0 == strcmp(tag, p_curFilter->mTag)) {
11. if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
12. return p_format->global_pri;
13. } else {
14. return p_curFilter->mPri;
15. }
16. }
17. }
18.
19. return p_format->global_pri;
20.}
如果在p_format中到找与tag统统统的filter~且统并filter的mPri不等于ANDROID_LOG_DEFAULT~那统就返回统filter的成统统量mPri的统~其情下~它况返回p_format->global_pri的统。
回到processBuffer函中~如果统行完数android_log_shouldPrintLine函数
后~表明前日志统统统统出~统统用当当android_log_printLogLine函统出日志统统到文数来
件fd中~ 统函也是定统在个数system/core/liblog/logprint.c文件中,
view plain
1.int android_log_printLogLine( 2. AndroidLogFormat *p_format, 3. int fd,
4. const AndroidLogEntry *entry) 5.{
6. int ret;
7. char defaultBuffer[512];
8. char *outBuffer = NULL;
9. size_t totalLen;
10.
11. outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
12. sizeof(defaultBuffer), entry, &totalLen);
13.
14. if (!outBuffer)
15. return -1;
16.
17. do {
18. ret = write(fd, outBuffer, totalLen); 19. } while (ret < 0 && errno == EINTR); 20.
21. if (ret < 0) {
22. fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno); 23. ret = 0;
24. goto done;
25. }
26.
27. if (((size_t)ret) < totalLen) {
28. fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret, 29. (int)totalLen);
30. goto done;
31. }
32.
33.done:
34. if (outBuffer != defaultBuffer) { 35. free(outBuffer);
36. }
37.
38. return ret;
39.}
统函的作用就是把个数AndroidLogEntry格式的日志统统按照指定的格式
AndroidLogFormat统行统出了~统里~不再统一步分析统函。个数
processBuffer函的最后~统有一数个rotateLogs的操作,
view plain
1.static void rotateLogs()
2.{
3. int err;
4.
5. // Can't rotate logs if we're not outputting to a file
6. if (g_outputFileName == NULL) { 7. return;
8. }
9.
10. close(g_outFD);
11.
12. for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
13. char *file0, *file1;
14.
15. asprintf(&file1, "%s.%d", g_outputFileName, i); 16.
17. if (i - 1 == 0) {
18. asprintf(&file0, "%s", g_outputFileName); 19. } else {
20. asprintf(&file0, "%s.%d", g_outputFileName, i - 1);
21. }
22.
23. err = rename (file0, file1); 24.
25. if (err < 0 && errno != ENOENT) { 26. perror("while rotating log files");
27. }
28.
29. free(file1);
30. free(file0);
31. }
32.
33. g_outFD = openLogFile (g_outputFileName);
34.
35. if (g_outFD < 0) {
36. perror ("couldn't open output file");
37. exit(-1);
38. }
39.
40. g_outByteCount = 0;
41.
42.}
统函只有在统行个数logcat命令统~指定了-f 参数即统~g_outputFileName不统NULL统才起作用。的作用是在日志统统循统统出到一统文件它将
中。例如~指定-f参数统logfile~g_maxRotatedLogs统3~统统统文件分统统,
logfile~logfile.1~logfile.2~logfile.3
前统入到当当logfile文件的日志统统大小g_outByteCount大于等于g_logRotateSizeKBytes统~就要将logfile.2的容移至内logfile.3中~同统将logfile.1的容移至内logfile.2中~同统logfle的容移至内logfile.1中~再重新打统logfile文件统入后统统入。统统做的作用是不至于使得日志文件统得越越大~以至于占用统多的磁来来
统空统~而是只在磁统上保存一定量的最新的日志统统。统统~的日志统统就可能被新旧会
的日志统统所覆盖。
至此~统于Android日志系统源代统~我统就完整地分析完了~其中包括位于
内核空统的统统程序 Logger 源代统分析 ~统有位于统用程序架统和系统行统统的日志框运写
入操作接口源代统分析和用于日志统取的工具Logcat源代统分析~希望能统助统者统帮Android的日志系统有一的统统。个清晰
本文档为【Android日志系统Logcat源代码简要分析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。