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)
- 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
- struct logger_entry {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry) */
- int32_t pid; /* generating process's pid */
- uint32_t tid; /* generating process's tid */
- uint32_t sec; /* seconds since Epoch */
- uint32_t nsec; /* nanoseconds */
- uint32_t lid; /* log id of the payload, bottom 4 bits currently */
- uint32_t uid; /* generating process's uid */
- };
复制代码 log_msg
- 缓冲区5M
- 包罗logger_entry
- 若为C++,则新增函数返回nsec、lid、msg、len
- #define LOGGER_ENTRY_MAX_LEN (5 * 1024)
- struct log_msg {
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry entry;
- } __attribute__((aligned(4)));
- #ifdef __cplusplus
- uint64_t nsec() const {
- return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
- }
- log_id_t id() {
- return static_cast<log_id_t>(entry.lid);
- }
- char* msg() {
- unsigned short hdr_size = entry.hdr_size;
- if (hdr_size >= sizeof(struct log_msg) - sizeof(entry)) {
- return nullptr;
- }
- return reinterpret_cast<char*>(buf) + hdr_size;
- }
- unsigned int len() { return entry.hdr_size + entry.len; }
- #endif
- };
复制代码 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
- int main(int argc, char* argv[]) {
- // We want EPIPE when a reader disconnects, not to terminate logd.
- signal(SIGPIPE, SIG_IGN);
- // logd is written under the assumption that the timezone is UTC.
- // If TZ is not set, persist.sys.timezone is looked up in some time utility
- // libc functions, including mktime. It confuses the logd time handling,
- // so here explicitly set TZ to UTC, which overrides the property.
- setenv("TZ", "UTC", 1);
- // issue reinit command. KISS argument parsing.
- if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
- return issueReinit();
- }
- android::base::InitLogging(
- argv, [](android::base::LogId log_id, android::base::LogSeverity severity,
- const char* tag, const char* file, unsigned int line, const char* message) {
- if (tag && strcmp(tag, "logd") != 0) {
- auto prefixed_message = android::base::StringPrintf("%s: %s", tag, message);
- android::base::KernelLogger(log_id, severity, "logd", file, line,
- prefixed_message.c_str());
- } else {
- android::base::KernelLogger(log_id, severity, "logd", file, line, message);
- }
- });
- static const char dev_kmsg[] = "/dev/kmsg";
- int fdDmesg = android_get_control_file(dev_kmsg);
- if (fdDmesg < 0) {
- fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
- }
- int fdPmesg = -1;
- bool klogd = GetBoolPropertyEngSvelteDefault("ro.logd.kernel");
- if (klogd) {
- SetProperty("ro.logd.kernel", "true");
- static const char proc_kmsg[] = "/proc/kmsg";
- fdPmesg = android_get_control_file(proc_kmsg);
- if (fdPmesg < 0) {
- fdPmesg = TEMP_FAILURE_RETRY(
- open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
- }
- if (fdPmesg < 0) PLOG(ERROR) << "Failed to open " << proc_kmsg;
- }
- bool auditd = GetBoolProperty("ro.logd.auditd", true);
- DropPrivs(klogd, auditd);
- // A cache of event log tags
- LogTags log_tags;
- // Pruning configuration.
- PruneList prune_list;
- std::string buffer_type = GetProperty("logd.buffer_type", "serialized");
- LogStatistics log_statistics(GetBoolPropertyEngSvelteDefault("logd.statistics"),
- buffer_type == "serialized");
- // Serves the purpose of managing the last logs times read on a socket connection, and as a
- // reader lock on a range of log entries.
- LogReaderList reader_list;
- // LogBuffer is the object which is responsible for holding all log entries.
- LogBuffer* log_buffer = nullptr;
- if (buffer_type == "serialized") {
- log_buffer = new SerializedLogBuffer(&reader_list, &log_tags, &log_statistics);
- } else if (buffer_type == "simple") {
- log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);
- } else {
- LOG(FATAL) << "buffer_type must be one of 'serialized' or 'simple'";
- }
- // LogReader listens on /dev/socket/logdr. When a client
- // connects, log entries in the LogBuffer are written to the client.
- LogReader* reader = new LogReader(log_buffer, &reader_list);
- if (reader->startListener()) {
- return EXIT_FAILURE;
- }
- // LogListener listens on /dev/socket/logdw for client
- // initiated log messages. New log entries are added to LogBuffer
- // and LogReader is notified to send updates to connected clients.
- LogListener* swl = new LogListener(log_buffer);
- if (!swl->StartListener()) {
- return EXIT_FAILURE;
- }
- // Command listener listens on /dev/socket/logd for incoming logd
- // administrative commands.
- CommandListener* cl = new CommandListener(log_buffer, &log_tags, &prune_list, &log_statistics);
- if (cl->startListener()) {
- return EXIT_FAILURE;
- }
- // Notify that others can now interact with logd
- SetProperty("logd.ready", "true");
- // LogAudit listens on NETLINK_AUDIT socket for selinux
- // initiated log messages. New log entries are added to LogBuffer
- // and LogReader is notified to send updates to connected clients.
- LogAudit* al = nullptr;
- if (auditd) {
- int dmesg_fd = GetBoolProperty("ro.logd.auditd.dmesg", true) ? fdDmesg : -1;
- al = new LogAudit(log_buffer, dmesg_fd, &log_statistics);
- }
- LogKlog* kl = nullptr;
- if (klogd) {
- kl = new LogKlog(log_buffer, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
- }
- readDmesg(al, kl);
- // failure is an option ... messages are in dmesg (required by standard)
- if (kl && kl->startListener()) {
- delete kl;
- }
- if (al && al->startListener()) {
- delete al;
- }
- TrustyLog::create(log_buffer);
- TEMP_FAILURE_RETRY(pause());
- return EXIT_SUCCESS;
- }
复制代码 SerializedLogBuffer
- Log将日志封装成SerializedLogEntry、LogStatisticsElement添加到stats_
- SerializedLogBuffer::SerializedLogBuffer(LogReaderList* reader_list, LogTags* tags,
- LogStatistics* stats)
- : reader_list_(reader_list), tags_(tags), stats_(stats) {
- Init();
- }
- void SerializedLogBuffer::Init() {
- log_id_for_each(i) {
- if (!SetSize(i, GetBufferSizeFromProperties(i))) {
- SetSize(i, kLogBufferMinSize);
- }
- }
- // Release any sleeping reader threads to dump their current content.
- auto lock = std::lock_guard{logd_lock};
- for (const auto& reader_thread : reader_list_->running_reader_threads()) {
- reader_thread->TriggerReader();
- }
- }
- int SerializedLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len) {
- if (log_id >= LOG_ID_MAX || len == 0) {
- return -EINVAL;
- }
- if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
- len = LOGGER_ENTRY_MAX_PAYLOAD;
- }
- if (!ShouldLog(log_id, msg, len)) {
- stats_->AddTotal(log_id, len);
- return -EACCES;
- }
- auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
- auto lock = std::lock_guard{logd_lock};
- auto entry = LogToLogBuffer(logs_[log_id], max_size_[log_id], sequence, realtime, uid, pid, tid,
- msg, len);
- stats_->Add(entry->ToLogStatisticsElement(log_id));
- MaybePrune(log_id);
- reader_list_->NotifyNewLog(1 << log_id);
- return len;
- }
- static SerializedLogEntry* LogToLogBuffer(std::list<SerializedLogChunk>& log_buffer,
- size_t max_size, uint64_t sequence, log_time realtime,
- uid_t uid, pid_t pid, pid_t tid, const char* msg,
- uint16_t len) {
- if (log_buffer.empty()) {
- log_buffer.push_back(SerializedLogChunk(max_size / SerializedLogBuffer::kChunkSizeDivisor));
- }
- auto total_len = sizeof(SerializedLogEntry) + len;
- if (!log_buffer.back().CanLog(total_len)) {
- log_buffer.back().FinishWriting();
- log_buffer.push_back(SerializedLogChunk(max_size / SerializedLogBuffer::kChunkSizeDivisor));
- }
- return log_buffer.back().Log(sequence, realtime, uid, pid, tid, msg, len);
- }
复制代码 LogReader
LogListener
StartListener开启线程LogListener,循环调用HandleData,通过LogBuffer的Log方法写入日志
- LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
- bool LogListener::StartListener() {
- if (socket_ <= 0) {
- return false;
- }
- auto thread = std::thread(&LogListener::ThreadFunction, this);
- thread.detach();
- return true;
- }
- void LogListener::ThreadFunction() {
- prctl(PR_SET_NAME, "logd.writer");
- while (true) {
- HandleData();
- }
- }
- void LogListener::HandleData() {
- // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
- __attribute__((uninitialized)) char
- buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
- struct iovec iov = {buffer, sizeof(buffer) - 1};
- alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
- struct msghdr hdr = {
- nullptr, 0, &iov, 1, control, sizeof(control), 0,
- };
- ssize_t n = recvmsg(socket_, &hdr, 0);
- if (n <= (ssize_t)(sizeof(android_log_header_t))) {
- return;
- }
- // To clear the entire buffer would be safe, but this contributes to 1.68%
- // overhead under logging load. We are safe because we check counts, but
- // still need to clear null terminator
- buffer[n] = 0;
- struct ucred* cred = nullptr;
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
- while (cmsg != nullptr) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS) {
- cred = (struct ucred*)CMSG_DATA(cmsg);
- break;
- }
- cmsg = CMSG_NXTHDR(&hdr, cmsg);
- }
- if (cred == nullptr) {
- return;
- }
- if (cred->uid == AID_LOGD) {
- // ignore log messages we send to ourself.
- // Such log messages are often generated by libraries we depend on
- // which use standard Android logging.
- return;
- }
- android_log_header_t* header =
- reinterpret_cast<android_log_header_t*>(buffer);
- log_id_t logId = static_cast<log_id_t>(header->id);
- if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
- logId == LOG_ID_KERNEL) {
- return;
- }
- if (logId == LOG_ID_SECURITY) {
- if (!__android_log_security()) {
- return;
- }
- if (!clientCanWriteSecurityLog(cred->uid, cred->gid, cred->pid)) {
- return;
- }
- }
- char* msg = ((char*)buffer) + sizeof(android_log_header_t);
- n -= sizeof(android_log_header_t);
- // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
- // truncated message to the logs.
- logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
- ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
- }
- int LogListener::GetLogSocket() {
- static const char socketName[] = "logdw";
- int sock = android_get_control_socket(socketName);
- if (sock < 0) { // logd started up in init.sh
- sock = socket_local_server(
- socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
- int on = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
- return -1;
- }
- }
- return sock;
- }
复制代码 CommandListener
运行时库
write_to_log
system/logging/liblog/logger_write.cpp
调用LogdWrite
- #ifdef __ANDROID__
- static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
- int ret;
- struct timespec ts;
- if (log_id == LOG_ID_KERNEL) {
- return -EINVAL;
- }
- clock_gettime(CLOCK_REALTIME, &ts);
- if (log_id == LOG_ID_SECURITY) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
- ret = check_log_uid_permissions();
- if (ret < 0) {
- return ret;
- }
- if (!__android_log_security()) {
- /* If only we could reset downstream logd counter */
- return -EPERM;
- }
- } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
- }
- ret = LogdWrite(log_id, &ts, vec, nr);
- PmsgWrite(log_id, &ts, vec, nr);
- return ret;
- }
- #else
- static int write_to_log(log_id_t, struct iovec*, size_t) {
- // Non-Android text logs should go to __android_log_stderr_logger, not here.
- // Non-Android binary logs are always dropped.
- return 1;
- }
- #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需要重新毗连再次写入
- int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
- ssize_t ret;
- static const unsigned headerLength = 1;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- size_t i, payloadSize;
- static atomic_int dropped;
- LogdSocket& logd_socket =
- logId == LOG_ID_SECURITY ? LogdSocket::BlockingSocket() : LogdSocket::NonBlockingSocket();
- if (logd_socket.sock() < 0) {
- return -EBADF;
- }
- /* logd, after initialization and priv drop */
- if (getuid() == AID_LOGD) {
- /*
- * ignore log messages we send to ourself (logd).
- * Such log messages are often generated by libraries we depend on
- * which use standard Android logging.
- */
- return 0;
- }
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
- newVec[0].iov_base = (unsigned char*)&header;
- newVec[0].iov_len = sizeof(header);
- int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
- if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
- ANDROID_LOG_VERBOSE)) {
- android_log_event_int_t buffer;
- header.id = LOG_ID_EVENTS;
- buffer.header.tag = LIBLOG_LOG_TAG;
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = snapshot;
- newVec[headerLength].iov_base = &buffer;
- newVec[headerLength].iov_len = sizeof(buffer);
- ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
- }
- }
- header.id = logId;
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- break;
- }
- }
- // EAGAIN occurs if logd is overloaded, other errors indicate that something went wrong with
- // the connection, so we reset it and try again.
- ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, i));
- if (ret < 0 && errno != EAGAIN) {
- logd_socket.Reconnect();
- ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, i));
- }
- if (ret < 0) {
- ret = -errno;
- }
- if (ret > (ssize_t)sizeof(header)) {
- ret -= sizeof(header);
- } else if (ret < 0) {
- atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
- }
- return ret;
- }
复制代码 LogdSocket
sock、GetSocket、LogdConnect打开装备/dev/socket/logdw
- class LogdSocket {
- public:
- static LogdSocket& BlockingSocket() {
- static LogdSocket logd_socket(true);
- return logd_socket;
- }
- static LogdSocket& NonBlockingSocket() {
- static LogdSocket logd_socket(false);
- return logd_socket;
- }
- void Reconnect() { LogdConnect(sock_); }
- // Zygote uses this to clean up open FD's after fork() and before specialization. It is single
- // threaded at this point and therefore this function is explicitly not thread safe. It sets
- // sock_ to kUninitialized, so future logs will be safely initialized whenever they happen.
- void Close() {
- if (sock_ != kUninitialized) {
- close(sock_);
- }
- sock_ = kUninitialized;
- }
- int sock() {
- GetSocket();
- return sock_;
- }
- private:
- LogdSocket(bool blocking) : blocking_(blocking) {}
- // Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this
- // function is used to reconnect to logd without requiring a new socket.
- static void LogdConnect(int sock) {
- sockaddr_un un = {};
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/logdw");
- TEMP_FAILURE_RETRY(connect(sock, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)));
- }
- // sock_ should only be opened once. If we see that sock_ is uninitialized, we
- // create a new socket and attempt to exchange it into the atomic sock_. If the
- // compare/exchange was successful, then that will be the socket used for the duration of the
- // program, otherwise a different thread has already opened and written the socket to the atomic,
- // so close the new socket and return.
- void GetSocket() {
- if (sock_ != kUninitialized) {
- return;
- }
- int flags = SOCK_DGRAM | SOCK_CLOEXEC;
- if (!blocking_) {
- flags |= SOCK_NONBLOCK;
- }
- int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, flags, 0));
- if (new_socket < 0) {
- return;
- }
- LogdConnect(new_socket);
- int uninitialized_value = kUninitialized;
- if (!sock_.compare_exchange_strong(uninitialized_value, new_socket)) {
- close(new_socket);
- return;
- }
- }
- static const int kUninitialized = -1;
- atomic_int sock_ = kUninitialized;
- bool blocking_;
- };
复制代码 __android_log_print
system/logging/liblog/logger_write.cpp
- int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
- ErrnoRestorer errno_restorer;
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
- va_list ap;
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
- __android_log_message log_message = {
- sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
- }
复制代码 __android_log_write_log_message
- void __android_log_write_log_message(__android_log_message* log_message) {
- ErrnoRestorer errno_restorer;
- if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
- log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
- log_message->buffer_id != LOG_ID_CRASH) {
- return;
- }
- if (log_message->tag == nullptr) {
- log_message->tag = GetDefaultTag().c_str();
- }
- #if __BIONIC__
- if (log_message->priority == ANDROID_LOG_FATAL) {
- android_set_abort_message(log_message->message);
- }
- #endif
- get_logger_function()(log_message);
- }
复制代码 调用get_logger_function,get_file_logger_path判定是否有界说ro.log.file_logger.path指定log文件路径,如果没有则调用__android_log_logd_logger
- static __android_logger_function get_logger_function() {
- if (user_set_logger_function != nullptr) {
- return user_set_logger_function;
- }
- static __android_logger_function default_logger_function = []() {
- #if __ANDROID__
- if (get_file_logger_path() != nullptr) {
- return file_logger;
- } else {
- return __android_log_logd_logger;
- }
- #else
- return file_logger;
- #endif
- }();
- return default_logger_function;
- }
- #ifdef __ANDROID__
- static const char* get_file_logger_path() {
- static const char* file_logger_path = []() {
- static char path[PROP_VALUE_MAX] = {};
- if (__system_property_get("ro.log.file_logger.path", path) > 0) {
- return path;
- }
- return (char*)nullptr; // means file_logger should not be used
- }();
- return file_logger_path;
- }
- #endif
复制代码 __android_log_logd_logger将优先级、标签、内容存在数字元素vec[0]、vec[1]和vec[2],最后调用write_to_log
+1是因为标签和内容后面跟着’\0’,用来区分息争析
- void __android_log_logd_logger(const struct __android_log_message* log_message) {
- int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;
- struct iovec vec[3];
- vec[0].iov_base =
- const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
- vec[0].iov_len = 1;
- vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
- vec[1].iov_len = strlen(log_message->tag) + 1;
- vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
- vec[2].iov_len = strlen(log_message->message) + 1;
- write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
- }
复制代码 __android_log_buf_print
也是调用__android_log_write_log_message,同上
- int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...) {
- ErrnoRestorer errno_restorer;
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
- va_list ap;
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
- __android_log_message log_message = {
- sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
- }
复制代码 __android_log_bwrite/__android_log_btwrite/__android_log_bswrite
- __android_log_bwrite 的内容可由多个值组成
- __android_log_btwrite 的内容只有一个值,类型为参数type
- __android_log_btwrite 的内容为字符串
- int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
- struct iovec vec[2];
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
- return write_to_log(LOG_ID_EVENTS, vec, 2);
- }
- int __android_log_btwrite(int32_t tag, char type, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
- struct iovec vec[3];
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = (void*)payload;
- vec[2].iov_len = len;
- return write_to_log(LOG_ID_EVENTS, vec, 3);
- }
- int __android_log_bswrite(int32_t tag, const char* payload) {
- ErrnoRestorer errno_restorer;
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
- return write_to_log(LOG_ID_EVENTS, vec, 4);
- }
复制代码 # C/C++写入日志
system/logging/liblog/include/log/log.h(Android13)
属性LOG_NDEBUG限定Log的输出(为0时相关函数界说为空)
- #ifndef LOG_NDEBUG
- #ifdef NDEBUG
- #define LOG_NDEBUG 1
- #else
- #define LOG_NDEBUG 0
- #endif
- #endif
复制代码 属性LOG_TAG界说了当前编译单位的日志TAG,默认为空
- #ifndef LOG_TAG
- #define LOG_TAG NULL
- #endif
复制代码 ALOGV 、ALOGD 、ALOGI 、ALOGW 和ALOGE
/system/logging/liblog/include/log/log_main.h,ALOGV只有当LOG_NDEBUG为0时才有效
- #ifndef ALOGV
- #define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
- #if LOG_NDEBUG
- #define ALOGV(...) \
- do { \
- __FAKE_USE_VA_ARGS(__VA_ARGS__); \
- if (false) { \
- __ALOGV(__VA_ARGS__); \
- } \
- } while (false)
- #else
- #define ALOGV(...) __ALOGV(__VA_ARGS__)
- #endif
- #endif
- #ifndef ALOGD
- #define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
- #endif
- #ifndef ALOGI
- #define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
- #endif
- #ifndef ALOGW
- #define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
- #endif
- #ifndef ALOGE
- #define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
- #endif
复制代码 调用ALOG、LOG_PRI、android_printLog,最后调用运行时库的__android_log_print
- #ifndef ALOG
- #define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
- #endif
- #ifndef LOG_PRI
- #define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
- #endif
- #define android_printLog(prio, tag, ...) \
- __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
- #ifndef RLOGV
- #define __RLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, \
- __VA_ARGS__))
- #if LOG_NDEBUG
- #define RLOGV(...) \
- do { \
- if (0) { \
- __RLOGV(__VA_ARGS__); \
- } \
- } while (0)
- #else
- #define RLOGV(...) __RLOGV(__VA_ARGS__)
- #endif
- #endif
- #ifndef RLOGD
- #define RLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, \
- __VA_ARGS__))
- #endif
- #ifndef RLOGI
- #define RLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, \
- __VA_ARGS__))
- #endif
- #ifndef RLOGW
- #define RLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, \
- __VA_ARGS__))
- #endif
- #ifndef RLOGE
- #define RLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, \
- __VA_ARGS__))
- #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
- #ifndef SLOGV
- #define __SLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, \
- __VA_ARGS__))
- #if LOG_NDEBUG
- #define SLOGV(...) \
- do { \
- if (0) { \
- __SLOGV(__VA_ARGS__); \
- } \
- } while (0)
- #else
- #define SLOGV(...) __SLOGV(__VA_ARGS__)
- #endif
- #endif
- #ifndef SLOGD
- #define SLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, \
- __VA_ARGS__))
- #endif
- #ifndef SLOGI
- #define SLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, \
- __VA_ARGS__))
- #endif
- #ifndef SLOGW
- #define SLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, \
- __VA_ARGS__))
- #endif
- #ifndef SLOGE
- #define SLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, \
- __VA_ARGS__))
- #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
- #define android_btWriteLog(tag, type, payload, len) \
- __android_log_btwrite(tag, type, payload, len)
- typedef enum {
- /* Special markers for android_log_list_element type */
- EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
- EVENT_TYPE_UNKNOWN = '?', /* protocol error */
- /* must match with declaration in java/android/android/util/EventLog.java */
- EVENT_TYPE_INT = 0, /* int32_t */
- EVENT_TYPE_LONG = 1, /* int64_t */
- EVENT_TYPE_STRING = 2,
- EVENT_TYPE_LIST = 3,
- EVENT_TYPE_FLOAT = 4,
- } AndroidEventLogType;
- #ifndef LOG_EVENT_INT
- #define LOG_EVENT_INT(_tag, _value) \
- { \
- int intBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)); \
- }
- #endif
- #ifndef LOG_EVENT_LONG
- #define LOG_EVENT_LONG(_tag, _value) \
- { \
- long long longBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)); \
- }
- #endif
- #ifndef LOG_EVENT_FLOAT
- #define LOG_EVENT_FLOAT(_tag, _value) \
- { \
- float floatBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
- sizeof(floatBuf)); \
- }
- #endif
- #ifndef LOG_EVENT_STRING
- #define LOG_EVENT_STRING(_tag, _value) \
- (void)__android_log_bswrite(_tag, _value);
- #endif
复制代码 Java写入日志
android.util.Log
frameworks/base/core/java/android/util/Log.java
- public final class Log {
- ......
- /**
- * Priority constant for the println method; use Log.v.
- */
- public static final int VERBOSE = 2;
- /**
- * Priority constant for the println method; use Log.d.
- */
- public static final int DEBUG = 3;
- /**
- * Priority constant for the println method; use Log.i.
- */
- public static final int INFO = 4;
- /**
- * Priority constant for the println method; use Log.w.
- */
- public static final int WARN = 5;
- /**
- * Priority constant for the println method; use Log.e.
- */
- public static final int ERROR = 6;
- /**
- * Priority constant for the println method.
- */
- public static final int ASSERT = 7;
- ......
- public static int v(@Nullable String tag, @NonNull String msg) {
- return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
- }
- public static int d(@Nullable String tag, @NonNull String msg) {
- return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
- }
- public static int i(@Nullable String tag, @NonNull String msg) {
- return println_native(LOG_ID_MAIN, INFO, tag, msg);
- }
- public static int w(@Nullable String tag, @NonNull String msg) {
- return println_native(LOG_ID_MAIN, WARN, tag, msg);
- }
- public static int e(@Nullable String tag, @NonNull String msg) {
- return println_native(LOG_ID_MAIN, ERROR, tag, msg);
- }
- ......
- /** @hide */ public static final int LOG_ID_MAIN = 0;
- /** @hide */ public static final int LOG_ID_RADIO = 1;
- /** @hide */ public static final int LOG_ID_EVENTS = 2;
- /** @hide */ public static final int LOG_ID_SYSTEM = 3;
- /** @hide */ public static final int LOG_ID_CRASH = 4;
- ......
- }
复制代码 调用println_native,传入LOG_ID_MAIN
println_native
根据frameworks/base/core/jni/android_util_Log.cpp
- static const JNINativeMethod gMethods[] = {
- ......
- { "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
- ......
- };
复制代码 可知对应的调用函数,判定日志内容msgObj 是否为空,判定类型是否在[0, LOG_ID_MAX],最后调用运行时库的__android_log_buf_write写入log
- static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
- jint bufID, jint priority, jstring tagObj, jstring msgObj)
- {
- const char* tag = NULL;
- const char* msg = NULL;
- if (msgObj == NULL) {
- jniThrowNullPointerException(env, "println needs a message");
- return -1;
- }
- if (bufID < 0 || bufID >= LOG_ID_MAX) {
- jniThrowNullPointerException(env, "bad bufID");
- return -1;
- }
- if (tagObj != NULL)
- tag = env->GetStringUTFChars(tagObj, NULL);
- msg = env->GetStringUTFChars(msgObj, NULL);
- int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
- if (tag != NULL)
- env->ReleaseStringUTFChars(tagObj, tag);
- env->ReleaseStringUTFChars(msgObj, msg);
- return res;
- }
复制代码 android.util.Slog
frameworks/base/core/java/android/util/Slog.java
只可在系统内部使用,同上调用Log中的println_native传入LOG_ID_SYSTEM
- public final class Slog {
-
- ......
-
- @UnsupportedAppUsage
- public static int v(@Nullable String tag, @NonNull String msg) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg);
- }
-
- @UnsupportedAppUsage
- public static int d(@Nullable String tag, @NonNull String msg) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
- }
- @UnsupportedAppUsage
- public static int i(@Nullable String tag, @NonNull String msg) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg);
- }
- @UnsupportedAppUsage
- public static int w(@Nullable String tag, @NonNull String msg) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg);
- }
- @UnsupportedAppUsage
- public static int e(@Nullable String tag, @NonNull String msg) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg);
- }
- }
复制代码 android.util.Rlog
frameworks/base/core/java/android/util/Rlog.java
只可在系统内部使用,同上调用Log中的println_native传入LOG_ID_RADIO
- public final class Rlog {
-
- .....
- @UnsupportedAppUsage
- public static int v(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.VERBOSE, tag, msg);
- }
- @UnsupportedAppUsage
- public static int d(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.DEBUG, tag, msg);
- }
- @UnsupportedAppUsage
- public static int i(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.INFO, tag, msg);
- }
- @UnsupportedAppUsage
- public static int w(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.WARN, tag, msg);
- }
- @UnsupportedAppUsage
- public static int e(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.ERROR, tag, msg);
- }
- public static int println(int priority, String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, priority, tag, msg);
- }
- }
复制代码 android.util.EventLog
frameworks/base/core/java/android/util/EventLog.java,重载了5个版本的writeEvent方法,日志内容分别为int、long、float、string、list
- public class EventLog {
- ......
-
- private static final byte INT_TYPE = 0;
- private static final byte LONG_TYPE = 1;
- private static final byte STRING_TYPE = 2;
- private static final byte LIST_TYPE = 3;
- private static final byte FLOAT_TYPE = 4;
-
- public static native int writeEvent(int tag, int value);
- public static native int writeEvent(int tag, long value);
- public static native int writeEvent(int tag, float value);
- public static native int writeEvent(int tag, String str);
- public static native int writeEvent(int tag, Object... list);
-
- ......
- }
复制代码 writeEvent
根据frameworks/base/core/jni/android_util_EventLog.cpp
- static const JNINativeMethod gRegisterMethods[] = {
- /* name, signature, funcPtr */
- { "writeEvent", "(II)I", (void*) ELog::writeEventInteger },
- { "writeEvent", "(IJ)I", (void*) ELog::writeEventLong },
- { "writeEvent", "(IF)I", (void*) ELog::writeEventFloat },
- { "writeEvent", "(ILjava/lang/String;)I", (void*) ELog::writeEventString },
- { "writeEvent", "(I[Ljava/lang/Object;)I", (void*) ELog::writeEventArray },
- ......
- };
复制代码 可知调用
- static jint writeEventInteger(JNIEnv* env ATTRIBUTE_UNUSED, jobject clazz ATTRIBUTE_UNUSED,
- jint tag, jint value) {
- android_log_event_list ctx(tag);
- ctx << (int32_t)value;
- return ctx.write(LogID);
- }
- static jint writeEventLong(JNIEnv* env ATTRIBUTE_UNUSED, jobject clazz ATTRIBUTE_UNUSED,
- jint tag, jlong value) {
- android_log_event_list ctx(tag);
- ctx << (int64_t)value;
- return ctx.write(LogID);
- }
- static jint writeEventFloat(JNIEnv* env ATTRIBUTE_UNUSED, jobject clazz ATTRIBUTE_UNUSED,
- jint tag, jfloat value) {
- android_log_event_list ctx(tag);
- ctx << (float)value;
- return ctx.write(LogID);
- }
- static jint writeEventString(JNIEnv* env, jobject clazz ATTRIBUTE_UNUSED, jint tag,
- jstring value) {
- android_log_event_list ctx(tag);
- // Don't throw NPE -- I feel like it's sort of mean for a logging function
- // to be all crashy if you pass in NULL -- but make the NULL value explicit.
- ctx << (value != nullptr ? ScopedUtfChars(env, value).c_str() : "NULL");
- return ctx.write(LogID);
- }
- static jint writeEventArray(JNIEnv* env, jobject clazz ATTRIBUTE_UNUSED, jint tag,
- jobjectArray value) {
- android_log_event_list ctx(tag);
- if (value == nullptr) {
- ctx << "[NULL]";
- return ctx.write(LogID);
- }
- jsize copied = 0, num = env->GetArrayLength(value);
- for (; copied < num && copied < 255; ++copied) {
- if (ctx.status()) break;
- ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(value, copied));
- if (item == nullptr) {
- ctx << "NULL";
- } else if (env->IsInstanceOf(item.get(), gStringClass)) {
- ctx << ScopedUtfChars(env, (jstring) item.get()).c_str();
- } else if (env->IsInstanceOf(item.get(), gIntegerClass)) {
- ctx << (int32_t)env->GetIntField(item.get(), gIntegerValueID);
- } else if (env->IsInstanceOf(item.get(), gLongClass)) {
- ctx << (int64_t)env->GetLongField(item.get(), gLongValueID);
- } else if (env->IsInstanceOf(item.get(), gFloatClass)) {
- ctx << (float)env->GetFloatField(item.get(), gFloatValueID);
- } else {
- jniThrowException(env,
- "java/lang/IllegalArgumentException",
- "Invalid payload item type");
- return -1;
- }
- }
- return ctx.write(LogID);
- }
复制代码 log_event_list
system/logging/liblog/include/log/log_event_list.h
- int android_log_write_list(android_log_context ctx, log_id_t id);
- class android_log_event_list {
- ......
- int write(log_id_t id = LOG_ID_EVENTS) {
- /* facilitate -EBUSY retry */
- if ((ret == -EBUSY) || (ret > 0)) ret = 0;
- int retval = android_log_write_list(ctx, id);
- /* existing errors trump transmission errors */
- if (!ret) ret = retval;
- return ret;
- }
- ......
- }
复制代码 system/logging/liblog/log_event_list.cpp,根据id == LOG_ID_EVENTS调用__android_log_bwrite
- int android_log_write_list(android_log_context context, log_id_t id) {
- const char* msg;
- ssize_t len;
- if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (id != LOG_ID_STATS)) {
- return -EINVAL;
- }
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth) {
- return -EIO;
- }
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char*)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
- return (id == LOG_ID_EVENTS)
- ? __android_log_bwrite(context->tag, msg, len)
- : ((id == LOG_ID_STATS) ? __android_log_stats_bwrite(context->tag, msg, len)
- : __android_log_security_bwrite(context->tag, msg, len));
- }
复制代码 Logcat工具分析
基础数据布局
logcat
system/logging/logcat/logcat.cpp
- int main(int argc, char** argv) {
- Logcat logcat;
- return logcat.Run(argc, argv);
- }
复制代码 下面来分析其Run方法
命令参数
- int Logcat::Run(int argc, char** argv) {
- ......
- while (true) {
- ......
- switch (c) {
- ......
- case 'd':
- mode |= ANDROID_LOG_NONBLOCK;
- break;
- case 't':
- got_t = true;
- mode |= ANDROID_LOG_NONBLOCK;
- FALLTHROUGH_INTENDED;
- case 'T':
- if (strspn(optarg, "0123456789") != strlen(optarg)) {
- char* cp = parseTime(tail_time, optarg);
- if (!cp) {
- error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
- }
- if (*cp) {
- char ch = *cp;
- *cp = '\0';
- fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
- cp + 1);
- *cp = ch;
- }
- } else {
- if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
- fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
- tail_lines = 1;
- }
- }
- break;
- case 'D':
- print_dividers_ = true;
- break;
- case 'e':
- regex_.reset(new std::regex(optarg));
- break;
- case 'm': {
- if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
- error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
- optarg);
- }
- } break;
- case 'g':
- if (!optarg) {
- getLogSize = true;
- break;
- }
- FALLTHROUGH_INTENDED;
- case 'G': {
- if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
- error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
- }
- } break;
- case 'p':
- if (!optarg) {
- getPruneList = true;
- break;
- }
- FALLTHROUGH_INTENDED;
- case 'P':
- setPruneList = optarg;
- break;
- case 'b':
- for (const auto& buffer : Split(optarg, delimiters)) {
- if (buffer == "default") {
- id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
- } else if (buffer == "all") {
- id_mask = -1;
- } else {
- log_id_t log_id = android_name_to_log_id(buffer.c_str());
- if (log_id >= LOG_ID_MAX) {
- error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
- buffer.c_str());
- }
- if (log_id == LOG_ID_SECURITY) {
- security_buffer_selected = true;
- }
- id_mask |= (1 << log_id);
- }
- }
- break;
- case 'B':
- print_binary_ = 1;
- break;
- case 'f':
- if ((tail_time == log_time::EPOCH) && !tail_lines) {
- tail_time = lastLogTime(optarg);
- }
- // redirect output to a file
- output_file_name_ = optarg;
- break;
- case 'r':
- if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
- }
- break;
- case 'n':
- if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
- }
- break;
- case 'v':
- for (const auto& arg : Split(optarg, delimiters)) {
- int err = SetLogFormat(arg.c_str());
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
- }
- if (err) hasSetLogFormat = true;
- }
- break;
- case 'S':
- printStatistics = true;
- break;
- case ':':
- error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
- break;
- case 'h':
- show_help();
- return EXIT_SUCCESS;
- case '?':
- error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind]);
- break;
- default:
- error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
- }
- }
复制代码
- 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
- int Logcat::SetLogFormat(const char* format_string) {
- AndroidLogPrintFormat format = android_log_formatFromString(format_string);
- // invalid string?
- if (format == FORMAT_OFF) return -1;
- return android_log_setPrintFormat(logformat_.get(), format);
- }
复制代码 system/logging/liblog/logprint.cpp
- AndroidLogPrintFormat android_log_formatFromString(const char* formatString) {
- /* clang-format off */
- if (!strcmp(formatString, "brief")) return FORMAT_BRIEF;
- if (!strcmp(formatString, "process")) return FORMAT_PROCESS;
- if (!strcmp(formatString, "tag")) return FORMAT_TAG;
- if (!strcmp(formatString, "thread")) return FORMAT_THREAD;
- if (!strcmp(formatString, "raw")) return FORMAT_RAW;
- if (!strcmp(formatString, "time")) return FORMAT_TIME;
- if (!strcmp(formatString, "threadtime")) return FORMAT_THREADTIME;
- if (!strcmp(formatString, "long")) return FORMAT_LONG;
- if (!strcmp(formatString, "color")) return FORMAT_MODIFIER_COLOR;
- if (!strcmp(formatString, "colour")) return FORMAT_MODIFIER_COLOR;
- if (!strcmp(formatString, "usec")) return FORMAT_MODIFIER_TIME_USEC;
- if (!strcmp(formatString, "nsec")) return FORMAT_MODIFIER_TIME_NSEC;
- if (!strcmp(formatString, "printable")) return FORMAT_MODIFIER_PRINTABLE;
- if (!strcmp(formatString, "year")) return FORMAT_MODIFIER_YEAR;
- if (!strcmp(formatString, "zone")) return FORMAT_MODIFIER_ZONE;
- if (!strcmp(formatString, "epoch")) return FORMAT_MODIFIER_EPOCH;
- if (!strcmp(formatString, "monotonic")) return FORMAT_MODIFIER_MONOTONIC;
- if (!strcmp(formatString, "uid")) return FORMAT_MODIFIER_UID;
- if (!strcmp(formatString, "descriptive")) return FORMAT_MODIFIER_DESCRIPT;
- /* clang-format on */
- #if !defined(__MINGW32__)
- // Check whether the format string is actually a time zone. If tzname[0]
- // is the empty string, that's tzset() signalling that it doesn't know
- // the requested timezone.
- TzSetter tz(formatString);
- if (!*tzname[0]) {
- tz.Reset();
- } else {
- // We keep the new time zone as a side effect!
- return FORMAT_MODIFIER_ZONE;
- }
- #endif
- return FORMAT_OFF;
- }
- int android_log_setPrintFormat(AndroidLogFormat* p_format, AndroidLogPrintFormat format) {
- switch (format) {
- case FORMAT_MODIFIER_COLOR:
- p_format->colored_output = true;
- return 0;
- case FORMAT_MODIFIER_TIME_USEC:
- p_format->usec_time_output = true;
- return 0;
- case FORMAT_MODIFIER_TIME_NSEC:
- p_format->nsec_time_output = true;
- return 0;
- case FORMAT_MODIFIER_PRINTABLE:
- p_format->printable_output = true;
- return 0;
- case FORMAT_MODIFIER_YEAR:
- p_format->year_output = true;
- return 0;
- case FORMAT_MODIFIER_ZONE:
- p_format->zone_output = !p_format->zone_output;
- return 0;
- case FORMAT_MODIFIER_EPOCH:
- p_format->epoch_output = true;
- return 0;
- case FORMAT_MODIFIER_MONOTONIC:
- p_format->monotonic_output = true;
- return 0;
- case FORMAT_MODIFIER_UID:
- p_format->uid_output = true;
- return 0;
- case FORMAT_MODIFIER_DESCRIPT:
- p_format->descriptive_output = true;
- descriptive_output = true;
- return 0;
- default:
- break;
- }
- p_format->format = format;
- return 1;
- }
复制代码 日志的格式为<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
- // If no buffers are specified, default to using these buffers.
- if (id_mask == 0) {
- id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
- (1 << LOG_ID_KERNEL);
- }
复制代码 未设置选项v时,将情况变量ANDROID_PRINTF_LOG的值设置为当前格式,若无则设置为threadtime
- if (!hasSetLogFormat) {
- const char* logFormat = getenv("ANDROID_PRINTF_LOG");
- if (!!logFormat) {
- for (const auto& arg : Split(logFormat, delimiters)) {
- int err = SetLogFormat(arg.c_str());
- // environment should not cause crash of logcat
- if (err < 0) {
- fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
- }
- if (err > 0) hasSetLogFormat = true;
- }
- }
- if (!hasSetLogFormat) {
- SetLogFormat("threadtime");
- }
- }
复制代码
- forceFilters.size()不为0,表示通过选项Q让logcat读取/proc/cmdline中的过滤器
- argc == optind表示命令没有其他参数,读取ANDROID_LOG_TAGS的值作为过滤器
- 将命令参数设置为过滤器,格式为 tag:priority,如 *:E
- if (forceFilters.size()) {
- int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
- }
- } else if (argc == optind) {
- // Add from environment variable
- const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
- if (!!env_tags_orig) {
- int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
- }
- }
- } else {
- // Add from commandline
- for (int i = optind ; i < argc ; i++) {
- int err = android_log_addFilterString(logformat_.get(), argv[i]);
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
- }
- }
- }
复制代码 通过android_log_addFilterString设置过滤器,filterString大概以空格、tab或逗号分割
- int android_log_addFilterString(AndroidLogFormat* p_format, const char* filterString) {
- char* filterStringCopy = strdup(filterString);
- char* p_cur = filterStringCopy;
- char* p_ret;
- int err;
- /* Yes, I'm using strsep */
- while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
- /* ignore whitespace-only entries */
- if (p_ret[0] != '\0') {
- err = android_log_addFilterRule(p_format, p_ret);
- if (err < 0) {
- goto error;
- }
- }
- }
- free(filterStringCopy);
- return 0;
- error:
- free(filterStringCopy);
- return -1;
- }
复制代码 通过android_log_addFilterRule添加解析过滤器,将冒号后面的字符转为android_LogPriority,通过tagName和pri创建FilterInfo
- int android_log_addFilterRule(AndroidLogFormat* p_format, const char* filterExpression) {
- size_t tagNameLength;
- android_LogPriority pri = ANDROID_LOG_DEFAULT;
- tagNameLength = strcspn(filterExpression, ":");
- if (tagNameLength == 0) {
- goto error;
- }
- if (filterExpression[tagNameLength] == ':') {
- pri = filterCharToPri(filterExpression[tagNameLength + 1]);
- if (pri == ANDROID_LOG_UNKNOWN) {
- goto error;
- }
- }
- if (0 == strncmp("*", filterExpression, tagNameLength)) {
- /*
- * This filter expression refers to the global filter
- * The default level for this is DEBUG if the priority
- * is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_DEBUG;
- }
- p_format->global_pri = pri;
- } else {
- /*
- * for filter expressions that don't refer to the global
- * filter, the default is verbose if the priority is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_VERBOSE;
- }
- char* tagName;
- /*
- * Presently HAVE_STRNDUP is never defined, so the second case is always taken
- * Darwin doesn't have strndup, everything else does
- */
- #ifdef HAVE_STRNDUP
- tagName = strndup(filterExpression, tagNameLength);
- #else
- /* a few extra bytes copied... */
- tagName = strdup(filterExpression);
- tagName[tagNameLength] = '\0';
- #endif /*HAVE_STRNDUP*/
- FilterInfo* p_fi = filterinfo_new(tagName, pri);
- free(tagName);
- p_fi->p_next = p_format->filters;
- p_format->filters = p_fi;
- }
- return 0;
- error:
- return -1;
- }
- static android_LogPriority filterCharToPri(char c) {
- android_LogPriority pri;
- c = tolower(c);
- if (c >= '0' && c <= '9') {
- if (c >= ('0' + ANDROID_LOG_SILENT)) {
- pri = ANDROID_LOG_VERBOSE;
- } else {
- pri = (android_LogPriority)(c - '0');
- }
- } else if (c == 'v') {
- pri = ANDROID_LOG_VERBOSE;
- } else if (c == 'd') {
- pri = ANDROID_LOG_DEBUG;
- } else if (c == 'i') {
- pri = ANDROID_LOG_INFO;
- } else if (c == 'w') {
- pri = ANDROID_LOG_WARN;
- } else if (c == 'e') {
- pri = ANDROID_LOG_ERROR;
- } else if (c == 'f') {
- pri = ANDROID_LOG_FATAL;
- } else if (c == 's') {
- pri = ANDROID_LOG_SILENT;
- } else if (c == '*') {
- pri = ANDROID_LOG_DEFAULT;
- } else {
- pri = ANDROID_LOG_UNKNOWN;
- }
- return pri;
- }
复制代码 若通过选项f指定输出文件,通过max_rotated_logs_设置个数,格式为xxx.1/…/xxx.n
- if (output_file_name_) {
- if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
- error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
- }
- if (clearLog || setId) {
- int max_rotation_count_digits =
- max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
- for (int i = max_rotated_logs_; i >= 0; --i) {
- std::string file;
- if (!i) {
- file = output_file_name_;
- } else {
- file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
- }
- int err = unlink(file.c_str());
- if (err < 0 && errno != ENOENT) {
- fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
- strerror(errno));
- }
- }
- }
- if (clearLog) {
- return EXIT_SUCCESS;
- }
- }
复制代码 根据id打开log装备
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- if (!(id_mask & (1 << i))) continue;
- const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
- auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
- if (logger == nullptr) {
- ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
- continue;
- }
- ......
复制代码 判定输出是二进制调用WriteFully,否则调用ProcessBuffer
- while (!max_count_ || print_count_ < max_count_) {
- ......
- if (print_binary_) {
- WriteFully(&log_msg, log_msg.len());
- } else {
- ProcessBuffer(&log_msg);
- }
- if (blocking && output_file_ == stdout) fflush(stdout);
- }
- return EXIT_SUCCESS;
- }
复制代码
- 若日志类型是Event,调用android_log_processBinaryLogBuffer,否则调用android_log_processLogBuffer,他们都会将buf转为AndroidLogEntry用于输出
- android_log_shouldPrintLine 判定tag和pri是否符合设置的过滤条件
- 当日志超出大小时,调用RotateLogs建立新文件
- void Logcat::ProcessBuffer(struct log_msg* buf) {
- AndroidLogEntry entry;
- char binaryMsgBuf[1024] __attribute__((__uninitialized__));
- bool is_binary =
- buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
- int err;
- if (is_binary) {
- if (!event_tag_map_ && !has_opened_event_tag_map_) {
- event_tag_map_.reset(android_openEventTagMap(nullptr));
- has_opened_event_tag_map_ = true;
- }
- // This causes entry to point to binaryMsgBuf!
- err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
- binaryMsgBuf, sizeof(binaryMsgBuf));
- // printf(">>> pri=%d len=%d msg='%s'\n",
- // entry.priority, entry.messageLen, entry.message);
- } else {
- err = android_log_processLogBuffer(&buf->entry, &entry);
- }
- if (err < 0 && !debug_) return;
- if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
- entry.priority)) {
- bool match = !regex_ ||
- std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
- print_count_ += match;
- if (match || print_it_anyway_) {
- PrintDividers(buf->id(), print_dividers_);
- out_byte_count_ += android_log_printLogLine(logformat_.get(), output_file_, &entry);
- }
- }
- if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
- RotateLogs();
- }
- }
复制代码 android_log_printLogLine时输出的最后一个步骤,调用android_log_formatLogLine格式化要输出的日志,调用fwrite把日志输出到文件形貌符fd所形貌的目标文件中
- size_t android_log_printLogLine(AndroidLogFormat* p_format, FILE* fp,
- const AndroidLogEntry* entry) {
- char buf[4096] __attribute__((__uninitialized__));
- size_t line_length;
- char* line = android_log_formatLogLine(p_format, buf, sizeof(buf), entry, &line_length);
- if (!line) {
- fprintf(stderr, "android_log_formatLogLine failed\n");
- exit(1);
- }
- size_t bytesWritten = fwrite(line, 1, line_length, fp);
- if (bytesWritten != line_length) {
- perror("fwrite failed");
- exit(1);
- }
- if (line != buf) free(line);
- return bytesWritten;
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |