Loading logcat/logcat.cpp +94 −238 Original line number Diff line number Diff line // Copyright 2006 The Android Open Source Project // Copyright 2006-2013 The Android Open Source Project #include <log/log.h> #include <log/logger.h> #include <log/logd.h> #include <log/logprint.h> Loading @@ -24,65 +25,27 @@ #define DEFAULT_MAX_ROTATED_LOGS 4 static AndroidLogFormat * g_logformat; static bool g_nonblock = false; static int g_tail_lines = 0; /* logd prefixes records with a length field */ #define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t) #define LOG_FILE_DIR "/dev/log/" struct queued_entry_t { union { unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4))); struct logger_entry entry __attribute__((aligned(4))); }; queued_entry_t* next; queued_entry_t() { next = NULL; } }; static int cmp(queued_entry_t* a, queued_entry_t* b) { int n = a->entry.sec - b->entry.sec; if (n != 0) { return n; } return a->entry.nsec - b->entry.nsec; } struct log_device_t { char* device; const char* device; bool binary; int fd; struct logger *logger; struct logger_list *logger_list; bool printed; char label; queued_entry_t* queue; log_device_t* next; log_device_t(char* d, bool b, char l) { log_device_t(const char* d, bool b, char l) { device = d; binary = b; label = l; queue = NULL; next = NULL; printed = false; } void enqueue(queued_entry_t* entry) { if (this->queue == NULL) { this->queue = entry; } else { queued_entry_t** e = &this->queue; while (*e && cmp(entry, *e) >= 0) { e = &((*e)->next); } entry->next = *e; *e = entry; } } }; namespace android { Loading Loading @@ -147,17 +110,14 @@ static void rotateLogs() } void printBinary(struct logger_entry *buf) void printBinary(struct log_msg *buf) { size_t size = sizeof(logger_entry) + buf->len; int ret; size_t size = buf->len(); do { ret = write(g_outFD, buf, size); } while (ret < 0 && errno == EINTR); TEMP_FAILURE_RETRY(write(g_outFD, buf, size)); } static void processBuffer(log_device_t* dev, struct logger_entry *buf) static void processBuffer(log_device_t* dev, struct log_msg *buf) { int bytesWritten = 0; int err; Loading @@ -165,12 +125,14 @@ static void processBuffer(log_device_t* dev, struct logger_entry *buf) char binaryMsgBuf[1024]; if (dev->binary) { err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap, binaryMsgBuf, sizeof(binaryMsgBuf)); err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry, g_eventTagMap, binaryMsgBuf, sizeof(binaryMsgBuf)); //printf(">>> pri=%d len=%d msg='%s'\n", // entry.priority, entry.messageLen, entry.message); } else { err = android_log_processLogBuffer(buf, &entry); err = android_log_processLogBuffer(&buf->entry_v1, &entry); } if (err < 0) { goto error; Loading Loading @@ -208,20 +170,13 @@ error: return; } static void chooseFirst(log_device_t* dev, log_device_t** firstdev) { for (*firstdev = NULL; dev != NULL; dev = dev->next) { if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0)) { *firstdev = dev; } } } static void maybePrintStart(log_device_t* dev) { if (!dev->printed) { dev->printed = true; if (g_devCount > 1 && !g_printBinary) { char buf[1024]; snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device); snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device); if (write(g_outFD, buf, strlen(buf)) < 0) { perror("output error"); exit(-1); Loading @@ -230,145 +185,6 @@ static void maybePrintStart(log_device_t* dev) { } } static void skipNextEntry(log_device_t* dev) { maybePrintStart(dev); queued_entry_t* entry = dev->queue; dev->queue = entry->next; delete entry; } static void printNextEntry(log_device_t* dev) { maybePrintStart(dev); if (g_printBinary) { printBinary(&dev->queue->entry); } else { processBuffer(dev, &dev->queue->entry); } skipNextEntry(dev); } static void readLogLines(log_device_t* devices) { log_device_t* dev; int max = 0; int ret; int queued_lines = 0; bool sleep = false; 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); } else if (entry->entry.len != ret - sizeof(struct logger_entry)) { fprintf(stderr, "read: unexpected length. Expected %d, got %d\n", entry->entry.len, ret - sizeof(struct logger_entry)); 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) { return; } } 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: ; } } static int clearLog(int logfd) { return ioctl(logfd, LOGGER_FLUSH_LOG); } /* returns the total size of the log's ring buffer */ static int getLogSize(int logfd) { return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE); } /* 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); } static void setupOutput() { Loading Loading @@ -465,6 +281,8 @@ int main(int argc, char **argv) log_device_t* devices = NULL; log_device_t* dev; bool needBinary = false; struct logger_list *logger_list; int tail_lines = 0; g_logformat = android_log_format_new(); Loading Loading @@ -499,12 +317,12 @@ int main(int argc, char **argv) break; case 'd': g_nonblock = true; mode = O_RDONLY | O_NDELAY; break; case 't': g_nonblock = true; g_tail_lines = atoi(optarg); mode = O_RDONLY | O_NDELAY; tail_lines = atoi(optarg); break; case 'g': Loading @@ -512,10 +330,6 @@ int main(int argc, char **argv) break; case 'b': { char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1); strcpy(buf, LOG_FILE_DIR); strcat(buf, optarg); bool binary = strcmp(optarg, "events") == 0; if (binary) { needBinary = true; Loading @@ -526,9 +340,9 @@ int main(int argc, char **argv) while (dev->next) { dev = dev->next; } dev->next = new log_device_t(buf, binary, optarg[0]); dev->next = new log_device_t(optarg, binary, optarg[0]); } else { devices = new log_device_t(buf, binary, optarg[0]); devices = new log_device_t(optarg, binary, optarg[0]); } android::g_devCount++; } Loading Loading @@ -659,14 +473,10 @@ int main(int argc, char **argv) } if (!devices) { devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, 'm'); devices = new log_device_t("main", false, 'm'); android::g_devCount = 1; int accessmode = (mode & O_RDONLY) ? R_OK : 0 | (mode & O_WRONLY) ? W_OK : 0; // only add this if it's available if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) { devices->next = new log_device_t(strdup("/dev/"LOGGER_LOG_SYSTEM), false, 's'); if (android_name_to_log_id("system") == LOG_ID_SYSTEM) { devices->next = new log_device_t("system", false, 's'); android::g_devCount++; } } Loading Loading @@ -728,19 +538,21 @@ int main(int argc, char **argv) } dev = devices; logger_list = android_logger_list_alloc(mode, tail_lines, 0); while (dev) { dev->fd = open(dev->device, mode); if (dev->fd < 0) { fprintf(stderr, "Unable to open log device '%s': %s\n", dev->device, strerror(errno)); dev->logger_list = logger_list; dev->logger = android_logger_open(logger_list, android_name_to_log_id(dev->device)); if (!dev->logger) { fprintf(stderr, "Unable to open log device '%s'\n", dev->device); exit(EXIT_FAILURE); } if (clearLog) { int ret; ret = android::clearLog(dev->fd); ret = android_logger_clear(dev->logger); if (ret) { perror("ioctl"); perror("clearLog"); exit(EXIT_FAILURE); } } Loading @@ -748,15 +560,15 @@ int main(int argc, char **argv) if (getLogSize) { int size, readable; size = android::getLogSize(dev->fd); size = android_logger_get_log_size(dev->logger); if (size < 0) { perror("ioctl"); perror("getLogSize"); exit(EXIT_FAILURE); } readable = android::getLogReadableSize(dev->fd); readable = android_logger_get_log_readable_size(dev->logger); if (readable < 0) { perror("ioctl"); perror("getLogReadableSize"); exit(EXIT_FAILURE); } Loading @@ -783,7 +595,51 @@ int main(int argc, char **argv) if (needBinary) android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE); android::readLogLines(devices); while (1) { struct log_msg log_msg; int ret = android_logger_list_read(logger_list, &log_msg); if (ret == 0) { fprintf(stderr, "read: Unexpected EOF!\n"); exit(EXIT_FAILURE); } if (ret < 0) { if (ret == -EAGAIN) { break; } if (ret == -EIO) { fprintf(stderr, "read: Unexpected EOF!\n"); exit(EXIT_FAILURE); } if (ret == -EINVAL) { fprintf(stderr, "read: unexpected length.\n"); exit(EXIT_FAILURE); } perror("logcat read"); exit(EXIT_FAILURE); } for(dev = devices; dev; dev = dev->next) { if (android_name_to_log_id(dev->device) == log_msg.id()) { break; } } if (!dev) { fprintf(stderr, "read: Unexpected log ID!\n"); exit(EXIT_FAILURE); } android::maybePrintStart(dev); if (android::g_printBinary) { android::printBinary(&log_msg); } else { android::processBuffer(dev, &log_msg); } } android_logger_list_free(logger_list); return 0; } Loading
logcat/logcat.cpp +94 −238 Original line number Diff line number Diff line // Copyright 2006 The Android Open Source Project // Copyright 2006-2013 The Android Open Source Project #include <log/log.h> #include <log/logger.h> #include <log/logd.h> #include <log/logprint.h> Loading @@ -24,65 +25,27 @@ #define DEFAULT_MAX_ROTATED_LOGS 4 static AndroidLogFormat * g_logformat; static bool g_nonblock = false; static int g_tail_lines = 0; /* logd prefixes records with a length field */ #define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t) #define LOG_FILE_DIR "/dev/log/" struct queued_entry_t { union { unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4))); struct logger_entry entry __attribute__((aligned(4))); }; queued_entry_t* next; queued_entry_t() { next = NULL; } }; static int cmp(queued_entry_t* a, queued_entry_t* b) { int n = a->entry.sec - b->entry.sec; if (n != 0) { return n; } return a->entry.nsec - b->entry.nsec; } struct log_device_t { char* device; const char* device; bool binary; int fd; struct logger *logger; struct logger_list *logger_list; bool printed; char label; queued_entry_t* queue; log_device_t* next; log_device_t(char* d, bool b, char l) { log_device_t(const char* d, bool b, char l) { device = d; binary = b; label = l; queue = NULL; next = NULL; printed = false; } void enqueue(queued_entry_t* entry) { if (this->queue == NULL) { this->queue = entry; } else { queued_entry_t** e = &this->queue; while (*e && cmp(entry, *e) >= 0) { e = &((*e)->next); } entry->next = *e; *e = entry; } } }; namespace android { Loading Loading @@ -147,17 +110,14 @@ static void rotateLogs() } void printBinary(struct logger_entry *buf) void printBinary(struct log_msg *buf) { size_t size = sizeof(logger_entry) + buf->len; int ret; size_t size = buf->len(); do { ret = write(g_outFD, buf, size); } while (ret < 0 && errno == EINTR); TEMP_FAILURE_RETRY(write(g_outFD, buf, size)); } static void processBuffer(log_device_t* dev, struct logger_entry *buf) static void processBuffer(log_device_t* dev, struct log_msg *buf) { int bytesWritten = 0; int err; Loading @@ -165,12 +125,14 @@ static void processBuffer(log_device_t* dev, struct logger_entry *buf) char binaryMsgBuf[1024]; if (dev->binary) { err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap, binaryMsgBuf, sizeof(binaryMsgBuf)); err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry, g_eventTagMap, binaryMsgBuf, sizeof(binaryMsgBuf)); //printf(">>> pri=%d len=%d msg='%s'\n", // entry.priority, entry.messageLen, entry.message); } else { err = android_log_processLogBuffer(buf, &entry); err = android_log_processLogBuffer(&buf->entry_v1, &entry); } if (err < 0) { goto error; Loading Loading @@ -208,20 +170,13 @@ error: return; } static void chooseFirst(log_device_t* dev, log_device_t** firstdev) { for (*firstdev = NULL; dev != NULL; dev = dev->next) { if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0)) { *firstdev = dev; } } } static void maybePrintStart(log_device_t* dev) { if (!dev->printed) { dev->printed = true; if (g_devCount > 1 && !g_printBinary) { char buf[1024]; snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device); snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device); if (write(g_outFD, buf, strlen(buf)) < 0) { perror("output error"); exit(-1); Loading @@ -230,145 +185,6 @@ static void maybePrintStart(log_device_t* dev) { } } static void skipNextEntry(log_device_t* dev) { maybePrintStart(dev); queued_entry_t* entry = dev->queue; dev->queue = entry->next; delete entry; } static void printNextEntry(log_device_t* dev) { maybePrintStart(dev); if (g_printBinary) { printBinary(&dev->queue->entry); } else { processBuffer(dev, &dev->queue->entry); } skipNextEntry(dev); } static void readLogLines(log_device_t* devices) { log_device_t* dev; int max = 0; int ret; int queued_lines = 0; bool sleep = false; 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); } else if (entry->entry.len != ret - sizeof(struct logger_entry)) { fprintf(stderr, "read: unexpected length. Expected %d, got %d\n", entry->entry.len, ret - sizeof(struct logger_entry)); 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) { return; } } 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: ; } } static int clearLog(int logfd) { return ioctl(logfd, LOGGER_FLUSH_LOG); } /* returns the total size of the log's ring buffer */ static int getLogSize(int logfd) { return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE); } /* 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); } static void setupOutput() { Loading Loading @@ -465,6 +281,8 @@ int main(int argc, char **argv) log_device_t* devices = NULL; log_device_t* dev; bool needBinary = false; struct logger_list *logger_list; int tail_lines = 0; g_logformat = android_log_format_new(); Loading Loading @@ -499,12 +317,12 @@ int main(int argc, char **argv) break; case 'd': g_nonblock = true; mode = O_RDONLY | O_NDELAY; break; case 't': g_nonblock = true; g_tail_lines = atoi(optarg); mode = O_RDONLY | O_NDELAY; tail_lines = atoi(optarg); break; case 'g': Loading @@ -512,10 +330,6 @@ int main(int argc, char **argv) break; case 'b': { char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1); strcpy(buf, LOG_FILE_DIR); strcat(buf, optarg); bool binary = strcmp(optarg, "events") == 0; if (binary) { needBinary = true; Loading @@ -526,9 +340,9 @@ int main(int argc, char **argv) while (dev->next) { dev = dev->next; } dev->next = new log_device_t(buf, binary, optarg[0]); dev->next = new log_device_t(optarg, binary, optarg[0]); } else { devices = new log_device_t(buf, binary, optarg[0]); devices = new log_device_t(optarg, binary, optarg[0]); } android::g_devCount++; } Loading Loading @@ -659,14 +473,10 @@ int main(int argc, char **argv) } if (!devices) { devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, 'm'); devices = new log_device_t("main", false, 'm'); android::g_devCount = 1; int accessmode = (mode & O_RDONLY) ? R_OK : 0 | (mode & O_WRONLY) ? W_OK : 0; // only add this if it's available if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) { devices->next = new log_device_t(strdup("/dev/"LOGGER_LOG_SYSTEM), false, 's'); if (android_name_to_log_id("system") == LOG_ID_SYSTEM) { devices->next = new log_device_t("system", false, 's'); android::g_devCount++; } } Loading Loading @@ -728,19 +538,21 @@ int main(int argc, char **argv) } dev = devices; logger_list = android_logger_list_alloc(mode, tail_lines, 0); while (dev) { dev->fd = open(dev->device, mode); if (dev->fd < 0) { fprintf(stderr, "Unable to open log device '%s': %s\n", dev->device, strerror(errno)); dev->logger_list = logger_list; dev->logger = android_logger_open(logger_list, android_name_to_log_id(dev->device)); if (!dev->logger) { fprintf(stderr, "Unable to open log device '%s'\n", dev->device); exit(EXIT_FAILURE); } if (clearLog) { int ret; ret = android::clearLog(dev->fd); ret = android_logger_clear(dev->logger); if (ret) { perror("ioctl"); perror("clearLog"); exit(EXIT_FAILURE); } } Loading @@ -748,15 +560,15 @@ int main(int argc, char **argv) if (getLogSize) { int size, readable; size = android::getLogSize(dev->fd); size = android_logger_get_log_size(dev->logger); if (size < 0) { perror("ioctl"); perror("getLogSize"); exit(EXIT_FAILURE); } readable = android::getLogReadableSize(dev->fd); readable = android_logger_get_log_readable_size(dev->logger); if (readable < 0) { perror("ioctl"); perror("getLogReadableSize"); exit(EXIT_FAILURE); } Loading @@ -783,7 +595,51 @@ int main(int argc, char **argv) if (needBinary) android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE); android::readLogLines(devices); while (1) { struct log_msg log_msg; int ret = android_logger_list_read(logger_list, &log_msg); if (ret == 0) { fprintf(stderr, "read: Unexpected EOF!\n"); exit(EXIT_FAILURE); } if (ret < 0) { if (ret == -EAGAIN) { break; } if (ret == -EIO) { fprintf(stderr, "read: Unexpected EOF!\n"); exit(EXIT_FAILURE); } if (ret == -EINVAL) { fprintf(stderr, "read: unexpected length.\n"); exit(EXIT_FAILURE); } perror("logcat read"); exit(EXIT_FAILURE); } for(dev = devices; dev; dev = dev->next) { if (android_name_to_log_id(dev->device) == log_msg.id()) { break; } } if (!dev) { fprintf(stderr, "read: Unexpected log ID!\n"); exit(EXIT_FAILURE); } android::maybePrintStart(dev); if (android::g_printBinary) { android::printBinary(&log_msg); } else { android::processBuffer(dev, &log_msg); } } android_logger_list_free(logger_list); return 0; }