Android高级——Logger日志系统

打印 上一主题 下一主题

主题 1031|帖子 1031|积分 3093

Logger日志系统



  • Logger日志系统是基于内核中的Logger日志驱动程序实现
  • 将日志纪录保存在内核空间中
  • 使用一个环形缓冲区来保存日志,满了之后,新的日志就会覆盖旧的日志
日志类型



  • main,纪录应用程序级别
  • system,纪录系统级别
  • radio,纪录无线装备相关
  • events,用于诊断系统问题,开辟人员不应使用
日志驱动程序

4种类型的日志通过下面4个装备文件来访问


  • /dev/log/main
  • /dev/log/system
  • /dev/log/radio
  • /dev/log/events
运行时库

无论什么类型,终极调用write_to_log写入Logger日志驱动程序
C/C++写入日志



  • 宏ALOGV、ALOGD、ALOGI、ALOGW和ALOGE写入main
  • 宏SLOGV、SLOGD、SLOGI、SLOGW和SLOGE写入system
  • 宏RLOGV、RLOGD、RLOGI、RLOGW和RLOGE写入radio
  • 宏LOG_EVENT_INT、LOG_EVENT_LONG、LOG_EVENT_FLOAT和LOG_EVENT_STRING写入events
Java写入日志



  • android.util.Log 写入main
  • android.util.Slog 写入system
  • android.util.Rlog 写入radio
  • android.util.EventLog 写入event
团体架构


Logger日志格式

main、system和radio



  • priority:优先级,整数,VERBOSE、DEBUG、INFO、WARN、ERROR和FATAL
  • tag:标签,字符串
  • msg:内容,字符串

events



  • tag:标签,整数
  • msg:内容,二进制数据,由一个或多个值组成,每个值前面都有一个字段形貌它的类型

tag

tag为整数,根据/system/etc/event-log-tags转为字符串
/system/etc/event-log-tags还用来形貌events类型的日志内容的格式


  • tag number:标签值,范围为0~2147483648
  • tag name:标签值对应的字符串形貌,字母[A-Z][a-z]、数字[0-9]或者下画线“_”组成
  • 第三个字段:日志内容的值

值格式为


  • name:名称
  • data type:数据类型,int(1)、long(2)、string(3)、list(4)、float(5)
  • data unit:数据单位,范围是1~6,分别表示对象数量(number of objects)、字节数(Number of bytes)、毫秒数(Number of milliseconds)、分配额(Number of allocations)、标记(ID)和百分比(Percent)

  1. 2722 battery_level (level|1|6),(voltage|1|1),(temperature|1|1)
复制代码
如上为/system/etc/event-log-tags的内容


  • tag number:2722
  • tag name:battery_level
  • 由三个值组成,level/voltage/temperature,数据类型为1/1/1,数据单位为6/1/1
msg

msg格式为


  • 类型
  • 值,int(1)、long(2)、string(3)、list(4)、float(5)

Logger日志驱动程序(能力不够暂时分析不了)

基础数据布局

./system/logging/liblog/include/log/log_read.h(Android13)
logger_entry

logger_entry形貌一个日志纪录,最大长度为4K,其有效负载长度最大便是4K减去布局体logger_entry的大小


  • len:实际log的有效负载长度
  • hdr_size:logger_entry大小
  • pid/itd:进程pid/tid
  • sec/nsec:写入时间
  • lid:实际log id
  • uid:进程uid
  1. struct logger_entry {
  2.   uint16_t len;      /* length of the payload */
  3.   uint16_t hdr_size; /* sizeof(struct logger_entry) */
  4.   int32_t pid;       /* generating process's pid */
  5.   uint32_t tid;      /* generating process's tid */
  6.   uint32_t sec;      /* seconds since Epoch */
  7.   uint32_t nsec;     /* nanoseconds */
  8.   uint32_t lid;      /* log id of the payload, bottom 4 bits currently */
  9.   uint32_t uid;      /* generating process's uid */
  10. };
复制代码
log_msg



  • 缓冲区5M
  • 包罗logger_entry
  • 若为C++,则新增函数返回nsec、lid、msg、len
  1. #define LOGGER_ENTRY_MAX_LEN (5 * 1024)
  2. struct log_msg {
  3.   union {
  4.     unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
  5.     struct logger_entry entry;
  6.   } __attribute__((aligned(4)));
  7. #ifdef __cplusplus
  8.   uint64_t nsec() const {
  9.     return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
  10.   }
  11.   log_id_t id() {
  12.     return static_cast<log_id_t>(entry.lid);
  13.   }
  14.   char* msg() {
  15.     unsigned short hdr_size = entry.hdr_size;
  16.     if (hdr_size >= sizeof(struct log_msg) - sizeof(entry)) {
  17.       return nullptr;
  18.     }
  19.     return reinterpret_cast<char*>(buf) + hdr_size;
  20.   }
  21.   unsigned int len() { return entry.hdr_size + entry.len; }
  22. #endif
  23. };
复制代码
main

system/logging/logd/main.cpp,进行初始化操纵


  • 默认log时区为utc
  • 缓冲区类型有SerializedLogBuffer(默认)和SimpleLogBuffer,可通过logd.buffer_type属性修改
  • LogReader监听/dev/socket/logdr
  • LogListener监听/dev/socket/logdw
  • CommandListener监听/dev/socket/logd
  1. int main(int argc, char* argv[]) {
  2.     // We want EPIPE when a reader disconnects, not to terminate logd.
  3.     signal(SIGPIPE, SIG_IGN);
  4.     // logd is written under the assumption that the timezone is UTC.
  5.     // If TZ is not set, persist.sys.timezone is looked up in some time utility
  6.     // libc functions, including mktime. It confuses the logd time handling,
  7.     // so here explicitly set TZ to UTC, which overrides the property.
  8.     setenv("TZ", "UTC", 1);
  9.     // issue reinit command. KISS argument parsing.
  10.     if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
  11.         return issueReinit();
  12.     }
  13.     android::base::InitLogging(
  14.             argv, [](android::base::LogId log_id, android::base::LogSeverity severity,
  15.                      const char* tag, const char* file, unsigned int line, const char* message) {
  16.                 if (tag && strcmp(tag, "logd") != 0) {
  17.                     auto prefixed_message = android::base::StringPrintf("%s: %s", tag, message);
  18.                     android::base::KernelLogger(log_id, severity, "logd", file, line,
  19.                                                 prefixed_message.c_str());
  20.                 } else {
  21.                     android::base::KernelLogger(log_id, severity, "logd", file, line, message);
  22.                 }
  23.             });
  24.     static const char dev_kmsg[] = "/dev/kmsg";
  25.     int fdDmesg = android_get_control_file(dev_kmsg);
  26.     if (fdDmesg < 0) {
  27.         fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
  28.     }
  29.     int fdPmesg = -1;
  30.     bool klogd = GetBoolPropertyEngSvelteDefault("ro.logd.kernel");
  31.     if (klogd) {
  32.         SetProperty("ro.logd.kernel", "true");
  33.         static const char proc_kmsg[] = "/proc/kmsg";
  34.         fdPmesg = android_get_control_file(proc_kmsg);
  35.         if (fdPmesg < 0) {
  36.             fdPmesg = TEMP_FAILURE_RETRY(
  37.                 open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
  38.         }
  39.         if (fdPmesg < 0) PLOG(ERROR) << "Failed to open " << proc_kmsg;
  40.     }
  41.     bool auditd = GetBoolProperty("ro.logd.auditd", true);
  42.     DropPrivs(klogd, auditd);
  43.     // A cache of event log tags
  44.     LogTags log_tags;
  45.     // Pruning configuration.
  46.     PruneList prune_list;
  47.     std::string buffer_type = GetProperty("logd.buffer_type", "serialized");
  48.     LogStatistics log_statistics(GetBoolPropertyEngSvelteDefault("logd.statistics"),
  49.                                  buffer_type == "serialized");
  50.     // Serves the purpose of managing the last logs times read on a socket connection, and as a
  51.     // reader lock on a range of log entries.
  52.     LogReaderList reader_list;
  53.     // LogBuffer is the object which is responsible for holding all log entries.
  54.     LogBuffer* log_buffer = nullptr;
  55.     if (buffer_type == "serialized") {
  56.         log_buffer = new SerializedLogBuffer(&reader_list, &log_tags, &log_statistics);
  57.     } else if (buffer_type == "simple") {
  58.         log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);
  59.     } else {
  60.         LOG(FATAL) << "buffer_type must be one of 'serialized' or 'simple'";
  61.     }
  62.     // LogReader listens on /dev/socket/logdr. When a client
  63.     // connects, log entries in the LogBuffer are written to the client.
  64.     LogReader* reader = new LogReader(log_buffer, &reader_list);
  65.     if (reader->startListener()) {
  66.         return EXIT_FAILURE;
  67.     }
  68.     // LogListener listens on /dev/socket/logdw for client
  69.     // initiated log messages. New log entries are added to LogBuffer
  70.     // and LogReader is notified to send updates to connected clients.
  71.     LogListener* swl = new LogListener(log_buffer);
  72.     if (!swl->StartListener()) {
  73.         return EXIT_FAILURE;
  74.     }
  75.     // Command listener listens on /dev/socket/logd for incoming logd
  76.     // administrative commands.
  77.     CommandListener* cl = new CommandListener(log_buffer, &log_tags, &prune_list, &log_statistics);
  78.     if (cl->startListener()) {
  79.         return EXIT_FAILURE;
  80.     }
  81.     // Notify that others can now interact with logd
  82.     SetProperty("logd.ready", "true");
  83.     // LogAudit listens on NETLINK_AUDIT socket for selinux
  84.     // initiated log messages. New log entries are added to LogBuffer
  85.     // and LogReader is notified to send updates to connected clients.
  86.     LogAudit* al = nullptr;
  87.     if (auditd) {
  88.         int dmesg_fd = GetBoolProperty("ro.logd.auditd.dmesg", true) ? fdDmesg : -1;
  89.         al = new LogAudit(log_buffer, dmesg_fd, &log_statistics);
  90.     }
  91.     LogKlog* kl = nullptr;
  92.     if (klogd) {
  93.         kl = new LogKlog(log_buffer, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
  94.     }
  95.     readDmesg(al, kl);
  96.     // failure is an option ... messages are in dmesg (required by standard)
  97.     if (kl && kl->startListener()) {
  98.         delete kl;
  99.     }
  100.     if (al && al->startListener()) {
  101.         delete al;
  102.     }
  103.     TrustyLog::create(log_buffer);
  104.     TEMP_FAILURE_RETRY(pause());
  105.     return EXIT_SUCCESS;
  106. }
复制代码
SerializedLogBuffer



  • Log将日志封装成SerializedLogEntry、LogStatisticsElement添加到stats_
  1. SerializedLogBuffer::SerializedLogBuffer(LogReaderList* reader_list, LogTags* tags,
  2.                                          LogStatistics* stats)
  3.     : reader_list_(reader_list), tags_(tags), stats_(stats) {
  4.     Init();
  5. }
  6. void SerializedLogBuffer::Init() {
  7.     log_id_for_each(i) {
  8.         if (!SetSize(i, GetBufferSizeFromProperties(i))) {
  9.             SetSize(i, kLogBufferMinSize);
  10.         }
  11.     }
  12.     // Release any sleeping reader threads to dump their current content.
  13.     auto lock = std::lock_guard{logd_lock};
  14.     for (const auto& reader_thread : reader_list_->running_reader_threads()) {
  15.         reader_thread->TriggerReader();
  16.     }
  17. }
  18. int SerializedLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
  19.                              const char* msg, uint16_t len) {
  20.     if (log_id >= LOG_ID_MAX || len == 0) {
  21.         return -EINVAL;
  22.     }
  23.     if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
  24.         len = LOGGER_ENTRY_MAX_PAYLOAD;
  25.     }
  26.     if (!ShouldLog(log_id, msg, len)) {
  27.         stats_->AddTotal(log_id, len);
  28.         return -EACCES;
  29.     }
  30.     auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
  31.     auto lock = std::lock_guard{logd_lock};
  32.     auto entry = LogToLogBuffer(logs_[log_id], max_size_[log_id], sequence, realtime, uid, pid, tid,
  33.                                 msg, len);
  34.     stats_->Add(entry->ToLogStatisticsElement(log_id));
  35.     MaybePrune(log_id);
  36.     reader_list_->NotifyNewLog(1 << log_id);
  37.     return len;
  38. }
  39. static SerializedLogEntry* LogToLogBuffer(std::list<SerializedLogChunk>& log_buffer,
  40.                                           size_t max_size, uint64_t sequence, log_time realtime,
  41.                                           uid_t uid, pid_t pid, pid_t tid, const char* msg,
  42.                                           uint16_t len) {
  43.     if (log_buffer.empty()) {
  44.         log_buffer.push_back(SerializedLogChunk(max_size / SerializedLogBuffer::kChunkSizeDivisor));
  45.     }
  46.     auto total_len = sizeof(SerializedLogEntry) + len;
  47.     if (!log_buffer.back().CanLog(total_len)) {
  48.         log_buffer.back().FinishWriting();
  49.         log_buffer.push_back(SerializedLogChunk(max_size / SerializedLogBuffer::kChunkSizeDivisor));
  50.     }
  51.     return log_buffer.back().Log(sequence, realtime, uid, pid, tid, msg, len);
  52. }
复制代码
LogReader

LogListener

StartListener开启线程LogListener,循环调用HandleData,通过LogBuffer的Log方法写入日志
  1. LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
  2. bool LogListener::StartListener() {
  3.     if (socket_ <= 0) {
  4.         return false;
  5.     }
  6.     auto thread = std::thread(&LogListener::ThreadFunction, this);
  7.     thread.detach();
  8.     return true;
  9. }
  10. void LogListener::ThreadFunction() {
  11.     prctl(PR_SET_NAME, "logd.writer");
  12.     while (true) {
  13.         HandleData();
  14.     }
  15. }
  16. void LogListener::HandleData() {
  17.     // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
  18.     __attribute__((uninitialized)) char
  19.             buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
  20.     struct iovec iov = {buffer, sizeof(buffer) - 1};
  21.     alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
  22.     struct msghdr hdr = {
  23.         nullptr, 0, &iov, 1, control, sizeof(control), 0,
  24.     };
  25.     ssize_t n = recvmsg(socket_, &hdr, 0);
  26.     if (n <= (ssize_t)(sizeof(android_log_header_t))) {
  27.         return;
  28.     }
  29.     // To clear the entire buffer would be safe, but this contributes to 1.68%
  30.     // overhead under logging load. We are safe because we check counts, but
  31.     // still need to clear null terminator
  32.     buffer[n] = 0;
  33.     struct ucred* cred = nullptr;
  34.     struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
  35.     while (cmsg != nullptr) {
  36.         if (cmsg->cmsg_level == SOL_SOCKET &&
  37.             cmsg->cmsg_type == SCM_CREDENTIALS) {
  38.             cred = (struct ucred*)CMSG_DATA(cmsg);
  39.             break;
  40.         }
  41.         cmsg = CMSG_NXTHDR(&hdr, cmsg);
  42.     }
  43.     if (cred == nullptr) {
  44.         return;
  45.     }
  46.     if (cred->uid == AID_LOGD) {
  47.         // ignore log messages we send to ourself.
  48.         // Such log messages are often generated by libraries we depend on
  49.         // which use standard Android logging.
  50.         return;
  51.     }
  52.     android_log_header_t* header =
  53.         reinterpret_cast<android_log_header_t*>(buffer);
  54.     log_id_t logId = static_cast<log_id_t>(header->id);
  55.     if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
  56.         logId == LOG_ID_KERNEL) {
  57.         return;
  58.     }
  59.     if (logId == LOG_ID_SECURITY) {
  60.         if (!__android_log_security()) {
  61.             return;
  62.         }
  63.         if (!clientCanWriteSecurityLog(cred->uid, cred->gid, cred->pid)) {
  64.             return;
  65.         }
  66.     }
  67.     char* msg = ((char*)buffer) + sizeof(android_log_header_t);
  68.     n -= sizeof(android_log_header_t);
  69.     // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
  70.     // truncated message to the logs.
  71.     logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
  72.                  ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
  73. }
  74. int LogListener::GetLogSocket() {
  75.     static const char socketName[] = "logdw";
  76.     int sock = android_get_control_socket(socketName);
  77.     if (sock < 0) {  // logd started up in init.sh
  78.         sock = socket_local_server(
  79.             socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
  80.         int on = 1;
  81.         if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
  82.             return -1;
  83.         }
  84.     }
  85.     return sock;
  86. }
复制代码
CommandListener

运行时库

write_to_log

system/logging/liblog/logger_write.cpp
调用LogdWrite
  1. #ifdef __ANDROID__
  2. static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
  3.   int ret;
  4.   struct timespec ts;
  5.   if (log_id == LOG_ID_KERNEL) {
  6.     return -EINVAL;
  7.   }
  8.   clock_gettime(CLOCK_REALTIME, &ts);
  9.   if (log_id == LOG_ID_SECURITY) {
  10.     if (vec[0].iov_len < 4) {
  11.       return -EINVAL;
  12.     }
  13.     ret = check_log_uid_permissions();
  14.     if (ret < 0) {
  15.       return ret;
  16.     }
  17.     if (!__android_log_security()) {
  18.       /* If only we could reset downstream logd counter */
  19.       return -EPERM;
  20.     }
  21.   } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
  22.     if (vec[0].iov_len < 4) {
  23.       return -EINVAL;
  24.     }
  25.   }
  26.   ret = LogdWrite(log_id, &ts, vec, nr);
  27.   PmsgWrite(log_id, &ts, vec, nr);
  28.   return ret;
  29. }
  30. #else
  31. static int write_to_log(log_id_t, struct iovec*, size_t) {
  32.   // Non-Android text logs should go to __android_log_stderr_logger, not here.
  33.   // Non-Android binary logs are always dropped.
  34.   return 1;
  35. }
  36. #endif
复制代码
LogdWrite

system/logging/liblog/logd_writer.cpp


  • 若logId == LOG_ID_SECURITY,获取LogdSocket::BlockingSocket(),否则获取LogdSocket::NonBlockingSocket()
  • 调用sock打开装备/dev/socket/logdw,通过writev写入struct iovec
  • 返回值小于0且错误码不便是EAGAIN需要重新毗连再次写入
  1. int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
  2.   ssize_t ret;
  3.   static const unsigned headerLength = 1;
  4.   struct iovec newVec[nr + headerLength];
  5.   android_log_header_t header;
  6.   size_t i, payloadSize;
  7.   static atomic_int dropped;
  8.   LogdSocket& logd_socket =
  9.       logId == LOG_ID_SECURITY ? LogdSocket::BlockingSocket() : LogdSocket::NonBlockingSocket();
  10.   if (logd_socket.sock() < 0) {
  11.     return -EBADF;
  12.   }
  13.   /* logd, after initialization and priv drop */
  14.   if (getuid() == AID_LOGD) {
  15.     /*
  16.      * ignore log messages we send to ourself (logd).
  17.      * Such log messages are often generated by libraries we depend on
  18.      * which use standard Android logging.
  19.      */
  20.     return 0;
  21.   }
  22.   header.tid = gettid();
  23.   header.realtime.tv_sec = ts->tv_sec;
  24.   header.realtime.tv_nsec = ts->tv_nsec;
  25.   newVec[0].iov_base = (unsigned char*)&header;
  26.   newVec[0].iov_len = sizeof(header);
  27.   int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
  28.   if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
  29.                                                 ANDROID_LOG_VERBOSE)) {
  30.     android_log_event_int_t buffer;
  31.     header.id = LOG_ID_EVENTS;
  32.     buffer.header.tag = LIBLOG_LOG_TAG;
  33.     buffer.payload.type = EVENT_TYPE_INT;
  34.     buffer.payload.data = snapshot;
  35.     newVec[headerLength].iov_base = &buffer;
  36.     newVec[headerLength].iov_len = sizeof(buffer);
  37.     ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, 2));
  38.     if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
  39.       atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
  40.     }
  41.   }
  42.   header.id = logId;
  43.   for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
  44.     newVec[i].iov_base = vec[i - headerLength].iov_base;
  45.     payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
  46.     if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
  47.       newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
  48.       if (newVec[i].iov_len) {
  49.         ++i;
  50.       }
  51.       break;
  52.     }
  53.   }
  54.   // EAGAIN occurs if logd is overloaded, other errors indicate that something went wrong with
  55.   // the connection, so we reset it and try again.
  56.   ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, i));
  57.   if (ret < 0 && errno != EAGAIN) {
  58.     logd_socket.Reconnect();
  59.     ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, i));
  60.   }
  61.   if (ret < 0) {
  62.     ret = -errno;
  63.   }
  64.   if (ret > (ssize_t)sizeof(header)) {
  65.     ret -= sizeof(header);
  66.   } else if (ret < 0) {
  67.     atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
  68.   }
  69.   return ret;
  70. }
复制代码
LogdSocket

sock、GetSocket、LogdConnect打开装备/dev/socket/logdw
  1. class LogdSocket {
  2. public:
  3.   static LogdSocket& BlockingSocket() {
  4.     static LogdSocket logd_socket(true);
  5.     return logd_socket;
  6.   }
  7.   static LogdSocket& NonBlockingSocket() {
  8.     static LogdSocket logd_socket(false);
  9.     return logd_socket;
  10.   }
  11.   void Reconnect() { LogdConnect(sock_); }
  12.   // Zygote uses this to clean up open FD's after fork() and before specialization.  It is single
  13.   // threaded at this point and therefore this function is explicitly not thread safe.  It sets
  14.   // sock_ to kUninitialized, so future logs will be safely initialized whenever they happen.
  15.   void Close() {
  16.     if (sock_ != kUninitialized) {
  17.       close(sock_);
  18.     }
  19.     sock_ = kUninitialized;
  20.   }
  21.   int sock() {
  22.     GetSocket();
  23.     return sock_;
  24.   }
  25. private:
  26.   LogdSocket(bool blocking) : blocking_(blocking) {}
  27.   // Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this
  28.   // function is used to reconnect to logd without requiring a new socket.
  29.   static void LogdConnect(int sock) {
  30.     sockaddr_un un = {};
  31.     un.sun_family = AF_UNIX;
  32.     strcpy(un.sun_path, "/dev/socket/logdw");
  33.     TEMP_FAILURE_RETRY(connect(sock, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)));
  34.   }
  35.   // sock_ should only be opened once.  If we see that sock_ is uninitialized, we
  36.   // create a new socket and attempt to exchange it into the atomic sock_.  If the
  37.   // compare/exchange was successful, then that will be the socket used for the duration of the
  38.   // program, otherwise a different thread has already opened and written the socket to the atomic,
  39.   // so close the new socket and return.
  40.   void GetSocket() {
  41.     if (sock_ != kUninitialized) {
  42.       return;
  43.     }
  44.     int flags = SOCK_DGRAM | SOCK_CLOEXEC;
  45.     if (!blocking_) {
  46.       flags |= SOCK_NONBLOCK;
  47.     }
  48.     int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, flags, 0));
  49.     if (new_socket < 0) {
  50.       return;
  51.     }
  52.     LogdConnect(new_socket);
  53.     int uninitialized_value = kUninitialized;
  54.     if (!sock_.compare_exchange_strong(uninitialized_value, new_socket)) {
  55.       close(new_socket);
  56.       return;
  57.     }
  58.   }
  59.   static const int kUninitialized = -1;
  60.   atomic_int sock_ = kUninitialized;
  61.   bool blocking_;
  62. };
复制代码
__android_log_print

system/logging/liblog/logger_write.cpp
  1. int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
  2.   ErrnoRestorer errno_restorer;
  3.   if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
  4.     return -EPERM;
  5.   }
  6.   va_list ap;
  7.   __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
  8.   va_start(ap, fmt);
  9.   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
  10.   va_end(ap);
  11.   __android_log_message log_message = {
  12.       sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
  13.   __android_log_write_log_message(&log_message);
  14.   return 1;
  15. }
复制代码
__android_log_write_log_message

  1. void __android_log_write_log_message(__android_log_message* log_message) {
  2.   ErrnoRestorer errno_restorer;
  3.   if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
  4.       log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
  5.       log_message->buffer_id != LOG_ID_CRASH) {
  6.     return;
  7.   }
  8.   if (log_message->tag == nullptr) {
  9.     log_message->tag = GetDefaultTag().c_str();
  10.   }
  11. #if __BIONIC__
  12.   if (log_message->priority == ANDROID_LOG_FATAL) {
  13.     android_set_abort_message(log_message->message);
  14.   }
  15. #endif
  16.   get_logger_function()(log_message);
  17. }
复制代码
调用get_logger_function,get_file_logger_path判定是否有界说ro.log.file_logger.path指定log文件路径,如果没有则调用__android_log_logd_logger
  1. static __android_logger_function get_logger_function() {
  2.   if (user_set_logger_function != nullptr) {
  3.     return user_set_logger_function;
  4.   }
  5.   static __android_logger_function default_logger_function = []() {
  6. #if __ANDROID__
  7.     if (get_file_logger_path() != nullptr) {
  8.       return file_logger;
  9.     } else {
  10.       return __android_log_logd_logger;
  11.     }
  12. #else
  13.     return file_logger;
  14. #endif
  15.   }();
  16.   return default_logger_function;
  17. }
  18. #ifdef __ANDROID__
  19. static const char* get_file_logger_path() {
  20.   static const char* file_logger_path = []() {
  21.     static char path[PROP_VALUE_MAX] = {};
  22.     if (__system_property_get("ro.log.file_logger.path", path) > 0) {
  23.       return path;
  24.     }
  25.     return (char*)nullptr;  // means file_logger should not be used
  26.   }();
  27.   return file_logger_path;
  28. }
  29. #endif
复制代码
__android_log_logd_logger将优先级、标签、内容存在数字元素vec[0]、vec[1]和vec[2],最后调用write_to_log
+1是因为标签和内容后面跟着’\0’,用来区分息争析
  1. void __android_log_logd_logger(const struct __android_log_message* log_message) {
  2.   int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;
  3.   struct iovec vec[3];
  4.   vec[0].iov_base =
  5.       const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
  6.   vec[0].iov_len = 1;
  7.   vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
  8.   vec[1].iov_len = strlen(log_message->tag) + 1;
  9.   vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
  10.   vec[2].iov_len = strlen(log_message->message) + 1;
  11.   write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
  12. }
复制代码
__android_log_buf_print

也是调用__android_log_write_log_message,同上
  1. int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...) {
  2.   ErrnoRestorer errno_restorer;
  3.   if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
  4.     return -EPERM;
  5.   }
  6.   va_list ap;
  7.   __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
  8.   va_start(ap, fmt);
  9.   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
  10.   va_end(ap);
  11.   __android_log_message log_message = {
  12.       sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, buf};
  13.   __android_log_write_log_message(&log_message);
  14.   return 1;
  15. }
复制代码
__android_log_bwrite/__android_log_btwrite/__android_log_bswrite



  • __android_log_bwrite 的内容可由多个值组成
  • __android_log_btwrite 的内容只有一个值,类型为参数type
  • __android_log_btwrite 的内容为字符串
  1. int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
  2.   ErrnoRestorer errno_restorer;
  3.   struct iovec vec[2];
  4.   vec[0].iov_base = &tag;
  5.   vec[0].iov_len = sizeof(tag);
  6.   vec[1].iov_base = (void*)payload;
  7.   vec[1].iov_len = len;
  8.   return write_to_log(LOG_ID_EVENTS, vec, 2);
  9. }
  10. int __android_log_btwrite(int32_t tag, char type, const void* payload, size_t len) {
  11.   ErrnoRestorer errno_restorer;
  12.   struct iovec vec[3];
  13.   vec[0].iov_base = &tag;
  14.   vec[0].iov_len = sizeof(tag);
  15.   vec[1].iov_base = &type;
  16.   vec[1].iov_len = sizeof(type);
  17.   vec[2].iov_base = (void*)payload;
  18.   vec[2].iov_len = len;
  19.   return write_to_log(LOG_ID_EVENTS, vec, 3);
  20. }
  21. int __android_log_bswrite(int32_t tag, const char* payload) {
  22.   ErrnoRestorer errno_restorer;
  23.   struct iovec vec[4];
  24.   char type = EVENT_TYPE_STRING;
  25.   uint32_t len = strlen(payload);
  26.   vec[0].iov_base = &tag;
  27.   vec[0].iov_len = sizeof(tag);
  28.   vec[1].iov_base = &type;
  29.   vec[1].iov_len = sizeof(type);
  30.   vec[2].iov_base = &len;
  31.   vec[2].iov_len = sizeof(len);
  32.   vec[3].iov_base = (void*)payload;
  33.   vec[3].iov_len = len;
  34.   return write_to_log(LOG_ID_EVENTS, vec, 4);
  35. }
复制代码
# C/C++写入日志

system/logging/liblog/include/log/log.h(Android13)
属性LOG_NDEBUG限定Log的输出(为0时相关函数界说为空)
  1. #ifndef LOG_NDEBUG
  2. #ifdef NDEBUG
  3. #define LOG_NDEBUG 1
  4. #else
  5. #define LOG_NDEBUG 0
  6. #endif
  7. #endif
复制代码
属性LOG_TAG界说了当前编译单位的日志TAG,默认为空
  1. #ifndef LOG_TAG
  2. #define LOG_TAG NULL
  3. #endif
复制代码
ALOGV 、ALOGD 、ALOGI 、ALOGW 和ALOGE

/system/logging/liblog/include/log/log_main.h,ALOGV只有当LOG_NDEBUG为0时才有效
  1. #ifndef ALOGV
  2. #define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
  3. #if LOG_NDEBUG
  4. #define ALOGV(...)                   \
  5.   do {                               \
  6.     __FAKE_USE_VA_ARGS(__VA_ARGS__); \
  7.     if (false) {                     \
  8.       __ALOGV(__VA_ARGS__);          \
  9.     }                                \
  10.   } while (false)
  11. #else
  12. #define ALOGV(...) __ALOGV(__VA_ARGS__)
  13. #endif
  14. #endif
  15. #ifndef ALOGD
  16. #define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
  17. #endif
  18. #ifndef ALOGI
  19. #define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
  20. #endif
  21. #ifndef ALOGW
  22. #define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
  23. #endif
  24. #ifndef ALOGE
  25. #define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
  26. #endif
复制代码
调用ALOG、LOG_PRI、android_printLog,最后调用运行时库的__android_log_print
  1. #ifndef ALOG
  2. #define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
  3. #endif
  4. #ifndef LOG_PRI
  5. #define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
  6. #endif
  7. #define android_printLog(prio, tag, ...) \
  8.   __android_log_print(prio, tag, __VA_ARGS__)
复制代码
RLOGV、RLOGD、RLOGI、RLOGW和RLOGE

/system/logging/liblog/include/log/log_radio.h
同理,RLOGV只有在LOG_NDEBUG为0才有效,最后调用运行时库的__android_log_buf_print,传入LOG_ID_RADIO
  1. #ifndef RLOGV
  2. #define __RLOGV(...)                                                         \
  3.   ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, \
  4.                                  __VA_ARGS__))
  5. #if LOG_NDEBUG
  6. #define RLOGV(...)          \
  7.   do {                      \
  8.     if (0) {                \
  9.       __RLOGV(__VA_ARGS__); \
  10.     }                       \
  11.   } while (0)
  12. #else
  13. #define RLOGV(...) __RLOGV(__VA_ARGS__)
  14. #endif
  15. #endif
  16. #ifndef RLOGD
  17. #define RLOGD(...)                                                         \
  18.   ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, \
  19.                                  __VA_ARGS__))
  20. #endif
  21. #ifndef RLOGI
  22. #define RLOGI(...)                                                        \
  23.   ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, \
  24.                                  __VA_ARGS__))
  25. #endif
  26. #ifndef RLOGW
  27. #define RLOGW(...)                                                        \
  28.   ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, \
  29.                                  __VA_ARGS__))
  30. #endif
  31. #ifndef RLOGE
  32. #define RLOGE(...)                                                         \
  33.   ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, \
  34.                                  __VA_ARGS__))
  35. #endif
复制代码
SLOGV、SLOGD、SLOGI、SLOGW和SLOGE

/system/logging/liblog/include/log/log_system.h
同理,SLOGV只有在LOG_NDEBUG为0才有效,最后调用运行时库的__android_log_buf_print,传入LOG_ID_SYSTEM
  1. #ifndef SLOGV
  2. #define __SLOGV(...)                                                          \
  3.   ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, \
  4.                                  __VA_ARGS__))
  5. #if LOG_NDEBUG
  6. #define SLOGV(...)          \
  7.   do {                      \
  8.     if (0) {                \
  9.       __SLOGV(__VA_ARGS__); \
  10.     }                       \
  11.   } while (0)
  12. #else
  13. #define SLOGV(...) __SLOGV(__VA_ARGS__)
  14. #endif
  15. #endif
  16. #ifndef SLOGD
  17. #define SLOGD(...)                                                          \
  18.   ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, \
  19.                                  __VA_ARGS__))
  20. #endif
  21. #ifndef SLOGI
  22. #define SLOGI(...)                                                         \
  23.   ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, \
  24.                                  __VA_ARGS__))
  25. #endif
  26. #ifndef SLOGW
  27. #define SLOGW(...)                                                         \
  28.   ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, \
  29.                                  __VA_ARGS__))
  30. #endif
  31. #ifndef SLOGE
  32. #define SLOGE(...)                                                          \
  33.   ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, \
  34.                                  __VA_ARGS__))
  35. #endif
复制代码
LOG_EVENT_INT、LOG_EVENT_LONG、LOG_EVENT_FLOAT和LOG_EVENT_STRING

system/logging/liblog/include/log/log.h


  • LOG_EVENT_INT、LOG_EVENT_LONG和LOG_EVENT_LONG调用android_btWriteLog,最后调用运行时库的__android_log_btwrite
  • LOG_EVENT_STRING调用运行时库的__android_log_bswrite
  1. #define android_btWriteLog(tag, type, payload, len) \
  2.   __android_log_btwrite(tag, type, payload, len)
  3. typedef enum {
  4.   /* Special markers for android_log_list_element type */
  5.   EVENT_TYPE_LIST_STOP = '\n', /* declare end of list  */
  6.   EVENT_TYPE_UNKNOWN = '?',    /* protocol error       */
  7.   /* must match with declaration in java/android/android/util/EventLog.java */
  8.   EVENT_TYPE_INT = 0,  /* int32_t */
  9.   EVENT_TYPE_LONG = 1, /* int64_t */
  10.   EVENT_TYPE_STRING = 2,
  11.   EVENT_TYPE_LIST = 3,
  12.   EVENT_TYPE_FLOAT = 4,
  13. } AndroidEventLogType;
  14. #ifndef LOG_EVENT_INT
  15. #define LOG_EVENT_INT(_tag, _value)                                          \
  16.   {                                                                          \
  17.     int intBuf = _value;                                                     \
  18.     (void)android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)); \
  19.   }
  20. #endif
  21. #ifndef LOG_EVENT_LONG
  22. #define LOG_EVENT_LONG(_tag, _value)                                            \
  23.   {                                                                             \
  24.     long long longBuf = _value;                                                 \
  25.     (void)android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)); \
  26.   }
  27. #endif
  28. #ifndef LOG_EVENT_FLOAT
  29. #define LOG_EVENT_FLOAT(_tag, _value)                           \
  30.   {                                                             \
  31.     float floatBuf = _value;                                    \
  32.     (void)android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
  33.                              sizeof(floatBuf));                 \
  34.   }
  35. #endif
  36. #ifndef LOG_EVENT_STRING
  37. #define LOG_EVENT_STRING(_tag, _value) \
  38.   (void)__android_log_bswrite(_tag, _value);
  39. #endif
复制代码
Java写入日志

android.util.Log

frameworks/base/core/java/android/util/Log.java
  1. public final class Log {
  2.    ......
  3.     /**
  4.      * Priority constant for the println method; use Log.v.
  5.      */
  6.     public static final int VERBOSE = 2;
  7.     /**
  8.      * Priority constant for the println method; use Log.d.
  9.      */
  10.     public static final int DEBUG = 3;
  11.     /**
  12.      * Priority constant for the println method; use Log.i.
  13.      */
  14.     public static final int INFO = 4;
  15.     /**
  16.      * Priority constant for the println method; use Log.w.
  17.      */
  18.     public static final int WARN = 5;
  19.     /**
  20.      * Priority constant for the println method; use Log.e.
  21.      */
  22.     public static final int ERROR = 6;
  23.     /**
  24.      * Priority constant for the println method.
  25.      */
  26.     public static final int ASSERT = 7;
  27.         ......
  28.     public static int v(@Nullable String tag, @NonNull String msg) {
  29.         return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
  30.     }
  31.     public static int d(@Nullable String tag, @NonNull String msg) {
  32.         return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
  33.     }
  34.     public static int i(@Nullable String tag, @NonNull String msg) {
  35.         return println_native(LOG_ID_MAIN, INFO, tag, msg);
  36.     }
  37.     public static int w(@Nullable String tag, @NonNull String msg) {
  38.         return println_native(LOG_ID_MAIN, WARN, tag, msg);
  39.     }
  40.     public static int e(@Nullable String tag, @NonNull String msg) {
  41.         return println_native(LOG_ID_MAIN, ERROR, tag, msg);
  42.     }
  43.         ......
  44.     /** @hide */ public static final int LOG_ID_MAIN = 0;
  45.     /** @hide */ public static final int LOG_ID_RADIO = 1;
  46.     /** @hide */ public static final int LOG_ID_EVENTS = 2;
  47.     /** @hide */ public static final int LOG_ID_SYSTEM = 3;
  48.     /** @hide */ public static final int LOG_ID_CRASH = 4;       
  49.         ......
  50. }
复制代码
调用println_native,传入LOG_ID_MAIN
println_native

根据frameworks/base/core/jni/android_util_Log.cpp
  1. static const JNINativeMethod gMethods[] = {
  2.         ......
  3.     { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
  4.           ......
  5. };
复制代码
可知对应的调用函数,判定日志内容msgObj 是否为空,判定类型是否在[0, LOG_ID_MAX],最后调用运行时库的__android_log_buf_write写入log
  1. static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
  2.         jint bufID, jint priority, jstring tagObj, jstring msgObj)
  3. {
  4.     const char* tag = NULL;
  5.     const char* msg = NULL;
  6.     if (msgObj == NULL) {
  7.         jniThrowNullPointerException(env, "println needs a message");
  8.         return -1;
  9.     }
  10.     if (bufID < 0 || bufID >= LOG_ID_MAX) {
  11.         jniThrowNullPointerException(env, "bad bufID");
  12.         return -1;
  13.     }
  14.     if (tagObj != NULL)
  15.         tag = env->GetStringUTFChars(tagObj, NULL);
  16.     msg = env->GetStringUTFChars(msgObj, NULL);
  17.     int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
  18.     if (tag != NULL)
  19.         env->ReleaseStringUTFChars(tagObj, tag);
  20.     env->ReleaseStringUTFChars(msgObj, msg);
  21.     return res;
  22. }
复制代码
android.util.Slog

frameworks/base/core/java/android/util/Slog.java
只可在系统内部使用,同上调用Log中的println_native传入LOG_ID_SYSTEM
  1. public final class Slog {
  2.        
  3.         ......
  4.        
  5.         @UnsupportedAppUsage
  6.     public static int v(@Nullable String tag, @NonNull String msg) {
  7.         return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg);
  8.     }
  9.        
  10.         @UnsupportedAppUsage
  11.     public static int d(@Nullable String tag, @NonNull String msg) {
  12.         return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
  13.     }
  14.     @UnsupportedAppUsage
  15.     public static int i(@Nullable String tag, @NonNull String msg) {
  16.         return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg);
  17.     }
  18.     @UnsupportedAppUsage
  19.     public static int w(@Nullable String tag, @NonNull String msg) {
  20.         return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg);
  21.     }
  22.     @UnsupportedAppUsage
  23.     public static int e(@Nullable String tag, @NonNull String msg) {
  24.         return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg);
  25.     }
  26. }
复制代码
android.util.Rlog

frameworks/base/core/java/android/util/Rlog.java
只可在系统内部使用,同上调用Log中的println_native传入LOG_ID_RADIO
  1. public final class Rlog {
  2.        
  3.         .....
  4.     @UnsupportedAppUsage
  5.     public static int v(String tag, String msg) {
  6.         return Log.println_native(Log.LOG_ID_RADIO, Log.VERBOSE, tag, msg);
  7.     }
  8.     @UnsupportedAppUsage
  9.     public static int d(String tag, String msg) {
  10.         return Log.println_native(Log.LOG_ID_RADIO, Log.DEBUG, tag, msg);
  11.     }
  12.     @UnsupportedAppUsage
  13.     public static int i(String tag, String msg) {
  14.         return Log.println_native(Log.LOG_ID_RADIO, Log.INFO, tag, msg);
  15.     }
  16.     @UnsupportedAppUsage
  17.     public static int w(String tag, String msg) {
  18.         return Log.println_native(Log.LOG_ID_RADIO, Log.WARN, tag, msg);
  19.     }
  20.     @UnsupportedAppUsage
  21.     public static int e(String tag, String msg) {
  22.         return Log.println_native(Log.LOG_ID_RADIO, Log.ERROR, tag, msg);
  23.     }
  24.     public static int println(int priority, String tag, String msg) {
  25.         return Log.println_native(Log.LOG_ID_RADIO, priority, tag, msg);
  26.     }
  27. }
复制代码
android.util.EventLog

frameworks/base/core/java/android/util/EventLog.java,重载了5个版本的writeEvent方法,日志内容分别为int、long、float、string、list
  1. public class EventLog {
  2.         ......
  3.        
  4.         private static final byte INT_TYPE    = 0;
  5.     private static final byte LONG_TYPE   = 1;
  6.     private static final byte STRING_TYPE = 2;
  7.     private static final byte LIST_TYPE   = 3;
  8.     private static final byte FLOAT_TYPE = 4;
  9.    
  10.     public static native int writeEvent(int tag, int value);
  11.     public static native int writeEvent(int tag, long value);
  12.     public static native int writeEvent(int tag, float value);
  13.     public static native int writeEvent(int tag, String str);
  14.     public static native int writeEvent(int tag, Object... list);
  15.        
  16.         ......
  17. }
复制代码
writeEvent

根据frameworks/base/core/jni/android_util_EventLog.cpp
  1. static const JNINativeMethod gRegisterMethods[] = {
  2.     /* name, signature, funcPtr */
  3.     { "writeEvent", "(II)I", (void*) ELog::writeEventInteger },
  4.     { "writeEvent", "(IJ)I", (void*) ELog::writeEventLong },
  5.     { "writeEvent", "(IF)I", (void*) ELog::writeEventFloat },
  6.     { "writeEvent", "(ILjava/lang/String;)I", (void*) ELog::writeEventString },
  7.     { "writeEvent", "(I[Ljava/lang/Object;)I", (void*) ELog::writeEventArray },
  8.     ......
  9. };
复制代码
可知调用
  1. static jint writeEventInteger(JNIEnv* env ATTRIBUTE_UNUSED, jobject clazz ATTRIBUTE_UNUSED,
  2.         jint tag, jint value) {
  3.     android_log_event_list ctx(tag);
  4.     ctx << (int32_t)value;
  5.     return ctx.write(LogID);
  6. }
  7. static jint writeEventLong(JNIEnv* env ATTRIBUTE_UNUSED, jobject clazz ATTRIBUTE_UNUSED,
  8.         jint tag, jlong value) {
  9.     android_log_event_list ctx(tag);
  10.     ctx << (int64_t)value;
  11.     return ctx.write(LogID);
  12. }
  13. static jint writeEventFloat(JNIEnv* env ATTRIBUTE_UNUSED, jobject clazz ATTRIBUTE_UNUSED,
  14.         jint tag, jfloat value) {
  15.     android_log_event_list ctx(tag);
  16.     ctx << (float)value;
  17.     return ctx.write(LogID);
  18. }
  19. static jint writeEventString(JNIEnv* env, jobject clazz ATTRIBUTE_UNUSED, jint tag,
  20.         jstring value) {
  21.     android_log_event_list ctx(tag);
  22.     // Don't throw NPE -- I feel like it's sort of mean for a logging function
  23.     // to be all crashy if you pass in NULL -- but make the NULL value explicit.
  24.     ctx << (value != nullptr ? ScopedUtfChars(env, value).c_str() : "NULL");
  25.     return ctx.write(LogID);
  26. }
  27. static jint writeEventArray(JNIEnv* env, jobject clazz ATTRIBUTE_UNUSED, jint tag,
  28.         jobjectArray value) {
  29.     android_log_event_list ctx(tag);
  30.     if (value == nullptr) {
  31.         ctx << "[NULL]";
  32.         return ctx.write(LogID);
  33.     }
  34.     jsize copied = 0, num = env->GetArrayLength(value);
  35.     for (; copied < num && copied < 255; ++copied) {
  36.         if (ctx.status()) break;
  37.         ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(value, copied));
  38.         if (item == nullptr) {
  39.             ctx << "NULL";
  40.         } else if (env->IsInstanceOf(item.get(), gStringClass)) {
  41.             ctx << ScopedUtfChars(env, (jstring) item.get()).c_str();
  42.         } else if (env->IsInstanceOf(item.get(), gIntegerClass)) {
  43.             ctx << (int32_t)env->GetIntField(item.get(), gIntegerValueID);
  44.         } else if (env->IsInstanceOf(item.get(), gLongClass)) {
  45.             ctx << (int64_t)env->GetLongField(item.get(), gLongValueID);
  46.         } else if (env->IsInstanceOf(item.get(), gFloatClass)) {
  47.             ctx << (float)env->GetFloatField(item.get(), gFloatValueID);
  48.         } else {
  49.             jniThrowException(env,
  50.                     "java/lang/IllegalArgumentException",
  51.                     "Invalid payload item type");
  52.             return -1;
  53.         }
  54.     }
  55.     return ctx.write(LogID);
  56. }
复制代码
log_event_list

system/logging/liblog/include/log/log_event_list.h
  1. int android_log_write_list(android_log_context ctx, log_id_t id);
  2. class android_log_event_list {
  3.         ......
  4.     int write(log_id_t id = LOG_ID_EVENTS) {
  5.     /* facilitate -EBUSY retry */
  6.     if ((ret == -EBUSY) || (ret > 0)) ret = 0;
  7.     int retval = android_log_write_list(ctx, id);
  8.     /* existing errors trump transmission errors */
  9.     if (!ret) ret = retval;
  10.     return ret;
  11.   }
  12.    ......
  13. }
复制代码
system/logging/liblog/log_event_list.cpp,根据id == LOG_ID_EVENTS调用__android_log_bwrite
  1. int android_log_write_list(android_log_context context, log_id_t id) {
  2.   const char* msg;
  3.   ssize_t len;
  4.   if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (id != LOG_ID_STATS)) {
  5.     return -EINVAL;
  6.   }
  7.   if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
  8.     return -EBADF;
  9.   }
  10.   if (context->list_nest_depth) {
  11.     return -EIO;
  12.   }
  13.   /* NB: if there was overflow, then log is truncated. Nothing reported */
  14.   context->storage[1] = context->count[0];
  15.   len = context->len = context->pos;
  16.   msg = (const char*)context->storage;
  17.   /* it's not a list */
  18.   if (context->count[0] <= 1) {
  19.     len -= sizeof(uint8_t) + sizeof(uint8_t);
  20.     if (len < 0) {
  21.       len = 0;
  22.     }
  23.     msg += sizeof(uint8_t) + sizeof(uint8_t);
  24.   }
  25.   return (id == LOG_ID_EVENTS)
  26.              ? __android_log_bwrite(context->tag, msg, len)
  27.              : ((id == LOG_ID_STATS) ? __android_log_stats_bwrite(context->tag, msg, len)
  28.                                      : __android_log_security_bwrite(context->tag, msg, len));
  29. }
复制代码
Logcat工具分析

基础数据布局

logcat

system/logging/logcat/logcat.cpp
  1. int main(int argc, char** argv) {
  2.     Logcat logcat;
  3.     return logcat.Run(argc, argv);
  4. }
复制代码
下面来分析其Run方法
命令参数

  1. int Logcat::Run(int argc, char** argv) {
  2.            ......
  3.     while (true) {
  4.     ......
  5.         switch (c) {
  6.                 ......
  7.             case 'd':
  8.                 mode |= ANDROID_LOG_NONBLOCK;
  9.                 break;
  10.             case 't':
  11.                 got_t = true;
  12.                 mode |= ANDROID_LOG_NONBLOCK;
  13.                 FALLTHROUGH_INTENDED;
  14.             case 'T':
  15.                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
  16.                     char* cp = parseTime(tail_time, optarg);
  17.                     if (!cp) {
  18.                         error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
  19.                     }
  20.                     if (*cp) {
  21.                         char ch = *cp;
  22.                         *cp = '\0';
  23.                         fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
  24.                                 cp + 1);
  25.                         *cp = ch;
  26.                     }
  27.                 } else {
  28.                     if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
  29.                         fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
  30.                         tail_lines = 1;
  31.                     }
  32.                 }
  33.                 break;
  34.             case 'D':
  35.                 print_dividers_ = true;
  36.                 break;
  37.             case 'e':
  38.                 regex_.reset(new std::regex(optarg));
  39.                 break;
  40.             case 'm': {
  41.                 if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
  42.                     error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
  43.                           optarg);
  44.                 }
  45.             } break;
  46.             case 'g':
  47.                 if (!optarg) {
  48.                     getLogSize = true;
  49.                     break;
  50.                 }
  51.                 FALLTHROUGH_INTENDED;
  52.             case 'G': {
  53.                 if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
  54.                     error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
  55.                 }
  56.             } break;
  57.             case 'p':
  58.                 if (!optarg) {
  59.                     getPruneList = true;
  60.                     break;
  61.                 }
  62.                 FALLTHROUGH_INTENDED;
  63.             case 'P':
  64.                 setPruneList = optarg;
  65.                 break;
  66.             case 'b':
  67.                 for (const auto& buffer : Split(optarg, delimiters)) {
  68.                     if (buffer == "default") {
  69.                         id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
  70.                     } else if (buffer == "all") {
  71.                         id_mask = -1;
  72.                     } else {
  73.                         log_id_t log_id = android_name_to_log_id(buffer.c_str());
  74.                         if (log_id >= LOG_ID_MAX) {
  75.                             error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
  76.                                   buffer.c_str());
  77.                         }
  78.                         if (log_id == LOG_ID_SECURITY) {
  79.                             security_buffer_selected = true;
  80.                         }
  81.                         id_mask |= (1 << log_id);
  82.                     }
  83.                 }
  84.                 break;
  85.             case 'B':
  86.                 print_binary_ = 1;
  87.                 break;
  88.             case 'f':
  89.                 if ((tail_time == log_time::EPOCH) && !tail_lines) {
  90.                     tail_time = lastLogTime(optarg);
  91.                 }
  92.                 // redirect output to a file
  93.                 output_file_name_ = optarg;
  94.                 break;
  95.             case 'r':
  96.                 if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
  97.                     error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
  98.                 }
  99.                 break;
  100.             case 'n':
  101.                 if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
  102.                     error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
  103.                 }
  104.                 break;
  105.             case 'v':
  106.                 for (const auto& arg : Split(optarg, delimiters)) {
  107.                     int err = SetLogFormat(arg.c_str());
  108.                     if (err < 0) {
  109.                         error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
  110.                     }
  111.                     if (err) hasSetLogFormat = true;
  112.                 }
  113.                 break;
  114.             case 'S':
  115.                 printStatistics = true;
  116.                 break;
  117.             case ':':
  118.                 error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
  119.                 break;
  120.             case 'h':
  121.                 show_help();
  122.                 return EXIT_SUCCESS;
  123.             case '?':
  124.                 error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind]);
  125.                 break;
  126.             default:
  127.                 error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
  128.         }
  129.     }
复制代码


  • d 把 mode设为ANDROID_LOG_NONBLOCK,表示没有日志纪录可读时logcat直接退出
  • t 将got_t 设为true,表示只输出最新的日志
  • b 将参数分割出来,通过id_mask设置读取的装备
  • B print_binary_ = 1,表示以二进制输出日志
  • f 指定输出文件output_file_name_
  • r 指定输出文件的大小log_rotate_size_kb_(默认0无穷制)
  • n 指定输出文件的个数max_rotated_logs_(默认4),若输出日志时,已超过-r指定大小,则建立新的日志文件,格式为xxx.1/xxx.2/xxx.n
  • v 调用SetLogFormat设置日志输特别式,将参数转为AndroidLogPrintFormat并设置到p_format->format
  1. int Logcat::SetLogFormat(const char* format_string) {
  2.     AndroidLogPrintFormat format = android_log_formatFromString(format_string);
  3.     // invalid string?
  4.     if (format == FORMAT_OFF) return -1;
  5.     return android_log_setPrintFormat(logformat_.get(), format);
  6. }
复制代码
system/logging/liblog/logprint.cpp
  1. AndroidLogPrintFormat android_log_formatFromString(const char* formatString) {
  2.   /* clang-format off */
  3.   if (!strcmp(formatString, "brief")) return FORMAT_BRIEF;
  4.   if (!strcmp(formatString, "process")) return FORMAT_PROCESS;
  5.   if (!strcmp(formatString, "tag")) return FORMAT_TAG;
  6.   if (!strcmp(formatString, "thread")) return FORMAT_THREAD;
  7.   if (!strcmp(formatString, "raw")) return FORMAT_RAW;
  8.   if (!strcmp(formatString, "time")) return FORMAT_TIME;
  9.   if (!strcmp(formatString, "threadtime")) return FORMAT_THREADTIME;
  10.   if (!strcmp(formatString, "long")) return FORMAT_LONG;
  11.   if (!strcmp(formatString, "color")) return FORMAT_MODIFIER_COLOR;
  12.   if (!strcmp(formatString, "colour")) return FORMAT_MODIFIER_COLOR;
  13.   if (!strcmp(formatString, "usec")) return FORMAT_MODIFIER_TIME_USEC;
  14.   if (!strcmp(formatString, "nsec")) return FORMAT_MODIFIER_TIME_NSEC;
  15.   if (!strcmp(formatString, "printable")) return FORMAT_MODIFIER_PRINTABLE;
  16.   if (!strcmp(formatString, "year")) return FORMAT_MODIFIER_YEAR;
  17.   if (!strcmp(formatString, "zone")) return FORMAT_MODIFIER_ZONE;
  18.   if (!strcmp(formatString, "epoch")) return FORMAT_MODIFIER_EPOCH;
  19.   if (!strcmp(formatString, "monotonic")) return FORMAT_MODIFIER_MONOTONIC;
  20.   if (!strcmp(formatString, "uid")) return FORMAT_MODIFIER_UID;
  21.   if (!strcmp(formatString, "descriptive")) return FORMAT_MODIFIER_DESCRIPT;
  22.     /* clang-format on */
  23. #if !defined(__MINGW32__)
  24.   // Check whether the format string is actually a time zone. If tzname[0]
  25.   // is the empty string, that's tzset() signalling that it doesn't know
  26.   // the requested timezone.
  27.   TzSetter tz(formatString);
  28.   if (!*tzname[0]) {
  29.     tz.Reset();
  30.   } else {
  31.     // We keep the new time zone as a side effect!
  32.     return FORMAT_MODIFIER_ZONE;
  33.   }
  34. #endif
  35.   return FORMAT_OFF;
  36. }
  37. int android_log_setPrintFormat(AndroidLogFormat* p_format, AndroidLogPrintFormat format) {
  38.   switch (format) {
  39.     case FORMAT_MODIFIER_COLOR:
  40.       p_format->colored_output = true;
  41.       return 0;
  42.     case FORMAT_MODIFIER_TIME_USEC:
  43.       p_format->usec_time_output = true;
  44.       return 0;
  45.     case FORMAT_MODIFIER_TIME_NSEC:
  46.       p_format->nsec_time_output = true;
  47.       return 0;
  48.     case FORMAT_MODIFIER_PRINTABLE:
  49.       p_format->printable_output = true;
  50.       return 0;
  51.     case FORMAT_MODIFIER_YEAR:
  52.       p_format->year_output = true;
  53.       return 0;
  54.     case FORMAT_MODIFIER_ZONE:
  55.       p_format->zone_output = !p_format->zone_output;
  56.       return 0;
  57.     case FORMAT_MODIFIER_EPOCH:
  58.       p_format->epoch_output = true;
  59.       return 0;
  60.     case FORMAT_MODIFIER_MONOTONIC:
  61.       p_format->monotonic_output = true;
  62.       return 0;
  63.     case FORMAT_MODIFIER_UID:
  64.       p_format->uid_output = true;
  65.       return 0;
  66.     case FORMAT_MODIFIER_DESCRIPT:
  67.       p_format->descriptive_output = true;
  68.       descriptive_output = true;
  69.       return 0;
  70.     default:
  71.       break;
  72.   }
  73.   p_format->format = format;
  74.   return 1;
  75. }
复制代码
日志的格式为<PREFIX>+MESSAGE+<SUFFIX>,差别格式的<PREFIX>和<SUFFIX>差别


  • FORMAT_BRIEF:“<priority>/<tag>(<pid>):”和“\n”。
  • FORMAT_PROCESS:“<priority>(<pid>)”和“(<t a g>)\n”。
  • FORMAT_TAG:“<priority>/(<tag>):”和“\n”。
  • FORMAT_THREAD:“<priority>(<pid>:<tid>)”和“\n”。
  • FORMAT_RAW:空值和“\n”。
  • FORMAT_TIME:“<sec>.<nsec> <priority>/<tag>(<pid>):”和“\n”。
  • FORMAT_THREADTIME:“<sec>.<nsec><pid><tid><priority><tag>:”和“\n”。
  • FORMAT_LONG:“[<sec>.<nsec> <pid>:<tid><priority>/<tag>]”和“\n\n”
其他

上面解析完参数,继续往后走,未指定选项b时,默认输出MAIN、system、crash、kernel的log
  1.     // If no buffers are specified, default to using these buffers.
  2.     if (id_mask == 0) {
  3.         id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
  4.                   (1 << LOG_ID_KERNEL);
  5.     }
复制代码
未设置选项v时,将情况变量ANDROID_PRINTF_LOG的值设置为当前格式,若无则设置为threadtime
  1.     if (!hasSetLogFormat) {
  2.         const char* logFormat = getenv("ANDROID_PRINTF_LOG");
  3.         if (!!logFormat) {
  4.             for (const auto& arg : Split(logFormat, delimiters)) {
  5.                 int err = SetLogFormat(arg.c_str());
  6.                 // environment should not cause crash of logcat
  7.                 if (err < 0) {
  8.                     fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
  9.                 }
  10.                 if (err > 0) hasSetLogFormat = true;
  11.             }
  12.         }
  13.         if (!hasSetLogFormat) {
  14.             SetLogFormat("threadtime");
  15.         }
  16.     }
复制代码


  • forceFilters.size()不为0,表示通过选项Q让logcat读取/proc/cmdline中的过滤器
  • argc == optind表示命令没有其他参数,读取ANDROID_LOG_TAGS的值作为过滤器
  • 将命令参数设置为过滤器,格式为 tag:priority,如 *:E
  1.     if (forceFilters.size()) {
  2.         int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
  3.         if (err < 0) {
  4.             error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
  5.         }
  6.     } else if (argc == optind) {
  7.         // Add from environment variable
  8.         const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
  9.         if (!!env_tags_orig) {
  10.             int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
  11.             if (err < 0) {
  12.                 error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
  13.             }
  14.         }
  15.     } else {
  16.         // Add from commandline
  17.         for (int i = optind ; i < argc ; i++) {
  18.             int err = android_log_addFilterString(logformat_.get(), argv[i]);
  19.             if (err < 0) {
  20.                 error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
  21.             }
  22.         }
  23.     }
复制代码
通过android_log_addFilterString设置过滤器,filterString大概以空格、tab或逗号分割
  1. int android_log_addFilterString(AndroidLogFormat* p_format, const char* filterString) {
  2.   char* filterStringCopy = strdup(filterString);
  3.   char* p_cur = filterStringCopy;
  4.   char* p_ret;
  5.   int err;
  6.   /* Yes, I'm using strsep */
  7.   while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
  8.     /* ignore whitespace-only entries */
  9.     if (p_ret[0] != '\0') {
  10.       err = android_log_addFilterRule(p_format, p_ret);
  11.       if (err < 0) {
  12.         goto error;
  13.       }
  14.     }
  15.   }
  16.   free(filterStringCopy);
  17.   return 0;
  18. error:
  19.   free(filterStringCopy);
  20.   return -1;
  21. }
复制代码
通过android_log_addFilterRule添加解析过滤器,将冒号后面的字符转为android_LogPriority,通过tagName和pri创建FilterInfo
  1. int android_log_addFilterRule(AndroidLogFormat* p_format, const char* filterExpression) {
  2.   size_t tagNameLength;
  3.   android_LogPriority pri = ANDROID_LOG_DEFAULT;
  4.   tagNameLength = strcspn(filterExpression, ":");
  5.   if (tagNameLength == 0) {
  6.     goto error;
  7.   }
  8.   if (filterExpression[tagNameLength] == ':') {
  9.     pri = filterCharToPri(filterExpression[tagNameLength + 1]);
  10.     if (pri == ANDROID_LOG_UNKNOWN) {
  11.       goto error;
  12.     }
  13.   }
  14.   if (0 == strncmp("*", filterExpression, tagNameLength)) {
  15.     /*
  16.      * This filter expression refers to the global filter
  17.      * The default level for this is DEBUG if the priority
  18.      * is unspecified
  19.      */
  20.     if (pri == ANDROID_LOG_DEFAULT) {
  21.       pri = ANDROID_LOG_DEBUG;
  22.     }
  23.     p_format->global_pri = pri;
  24.   } else {
  25.     /*
  26.      * for filter expressions that don't refer to the global
  27.      * filter, the default is verbose if the priority is unspecified
  28.      */
  29.     if (pri == ANDROID_LOG_DEFAULT) {
  30.       pri = ANDROID_LOG_VERBOSE;
  31.     }
  32.     char* tagName;
  33. /*
  34. * Presently HAVE_STRNDUP is never defined, so the second case is always taken
  35. * Darwin doesn't have strndup, everything else does
  36. */
  37. #ifdef HAVE_STRNDUP
  38.     tagName = strndup(filterExpression, tagNameLength);
  39. #else
  40.     /* a few extra bytes copied... */
  41.     tagName = strdup(filterExpression);
  42.     tagName[tagNameLength] = '\0';
  43. #endif /*HAVE_STRNDUP*/
  44.     FilterInfo* p_fi = filterinfo_new(tagName, pri);
  45.     free(tagName);
  46.     p_fi->p_next = p_format->filters;
  47.     p_format->filters = p_fi;
  48.   }
  49.   return 0;
  50. error:
  51.   return -1;
  52. }
  53. static android_LogPriority filterCharToPri(char c) {
  54.   android_LogPriority pri;
  55.   c = tolower(c);
  56.   if (c >= '0' && c <= '9') {
  57.     if (c >= ('0' + ANDROID_LOG_SILENT)) {
  58.       pri = ANDROID_LOG_VERBOSE;
  59.     } else {
  60.       pri = (android_LogPriority)(c - '0');
  61.     }
  62.   } else if (c == 'v') {
  63.     pri = ANDROID_LOG_VERBOSE;
  64.   } else if (c == 'd') {
  65.     pri = ANDROID_LOG_DEBUG;
  66.   } else if (c == 'i') {
  67.     pri = ANDROID_LOG_INFO;
  68.   } else if (c == 'w') {
  69.     pri = ANDROID_LOG_WARN;
  70.   } else if (c == 'e') {
  71.     pri = ANDROID_LOG_ERROR;
  72.   } else if (c == 'f') {
  73.     pri = ANDROID_LOG_FATAL;
  74.   } else if (c == 's') {
  75.     pri = ANDROID_LOG_SILENT;
  76.   } else if (c == '*') {
  77.     pri = ANDROID_LOG_DEFAULT;
  78.   } else {
  79.     pri = ANDROID_LOG_UNKNOWN;
  80.   }
  81.   return pri;
  82. }
复制代码
若通过选项f指定输出文件,通过max_rotated_logs_设置个数,格式为xxx.1/…/xxx.n
  1.     if (output_file_name_) {
  2.         if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
  3.             error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
  4.         }
  5.         if (clearLog || setId) {
  6.             int max_rotation_count_digits =
  7.                     max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
  8.             for (int i = max_rotated_logs_; i >= 0; --i) {
  9.                 std::string file;
  10.                 if (!i) {
  11.                     file = output_file_name_;
  12.                 } else {
  13.                     file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
  14.                 }
  15.                 int err = unlink(file.c_str());
  16.                 if (err < 0 && errno != ENOENT) {
  17.                     fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
  18.                             strerror(errno));
  19.                 }
  20.             }
  21.         }
  22.         if (clearLog) {
  23.             return EXIT_SUCCESS;
  24.         }
  25.     }
复制代码
根据id打开log装备
  1.     for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
  2.         if (!(id_mask & (1 << i))) continue;
  3.         const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
  4.         auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
  5.         if (logger == nullptr) {
  6.             ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
  7.             continue;
  8.         }
  9.         ......
复制代码
判定输出是二进制调用WriteFully,否则调用ProcessBuffer
  1.     while (!max_count_ || print_count_ < max_count_) {
  2.         ......
  3.         if (print_binary_) {
  4.             WriteFully(&log_msg, log_msg.len());
  5.         } else {
  6.             ProcessBuffer(&log_msg);
  7.         }
  8.         if (blocking && output_file_ == stdout) fflush(stdout);
  9.     }
  10.     return EXIT_SUCCESS;
  11. }
复制代码


  • 若日志类型是Event,调用android_log_processBinaryLogBuffer,否则调用android_log_processLogBuffer,他们都会将buf转为AndroidLogEntry用于输出
  • android_log_shouldPrintLine 判定tag和pri是否符合设置的过滤条件
  • 当日志超出大小时,调用RotateLogs建立新文件
  1. void Logcat::ProcessBuffer(struct log_msg* buf) {
  2.     AndroidLogEntry entry;
  3.     char binaryMsgBuf[1024] __attribute__((__uninitialized__));
  4.     bool is_binary =
  5.             buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
  6.     int err;
  7.     if (is_binary) {
  8.         if (!event_tag_map_ && !has_opened_event_tag_map_) {
  9.             event_tag_map_.reset(android_openEventTagMap(nullptr));
  10.             has_opened_event_tag_map_ = true;
  11.         }
  12.         // This causes entry to point to binaryMsgBuf!
  13.         err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
  14.                                                  binaryMsgBuf, sizeof(binaryMsgBuf));
  15.         // printf(">>> pri=%d len=%d msg='%s'\n",
  16.         //    entry.priority, entry.messageLen, entry.message);
  17.     } else {
  18.         err = android_log_processLogBuffer(&buf->entry, &entry);
  19.     }
  20.     if (err < 0 && !debug_) return;
  21.     if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
  22.                                     entry.priority)) {
  23.         bool match = !regex_ ||
  24.                      std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
  25.         print_count_ += match;
  26.         if (match || print_it_anyway_) {
  27.             PrintDividers(buf->id(), print_dividers_);
  28.             out_byte_count_ += android_log_printLogLine(logformat_.get(), output_file_, &entry);
  29.         }
  30.     }
  31.     if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
  32.         RotateLogs();
  33.     }
  34. }
复制代码
android_log_printLogLine时输出的最后一个步骤,调用android_log_formatLogLine格式化要输出的日志,调用fwrite把日志输出到文件形貌符fd所形貌的目标文件中
  1. size_t android_log_printLogLine(AndroidLogFormat* p_format, FILE* fp,
  2.                                 const AndroidLogEntry* entry) {
  3.   char buf[4096] __attribute__((__uninitialized__));
  4.   size_t line_length;
  5.   char* line = android_log_formatLogLine(p_format, buf, sizeof(buf), entry, &line_length);
  6.   if (!line) {
  7.     fprintf(stderr, "android_log_formatLogLine failed\n");
  8.     exit(1);
  9.   }
  10.   size_t bytesWritten = fwrite(line, 1, line_length, fp);
  11.   if (bytesWritten != line_length) {
  12.     perror("fwrite failed");
  13.     exit(1);
  14.   }
  15.   if (line != buf) free(line);
  16.   return bytesWritten;
  17. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

自由的羽毛

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表