欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

AndroidRLogd原理

时间:2023-06-30
文章目录

0、相关文件目录1、ALOGD写log流程

1.1 ALOGD打印log,传入可变参数1.2 logdw socket写log1.3 pmsg写入 /dev/pmsg0 2、logcat读取流程

2.1 logcat调用liblog流程2.2 logformat_ 申请和释放2.3 logger_list申请和释放2.4 android_logger_open打开设备log2.5 android_logger_list_read获取buffer2.6 android_log_printLogLine写log文件 3、logd流程

3.1 logd进程启动3.2 logd-reinit进程和 re-init线程3.3 LogListener监测socket logdw3.4 LogReader监测socket logdr3.5 logBuffer流程3.6 socket logd 交互3.7 kernel log流程3.8 selinux log流程3.9 logd各线程整理 4、整体流程图 0、相关文件目录

### liblog write//log_main logger_write定义log宏,组装可变内容write_to_logsystemcoreliblogincludeloglog_main.hsystemcorelibloglogger_write.cpp//写内容到pmsg /dev/pmsg0systemcoreliblogpmsg_writer.cpp//写内容到logdw /dev/socket/logdwsystemcorelibloglogd_writer.cpp### logcat readsystemcorelibloglogger_read.cppsystemcorelogcatlogcat.cppsystemcorelibloglogd_reader.cpp### logdsystemcorelogdmain.cpp//LogListener监听socket logdw把log写到logBuffersystemcorelogdLogListener.hsystemcorelogdLogListener.cpp//SocketListener socket的监听类systemcorelibsysutilssrcSocketListener.cppsystemcorelibsysutilsincludesysutilsSocketListener.h//记录每个使用LOG的pid客户端systemcorelibsysutilssrcSocketClient.cppsystemcorelogdFlushCommand.cpp//LogBuffer类systemcorelogdLogBuffer.cpp//LogReader监听logdr类systemcorelogdLogReader.cpp

1、ALOGD写log流程 1.1 ALOGD打印log,传入可变参数

@systemcoreliblogincludeloglog_main.h

//ALOGD调用到ALOG#ifndef ALOGD#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))#endif//最终使用到android_printLog#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__)

__android_log_print把log内容拼装到__android_log_message,然后调用写

@systemcorelibloglogger_write.cppint __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; char buf[LOG_BUF_SIZE]; va_start(ap, fmt); vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); va_end(ap); //拼凑log_message,然后写 __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;}void __android_log_write_log_message(__android_log_message* log_message) { ErrnoRestorer errno_restorer; //过滤buffer id 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; } //设置tag if (log_message->tag == nullptr) { log_message->tag = GetDefaultTag().c_str(); }//如果是fatal,abort_message#if __BIONIC__ if (log_message->priority == ANDROID_LOG_FATAL) { android_set_abort_message(log_message->message); }#endif //调用logger_function透传message logger_function(log_message);}//logger_function是函数__android_log_logd_logger#ifdef __ANDROID__static __android_logger_function logger_function = __android_log_logd_logger;#elsestatic __android_logger_function logger_function = __android_log_stderr_logger;#endif//__android_log_logd_logger继续转message到数组,最后write_to_logvoid __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;//io vector: iovec io数组申请3个,分别设置优先级,tag,message struct iovec vec[3]; vec[0].iov_base = const_cast(reinterpret_cast(&log_message->priority)); vec[0].iov_len = 1; vec[1].iov_base = const_cast(static_cast(log_message->tag)); vec[1].iov_len = strlen(log_message->tag) + 1; vec[2].iov_base = const_cast(static_cast(log_message->message)); vec[2].iov_len = strlen(log_message->message) + 1;//写log,参数分别是强转的log_id_t, 消息数组,和数组长度 write_to_log(static_cast(buffer_id), vec, 3);}

__android_log_message定义入下

//message包含 struct_size大小sizeof(__android_log_message)//buffer_id:这里是LOG_ID_MAIN,表示使用main log//priority:enum android_LogPriority 优先级越高,值越大//tag :设置的log tag//file:文件名不知道干啥 alogd是nullptr空//line;这里是0//message: message buf,这里是可变参数的内容struct __android_log_message { size_t struct_size; int32_t buffer_id; int32_t priority; const char* tag; const char* file; uint32_t line; const char* message; };

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; //invalid无效错误 } //获取时间 clock_gettime(android_log_clockid(), &ts); //安全需要检测长度,权限,安全等等,ALOGD不是此id 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()) { 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;}

1.2 logdw socket写log

//这里就是每个客户端写的socket logdw

@systemcorelibloglogd_writer.cppstatic void LogdConnect() { sockaddr_un un = {}; un.sun_family = AF_UNIX; strcpy(un.sun_path, "/dev/socket/logdw"); TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast(&un), sizeof(sockaddr_un)));}//GetSocket()只获取一次,如果第一次打开socket(/dev/socket/logdw)static void GetSocket() { if (logd_socket != 0) { return; } int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)); if (new_socket <= 0) { return; } int uninitialized_value = 0; if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) { close(new_socket); return; } LogdConnect();}

LogdWrite函数把tid 时间 vec组装成新的newvec,通过writev写到socket logdw

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; static atomic_int droppedSecurity; //获取 socket logdw GetSocket();//获取失败返回 if (logd_socket <= 0) { return -EBADF; }//logd本身不能用 if (getuid() == AID_LOGD) { return 0; } //log头包含id tid 和时间 header.tid = gettid(); header.realtime.tv_sec = ts->tv_sec; header.realtime.tv_nsec = ts->tv_nsec; //把header放入io数组 newVec[0].iov_base = (unsigned char*)&header; newVec[0].iov_len = sizeof(header); //LOG_ID_SECURITY int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed); if (snapshot) { android_log_event_int_t buffer;... //writev是循环写数组内容到fd,这里是把数组写到socket里面logd_socket // The write below could be lost, but will never block. // 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, newVec, i));//TEMP_FAILURE_RETRY定义writev函数while一直写 if (ret < 0 && errno != EAGAIN) { LogdConnect(); //如果失败是AGAIN,会重连socket在试一次 ret = TEMP_FAILURE_RETRY(writev(logd_socket, 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); if (logId == LOG_ID_SECURITY) { atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed); } } return ret;}

1.3 pmsg写入 /dev/pmsg0

log内容,分别写入socket logdw和pmsg /dev/pmsg0文件

@androidsystemcoreliblogpmsg_writer.cppstatic void GetPmsgFd() { if (pmsg_fd != 0) { return; } int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRonLY | O_CLOEXEC)); if (new_fd <= 0) { return; } int uninitialized_value = 0; if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) { close(new_fd); return; }}void PmsgClose() { if (pmsg_fd > 0) { close(pmsg_fd); } pmsg_fd = 0;}int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) { static const unsigned headerLength = 2; struct iovec newVec[nr + headerLength]; android_log_header_t header; android_pmsg_log_header_t pmsgHeader; size_t i, payloadSize; ssize_t ret;//userdebug就不走 if (!__android_log_is_debuggable()) { if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) { return -1; } if (logId == LOG_ID_EVENTS) { if (vec[0].iov_len < 4) { return -EINVAL; } if (SNET_EVENT_LOG_TAG != *static_cast(vec[0].iov_base)) { return -EPERM; } } }//获取fd /dev/pmsg0 GetPmsgFd(); if (pmsg_fd <= 0) { return -EBADF; } pmsgHeader.magic = LOGGER_MAGIC; pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header); pmsgHeader.uid = getuid(); pmsgHeader.pid = getpid(); header.id = logId; header.tid = gettid(); header.realtime.tv_sec = ts->tv_sec; header.realtime.tv_nsec = ts->tv_nsec; newVec[0].iov_base = (unsigned char*)&pmsgHeader; newVec[0].iov_len = sizeof(pmsgHeader); newVec[1].iov_base = (unsigned char*)&header; newVec[1].iov_len = sizeof(header); 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; } payloadSize = LOGGER_ENTRY_MAX_PAYLOAD; break; } } pmsgHeader.len += payloadSize;//把msg写到pmsg_fd ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i)); if (ret < 0) { ret = errno ? -errno : -ENOTCONN; } if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) { ret -= sizeof(header) - sizeof(pmsgHeader); } return ret;}static inline const char* strnrchr(const char* buf, size_t len, char c) { const char* cp = buf + len; while ((--cp > buf) && (*cp != c)) ; if (cp <= buf) { return buf + len; } return cp;}ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename, const char* buf, size_t len) { size_t length, packet_len; const char* tag; char *cp, *slash; struct timespec ts; struct iovec vec[3]; if ((logId == LOG_ID_KERNEL) || (logId == LOG_ID_EVENTS) || (logId == LOG_ID_SECURITY) || ((unsigned)logId >= 32)) { return -EINVAL; } clock_gettime(android_log_clockid(), &ts); cp = strdup(filename); if (!cp) { return -ENOMEM; } tag = cp; slash = strrchr(cp, '/'); if (slash) { *slash = ':'; slash = strrchr(cp, '/'); if (slash) { tag = slash + 1; } } length = strlen(tag) + 1; packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length; vec[0].iov_base = &prio; vec[0].iov_len = sizeof(char); vec[1].iov_base = (unsigned char*)tag; vec[1].iov_len = length; for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) { ssize_t ret; size_t transfer; if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) { len -= length; break; } transfer = length; if (transfer > packet_len) { transfer = strnrchr(buf, packet_len - 1, 'n') - buf; if ((transfer < length) && (buf[transfer] == 'n')) { ++transfer; } } vec[2].iov_base = (unsigned char*)buf; vec[2].iov_len = transfer; ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0])); if (ret <= 0) { free(cp); return ret ? ret : (len - length); } length -= transfer; buf += transfer; } free(cp); return len;}

2、logcat读取流程 2.1 logcat调用liblog流程

logcat客户端精简流程入下

@logcat.cppint Logcat::Run() { //reset文件fd output_fd_.reset(); //设置格式threadtime SetLogFormat("threadtime"); int mode = ANDROID_LOG_RDONLY; size_t tail_lines = 0; size_t pid = 0; unsigned id_mask = -1; //int err = android_log_addFilterString(logformat_.get(), env_tags_orig); //logger_list初始化 std::unique_ptr logger_list{ nullptr, &android_logger_list_free}; logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid)); //android_logger_open打开 logid的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(i)); auto logger = android_logger_open(logger_list.get(), static_cast(i)); if (logger == nullptr) { ALOGE("android_logger_open error! "); continue; } } int exit_reason = LOGCAT_EXIT_EOF; while (1) { struct log_msg log_msg; //android_logger_list_read读取buffer到log_msg int ret = android_logger_list_read(logger_list.get(), &log_msg); if (!ret) { ALOGE("android_logger_list_read ret failed, Unexpected EOF! look into using the -G option to increase log buffer sizes"); break; } if (ret < 0) {... } //处理log_msg,支持打印到中途或者写到文件fd ProcessBuffer(&log_msg); } return exit_reason;}

void Logcat::ProcessBuffer(struct log_msg* buf) { int bytesWritten = 0; int err; AndroidLogEntry entry; char binaryMsgBuf[1024]; bool is_binary = buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY; 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; } 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 { //处理buffer err = android_log_processLogBuffer(&buf->entry, &entry); } if (err < 0) return; //打印分界线内容 -----main格式 PrintDividers(buf->id(), false); //是否需要打印 if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(), entry.priority)) { //android_log_printLogLine写buffer内容到fd,如果是fd是终端就打印到终端 bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry); if (bytesWritten < 0) { ALOGE("bytesWritten < 0"); error(EXIT_FAILURE, 0, "Output error."); } } //已经写的内容大小 out_byte_count_ += bytesWritten; //大小超过限额就需要把log存到另外文件 if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) { ALOGE("RotateLogs < 0"); RotateLogs(); }}

LOGCAT客户端的流程大概入下

1、logcat先解析参数可以使用logcat --help查看2、初始化资源包括output_fd, logger_list3、android_logger_open打开各个logid4、android_logger_list_read读取log到log_msg5、android_log_printLogLine打印log

2.2 logformat_ 申请和释放

AndroidLogFormat_t和AndroidLogPrintFormat定义

struct AndroidLogFormat_t { android_LogPriority global_pri; FilterInfo* filters; AndroidLogPrintFormat format; bool colored_output; bool usec_time_output; bool nsec_time_output; bool printable_output; bool year_output; bool zone_output; bool epoch_output; bool monotonic_output; bool uid_output; bool descriptive_output;};typedef enum { FORMAT_OFF = 0, FORMAT_BRIEF, FORMAT_PROCESS, FORMAT_TAG, FORMAT_THREAD, FORMAT_RAW, FORMAT_TIME, FORMAT_THREADTIME, FORMAT_LONG, FORMAT_MODIFIER_COLOR, FORMAT_MODIFIER_TIME_USEC, FORMAT_MODIFIER_PRINTABLE, FORMAT_MODIFIER_YEAR, FORMAT_MODIFIER_ZONE, FORMAT_MODIFIER_EPOCH, FORMAT_MODIFIER_MONOTONIC, FORMAT_MODIFIER_UID, FORMAT_MODIFIER_DEscript, FORMAT_MODIFIER_TIME_NSEC, } AndroidLogPrintFormat;

@logcat.hpp // Used for all options android::base::unique_fd output_fd_{dup(STDOUT_FILENO)}; std::unique_ptr logformat_{ android_log_format_new(), &android_log_format_free};

log格式包含优先级,输出,过滤器等

AndroidLogFormat* android_log_format_new() { AndroidLogFormat* p_ret; p_ret = static_cast(calloc(1, sizeof(AndroidLogFormat))); p_ret->global_pri = ANDROID_LOG_VERBOSE; p_ret->format = FORMAT_BRIEF; p_ret->colored_output = false; p_ret->usec_time_output = false; p_ret->nsec_time_output = false; p_ret->printable_output = false; p_ret->year_output = false; p_ret->zone_output = false; p_ret->epoch_output = false;#ifdef __ANDROID__ p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;#else p_ret->monotonic_output = false;#endif p_ret->uid_output = false; p_ret->descriptive_output = false; descriptive_output = false; return p_ret;}

释放AndroidLogFormat,里面包含filter过滤

void android_log_format_free(AndroidLogFormat* p_format) { FilterInfo *p_info, *p_info_old; p_info = p_format->filters; while (p_info != NULL) { p_info_old = p_info; p_info = p_info->p_next; free(p_info_old); } free(p_format); while (!list_empty(&convertHead)) { struct listnode* node = list_head(&convertHead); list_remove(node); LOG_ALWAYS_FATAL_IF(node == list_head(&convertHead), "corrupted list"); free(node); }}

logcat设置格式

@logcat.cppint 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);}

直接设置format threadtime
SetLogFormat(“threadtime”)

int android_log_setPrintFormat(AndroidLogFormat* p_format, AndroidLogPrintFormat format) { switch (format) {... } p_format->format = format; return 1;}

2.3 logger_list申请和释放

logcat申请logger_list android_logger_list_alloc,自动释放 android_logger_list_free

@logcat.cppstd::unique_ptr logger_list{ nullptr, &android_logger_list_free};logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));

logger_list定义

@systemcorelibloglogger.hstruct logger_list { atomic_int fd;//原子操作int,多线程不用锁确保安全 int mode;//mode unsigned int tail;//尾巴 log_time start;//time pid_t pid;//pid uint32_t log_mask;//mask};

@systemcorelibloglogger_read.cppstruct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) { return android_logger_list_alloc_internal(mode, tail, log_time(0, 0), pid);}static struct logger_list* android_logger_list_alloc_internal(int mode, unsigned int tail, log_time start, pid_t pid) { //calloc申请一个logger_list auto* logger_list = static_cast(calloc(1, sizeof(struct logger_list))); if (!logger_list) { return nullptr; } //赋值初始化logger_list logger_list->mode = mode; logger_list->start = start; logger_list->tail = tail; logger_list->pid = pid; return logger_list;}//关闭log,主要是关闭fd,然后释放logger_list对象,防止泄露void android_logger_list_free(struct logger_list* logger_list) { if (logger_list == NULL) { return; }#ifdef __ANDROID__ if (logger_list->mode & ANDROID_LOG_PSTORE) { PmsgClose(logger_list); } else { LogdClose(logger_list); }#endif free(logger_list);}

2.4 android_logger_open打开设备log

@logcat.cpp 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(i)); auto logger = android_logger_open(logger_list.get(), static_cast(i)); if (logger == nullptr) { ALOGE("android_logger_open error! "); continue; } }

android_logger_open 把需要打印的logid添加进list,同时返回logger是使用logd还是pmsg

struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) { if (!logger_list || (logId >= LOG_ID_MAX)) { return nullptr; } logger_list->log_mask |= 1 << logId; //把打开的logID添加进logger_list,mask就可以打开多个log uintptr_t logger = logId; //logger 正常不是pstore mode时,值是LOGGER_LOGD logger |= (logger_list->mode & ANDROID_LOG_PSTORE) ? LOGGER_PMSG : LOGGER_LOGD; return reinterpret_cast(logger);}

2.5 android_logger_list_read获取buffer

struct log_msg定义,包含buffer, entry

@systemcoreliblogincludeloglog_read.hstruct log_msg { union { unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1]; struct logger_entry entry; } __attribute__((aligned(4)));#ifdef __cplusplus bool operator==(const log_msg& T) const { return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec); } bool operator!=(const log_msg& T) const { return !(*this == T); } bool operator<(const log_msg& T) const { return (entry.sec < T.entry.sec) || ((entry.sec == T.entry.sec) && (entry.nsec < T.entry.nsec)); } bool operator>=(const log_msg& T) const { return !(*this < T); } bool operator>(const log_msg& T) const { return (entry.sec > T.entry.sec) || ((entry.sec == T.entry.sec) && (entry.nsec > T.entry.nsec)); } bool operator<=(const log_msg& T) const { return !(*this > T); } uint64_t nsec() const { return static_cast(entry.sec) * NS_PER_SEC + entry.nsec; } log_id_t id() { return static_cast(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(buf) + hdr_size; } unsigned int len() { return entry.hdr_size + entry.len; }#endif};

entry包含长度size,uid pid tid等.
每一个entry都包含pid tid等,就可以用这个来过滤当前buffer了

struct logger_entry { uint16_t len; uint16_t hdr_size; int32_t pid; uint32_t tid; uint32_t sec; uint32_t nsec; uint32_t lid; uint32_t uid; };

@logger_read.cpp//读取log到log_msg,logger_list包含需要读取的logidint android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) { if (logger_list == nullptr || logger_list->log_mask == 0) { return -EINVAL; } int ret = 0;//这里使用LogdRead#ifdef __ANDROID__ if (logger_list->mode & ANDROID_LOG_PSTORE) { ret = PmsgRead(logger_list, log_msg); } else { ret = LogdRead(logger_list, log_msg); }#endif if (ret <= 0) { return ret; }//检测ret结果省略...//末尾设置 log_msg->buf[log_msg->entry.len + log_msg->entry.hdr_size] = ''; return ret;}

@logd_reader.cppint LogdRead(struct logger_list* logger_list, struct log_msg* log_msg) {//open会让打开的/dev/socket/loddr赋值给logger_list,然后write socket int ret = logdOpen(logger_list); if (ret < 0) { return ret; }//recv读取socket logdr的内容到log_msg里面 ret = TEMP_FAILURE_RETRY(recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0)); if ((logger_list->mode & ANDROID_LOG_NONBLOCK) && ret == 0) { return -EAGAIN;//判断返回值 } if (ret == -1) { return -errno; } return ret;}static int logdOpen(struct logger_list* logger_list) { char buffer[256], *cp, c; int ret, remaining, sock; //查看fd > 0,证明已经打开过socket,就return sock = atomic_load(&logger_list->fd); if (sock > 0) { return sock; } //连接/dev/socket/logdr,把fd给sock sock = socket_local_client("logdr", SOCK_SEQPACKET); if (sock <= 0) { if ((sock == -1) && errno) { return -errno; } return sock; } strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream"); cp = buffer + strlen(buffer); strcpy(cp, " lids"); cp += 5; c = '='; remaining = sizeof(buffer) - (cp - buffer); for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) { if ((1 << log_id) & logger_list->log_mask) { ret = snprintf(cp, remaining, "%c%zu", c, log_id); ret = MIN(ret, remaining); remaining -= ret; cp += ret; c = ','; } } if (logger_list->tail) { ret = snprintf(cp, remaining, " tail=%u", logger_list->tail); ret = MIN(ret, remaining); remaining -= ret; cp += ret; } if (logger_list->start.tv_sec || logger_list->start.tv_nsec) { if (logger_list->mode & ANDROID_LOG_WRAP) { // ToDo: alternate API to allow timeout to be adjusted. ret = snprintf(cp, remaining, " timeout=%u", ANDROID_LOG_WRAP_DEFAULT_TIMEOUT); ret = MIN(ret, remaining); remaining -= ret; cp += ret; } ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32, logger_list->start.tv_sec, logger_list->start.tv_nsec); ret = MIN(ret, remaining); remaining -= ret; cp += ret; } if (logger_list->pid) { ret = snprintf(cp, remaining, " pid=%u", logger_list->pid); ret = MIN(ret, remaining); cp += ret; }//这个写socket不知道干啥的,最好加log看一下,这个是啥 ret = TEMP_FAILURE_RETRY(write(sock, buffer, cp - buffer)); int write_errno = errno; if (ret <= 0) { close(sock); if (ret == -1) { return -write_errno; } if (ret == 0) { return -EIO; } return ret; }//交换了fd 和sock,把socket值送给logger_list ret = atomic_exchange(&logger_list->fd, sock); if ((ret > 0) && (ret != sock)) { close(ret); } return sock;}

2.6 android_log_printLogLine写log文件

联合体成员变量公用其实内存,因此recv到log_msg时,会把值同时对两个赋值。此时entry端会先赋值,buffer比较大,需要得到message真正在log_msg中的位置

struct logger_entry { uint16_t len; uint16_t hdr_size; int32_t pid; uint32_t tid; uint32_t sec; uint32_t nsec; uint32_t lid; uint32_t uid; };struct log_msg { union {//联合体成员变量公用其实内存 unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1]; struct logger_entry entry; } __attribute__((aligned(4)));//4字节对齐...};

转到AndroidLogEntry,需要找到各个变量在log_msg中的起始位置

typedef struct AndroidLogEntry_t { time_t tv_sec; long tv_nsec; android_LogPriority priority; int32_t uid; int32_t pid; int32_t tid; const char* tag; size_t tagLen; size_t messageLen; const char* message;} AndroidLogEntry;

android_log_processLogBuffer函数把log_msg内容,通过偏移得到log真正的内容message,同时还得到tag,优先级

log_msg内容入下

|--struct logger_entry entry --| pro | tag | msgbuffer | msg msgstart msgend

int android_log_processLogBuffer(struct logger_entry* buf, AndroidLogEntry* entry) { entry->message = NULL; entry->messageLen = 0; entry->tv_sec = buf->sec; entry->tv_nsec = buf->nsec; entry->uid = -1; entry->pid = buf->pid; entry->tid = buf->tid; if (buf->len < 3) { fprintf(stderr, "+++ LOG: entry too smalln"); return -1; } int msgStart = -1; int msgEnd = -1; int i; if (buf->hdr_size < sizeof(logger_entry)) { fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entryn"); return -1; } //msg表示buf偏移hdr_size(sizeof(struct logger_entry))个size char* msg = reinterpret_cast(buf) + buf->hdr_size; entry->uid = buf->uid;//通过有效长度len,和来找msgstart 和end//第一个是因为前面是tag//msgstart 和end中间才是真正log内容 for (i = 1; i < buf->len; i++) { if (msg[i] == '') { if (msgStart == -1) { msgStart = i + 1; } else { msgEnd = i; break; } } } if (msgStart == -1) { for (i = 1; i < buf->len; i++) { if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) { msg[i] = ''; msgStart = i + 1; break; } } if (msgStart == -1) { msgStart = buf->len - 1; } } if (msgEnd == -1) { msgEnd = buf->len - 1; msg[msgEnd] = ''; }//msg0是优先级 entry->priority = static_cast(msg[0]); entry->tag = msg + 1;//偏移1是tag entry->tagLen = msgStart - 1; //msg长度 entry->message = msg + msgStart;//真正log内容的开始位置 entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);//msg长度 return 0;}

int android_log_printLogLine(AndroidLogFormat* p_format, int fd, const AndroidLogEntry* entry) { int ret; char defaultBuffer[512]; char* outBuffer = NULL; size_t totalLen;//通过entry message,把buffer考到outBUffer outBuffer = android_log_formatLogLine(p_format, defaultBuffer, sizeof(defaultBuffer), entry, &totalLen); if (!outBuffer) return -1;//写outBuffer到文件,如果文件是终端,就打印终端 do { ret = write(fd, outBuffer, totalLen); } while (ret < 0 && errno == EINTR); if (ret < 0) { fprintf(stderr, "+++ LOG: write failed (errno=%d)n", errno); ret = 0; goto done; } if (((size_t)ret) < totalLen) { fprintf(stderr, "+++ LOG: write partial (%d of %d)n", ret, (int)totalLen); goto done; }done: if (outBuffer != defaultBuffer) { free(outBuffer); } return ret;}

3、logd流程 3.1 logd进程启动

logd通过rc启动,需要链接库liblog和liblogd

cc_binary { name: "logd", init_rc: ["logd.rc"], srcs: ["main.cpp"], static_libs: [ "liblog", "liblogd", ], shared_libs: [ "libsysutils", "libcutils", "libbase", "libpackagelistparser", "libprocessgroup", "libcap", ], cflags: ["-Werror"],}

@logd.rcservice logd /system/bin/logd //定义需要的3个socket,已经对应权限 socket logd stream 0666 logd logd socket logdr seqpacket 0666 logd logd socket logdw dgram+passcred 0222 logd logd file /proc/kmsg r file /dev/kmsg w //文件是干啥的? user logd //用户是logd group logd system package_info readproc capabilities SYSLOG AUDIT_ConTROL priority 10 //优先级,有用? writepid /dev/cpuset/system-background/tasksservice logd-reinit /system/bin/logd --reinit oneshot disabled user logd group logd writepid /dev/cpuset/system-background/tasks# Limit SELinux denial generation to 5/secondservice logd-auditctl /system/bin/auditctl -r 5 oneshot disabled user logd group logd capabilities AUDIT_ConTROLon fs//write write /dev/event-log-tags "# content owned by logd"//改文件权限,这样其他组没有访问event-log-tags的权限 chown logd logd /dev/event-log-tags chmod 0644 /dev/event-log-tagson property:sys.boot_completed=1 start logd-auditctl

1 设置时区timezone环境变量为UTC2 获取kernel 节点fd /dev/kmsg3 启动re-init线程4 创建logBuffer, 创建LogReader并且监听logdr,创建LogListener监听logdw,创建CommandListener监听socket logd5 LogAudit并监听selinux ,创建LogKlog监听kernel

@main.cppint main(int argc, char* argv[]) { // 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); //设置timezone为utc,害怕时间突变 // issue reinit command、KISS argument parsing. if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) { return issueReinit(); }//kernel log节点文件,获取kmsg文件fd fdDmesg static const char dev_kmsg[] = "/dev/kmsg"; fdDmesg = android_get_control_file(dev_kmsg); if (fdDmesg < 0) { fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRonLY | O_CLOEXEC)); } int fdPmesg = -1; //感觉是false,没有此属性 bool klogd = __android_logger_property_get_bool( "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); if (klogd) { 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) android::prdebug("Failed to open %sn", proc_kmsg); }//selinux权限 bool auditd = __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE); if (DropPrivs(klogd, auditd) != 0) { return EXIT_FAILURE; } // Reinit Thread sem_init(&reinit, 0, 0); pthread_attr_t attr; if (!pthread_attr_init(&attr)) { struct sched_param param; memset(¶m, 0, sizeof(param)); pthread_attr_setschedparam(&attr, ¶m); pthread_attr_setschedpolicy(&attr, SCHED_BATCH); //创建reinit_thread if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) { pthread_t thread; reinit_running = true; if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) { reinit_running = false; } } pthread_attr_destroy(&attr); } // 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. LastLogTimes* times = new LastLogTimes(); // LogBuffer is the object which is responsible for holding all // log entries.//创建logBuffer logBuf = new LogBuffer(times); signal(SIGHUP, reinit_signal_handler); //启动统计 if (__android_logger_property_get_bool( "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) { logBuf->enableStatistics(); } // LogReader listens on /dev/socket/logdr、When a client // connects, log entries in the LogBuffer are written to the client.//logReader监听logdr socket,客户端写的时候需要知道连接内容 LogReader* reader = new LogReader(logBuf); 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 LogListener* swl = new LogListener(logBuf, reader); // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value if (swl->startListener(600)) { return EXIT_FAILURE; } // Command listener listens on /dev/socket/logd for incoming logd // administrative commands.//CommandListener初始化监听logd socket CommandListener* cl = new CommandListener(logBuf, reader, swl); if (cl->startListener()) { return EXIT_FAILURE; } // 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.//selinux LogAudit* al = nullptr; if (auditd) { al = new LogAudit(logBuf, reader, __android_logger_property_get_bool( "ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE) ? fdDmesg : -1); }//kernel log每个都会传入静态logBuf对象 LogKlog* kl = nullptr; if (klogd) { kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr); }//读取dmesg readDmesg(al, kl); // failure is an option ..、messages are in dmesg (required by standard)//LogKlog和LogAudit都启动listener if (kl && kl->startListener()) { delete kl; } if (al && al->startListener()) { delete al; } TEMP_FAILURE_RETRY(pause()); return EXIT_SUCCESS;}

3.2 logd-reinit进程和 re-init线程

logd.rc中启动logd-reinit 如下:

service logd-reinit /system/bin/logd --reinit oneshot disabled user logd group logd writepid /dev/cpuset/system-background/tasks

启动logd-reinit的服务,主要工作是重新初始化logd的LogBuffer,在上面的启动脚本中,配置为oneshot,即开机只执行一次。

通过上面logd的初始化,可以看到,logd启动后,创建了一个线程reinit_thread_start(),当logd-reinit 传入参数 reinit后,进行功能执行。logd-reinit两个步骤:

如果reinit启动后,并且/deg/kmsg打开成功,把 logd.daemon: renit写入kmsg

重新初始化各个log buffer的大小,以及其他参数的初始化,但不会重新生成LogBuffer对象

3.3 LogListener监测socket logdw

LogListener继承sysutils库中的SocketListener,需要重写监听到socket变化后的回调接口onDataAvailable

@systemcorelogdLogListener.h#include #include "LogReader.h"class LogListener : public SocketListener { LogBuffer* logbuf; LogReader* reader; public: LogListener(LogBuffer* buf, LogReader* reader); protected: virtual bool onDataAvailable(SocketClient* cli); private://获取socket static int getLogSocket();};

LogListener构造器就会获取socket logdw

//SocketListener传入socket etLogSocket()//buffer 和reader也赋值到 logbuf, readerLogListener::LogListener(LogBuffer* buf, LogReader* reader) : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {}//获取到socketint 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;}

startListener开始监听,创建监听线程threadStart,调用runListener,此时创建fdspoll,mClients 是客户端连接socket内容。然后调用poll轮询vector fds数组,看是否变化,

@systemcorelibsysutilssrcSocketListener.cpp//backlog默认4,LogListenner默认600int SocketListener::startListener(int backlog) { //mSock是fd,不走这两个if if (!mSocketName && mSock == -1) { SLOGE("Failed to start unbound listener"); errno = EINVAL; return -1; } else if (mSocketName) { if ((mSock = android_get_control_socket(mSocketName)) < 0) { SLOGE("Obtaining file descriptor socket '%s' failed: %s", mSocketName, strerror(errno)); return -1; } SLOGV("got mSock = %d for %s", mSock, mSocketName); fcntl(mSock, F_SETFD, FD_CLOEXEC); } if (mListen && listen(mSock, backlog) < 0) { SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen) //保存键值对mSockfd和SocketClient* mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum); //piple创建 if (pipe2(mCtrlPipe, O_CLOEXEC)) { SLOGE("pipe failed (%s)", strerror(errno)); return -1; } //开启线程,防止阻塞主线程 if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) { SLOGE("pthread_create (%s)", strerror(errno)); return -1; } return 0;}//线程运行对象类SocketListener函数方法runListenervoid *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast(obj); me->runListener(); pthread_exit(nullptr);//正常不会退出 return nullptr;}//运行监听void SocketListener::runListener() { while (true) { //fd数组 std::vector fds; //上锁,防止释放等操作冲突 pthread_mutex_lock(&mClientsLock); //reserve对vector扩容,避免内存重新分配。客户端size + 2,客户端size是使用logd的进程数 fds.reserve(2 + mClients.size()); //数组push一个piple fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN}); if (mListen) fds.push_back({.fd = mSock, .events = POLLIN}); for (auto pair : mClients) { // NB: calling out to an other object with mClientsLock held (safe) const int fd = pair.second->getSocket(); if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first); fds.push_back({.fd = fd, .events = POLLIN});//在push client的socket fd } pthread_mutex_unlock(&mClientsLock); SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName); //轮询遍历fds fd变化 int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1)); if (rc < 0) { SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen); sleep(1); continue; } if (fds[0].revents & (POLLIN | POLLERR)) { char c = CtrlPipe_Shutdown; TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1)); if (c == CtrlPipe_Shutdown) { break; } continue; } //accept接收到客户到新的写log请求 if (mListen && (fds[1].revents & (POLLIN | POLLERR))) { int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC)); if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } //客户端的文件描述符c,传入SocketClietn pthread_mutex_lock(&mClientsLock); mClients[c] = new SocketClient(c, true, mUseCmdNum); pthread_mutex_unlock(&mClientsLock); } // Add all active clients to the pending list first, so we can release // the lock before invoking the callbacks. std::vector pending; pthread_mutex_lock(&mClientsLock); const int size = fds.size(); for (int i = mListen ? 2 : 1; i < size; ++i) { const struct pollfd& p = fds[i]; if (p.revents & (POLLIN | POLLERR)) { auto it = mClients.find(p.fd); if (it == mClients.end()) { SLOGE("fd vanished: %d", p.fd); continue; } SocketClient* c = it->second; pending.push_back(c); c->incRef();//增加计数 } } pthread_mutex_unlock(&mClientsLock); //循环遍历有变化的SocketClient,然后回调数组,传入数据的socket //这里是socket Logdw写,会有很多客户端 for (SocketClient* c : pending) { // Process it, if false is returned, remove from the map SLOGV("processing fd %d", c->getSocket()); if (!onDataAvailable(c)) {//回调数据 release(c, false);//数据回调失败,比如socket断开之类,就移除掉socket,释放ref引用 } c->decRef();//减计数 } }}bool SocketListener::release(SocketClient* c, bool wakeup) { bool ret = false; if (mListen && c) { SLOGV("going to zap %d for %s", c->getSocket(), mSocketName); pthread_mutex_lock(&mClientsLock); ret = (mClients.erase(c->getSocket()) != 0);//client移除掉,unordered_map效率比普通map更高 pthread_mutex_unlock(&mClientsLock); if (ret) { ret = c->decRef();//减掉ref计数 if (wakeup) { char b = CtrlPipe_Wakeup; TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1)); } } } return ret;}

onDataAvailable是收到socket变化的回调,通过组装iovec,读取socket内容,得到文件头id tid time 和内容msg.然后写到logbuffer最后通知有log写入

@LogListener.cppbool LogListener::onDataAvailable(SocketClient* cli) { static bool name_set; if (!name_set) { prctl(PR_SET_NAME, "logd.writer"); //设置线程名 name_set = true; } // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received 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, }; //获取client socket int socket = cli->getSocket(); // To clear the entire buffer is secure/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 // memset(buffer, 0, sizeof(buffer)); ssize_t n = recvmsg(socket, &hdr, 0);//socket内容写到hdr中,会把log内容放到iov里面,此时值就是buffer if (n <= (ssize_t)(sizeof(android_log_header_t))) { return false; } 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 false; } 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 false; } android_log_header_t* header = reinterpret_cast(buffer); log_id_t logId = static_cast(header->id); if ( logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) { return false; } if ((logId == LOG_ID_SECURITY) && (!__android_log_security() || !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) { return false; } //buffer 偏移头的大小,就是msg内容 //android_log_header_t内容只有id tid realtime,和ALOGD像scoket logdw内容一样,都是iovec格式 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. //写log到logbuf中 int res = logbuf->log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg, ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX); if (res > 0) {//写buffer成功后,通知新log reader->notifyNewLog(static_cast(1 << logId)); } return true;}

通知logReader有消息,然后刷新命令flushCommand

@androidsystemcorelogdLogReader.cpp// When we are notified a new log entry is available, inform// listening sockets who are watching this entry's log id.void LogReader::notifyNewLog(log_mask_t logMask) { FlushCommand command(*this, logMask); runOnEachSocket(&command);}

void SocketListener::runonEachSocket(SocketClientCommand *command) { for (SocketClient* c : snapshotClients()) { command->runSocketCommand(c); c->decRef(); }}

3.4 LogReader监测socket logdr

LogReader和LogListenner差不多,都继承SocketListener,重写onDataAvailable回调

class LogReader : public SocketListener { LogBuffer& mLogbuf; public: explicit LogReader(LogBuffer* logbuf); void notifyNewLog(log_mask_t logMask); LogBuffer& logbuf(void) const { return mLogbuf; } protected: virtual bool onDataAvailable(SocketClient* cli); private: static int getLogSocket(); void doSocketDelete(SocketClient* cli);};

@LogReader.cpp// Note returning false will release the SocketClient instance.// logdr改变,传入改变的client,可以知道客户端的socket fd(logdr),以及进程pid// onDataAvailable数据改变回调,由于logd是服务端,只能接收客户端写logdr socket回到,也就是只会接收logcat打开,写命令的那一条数据,正常只有一次bool LogReader::onDataAvailable(SocketClient* cli) { static bool name_set; if (!name_set) { prctl(PR_SET_NAME, "logd.reader");//设置线程 name_set = true; } char buffer[255];//读取socket内容,看起来就是logcat连接时发送的那一串tail start timeout等,好赋值给logd int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1); if (len <= 0) { doSocketDelete(cli); return false; } buffer[len] = ''; // Clients are only allowed to send one command, disconnect them if they // send another. LogTimeEntry::wrlock(); for (const auto& entry : mLogbuf.mTimes) { if (entry->mClient == cli) { entry->release_Locked(); LogTimeEntry::unlock(); return false; } } LogTimeEntry::unlock(); unsigned long tail = 0; static const char _tail[] = " tail="; char* cp = strstr(buffer, _tail); if (cp) { tail = atol(cp + sizeof(_tail) - 1); } log_time start(log_time::EPOCH); static const char _start[] = " start="; cp = strstr(buffer, _start); if (cp) { // Parse errors will result in current time start.strptime(cp + sizeof(_start) - 1, "%s.%q"); } uint64_t timeout = 0; static const char _timeout[] = " timeout="; cp = strstr(buffer, _timeout); if (cp) { timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC + log_time(CLOCK_REALTIME).nsec(); } unsigned int logMask = -1; static const char _logIds[] = " lids="; cp = strstr(buffer, _logIds); if (cp) { logMask = 0; cp += sizeof(_logIds) - 1; while (*cp && *cp != '') { int val = 0; while (isdigit(*cp)) { val = val * 10 + *cp - '0'; ++cp; } logMask |= 1 << val; if (*cp != ',') { break; } ++cp; } } pid_t pid = 0; static const char _pid[] = " pid="; cp = strstr(buffer, _pid); if (cp) { pid = atol(cp + sizeof(_pid) - 1); } bool nonBlock = false; if (!fastcmp (buffer, "dumpAndClose", 12)) { // Allow writer to get some cycles, and wait for pending notifications sched_yield(); LogTimeEntry::wrlock(); LogTimeEntry::unlock(); sched_yield(); nonBlock = true; } log_time sequence = start; // // This somewhat expensive data validation operation is required // for non-blocking, with timeout、 The incoming timestamp must be // in range of the list, if not, return immediately、 This is // used to prevent us from from getting stuck in timeout processing // with an invalid time. // // Find if time is really present in the logs, monotonic or real, implicit // conversion from monotonic or real as necessary to perform the check. // Exit in the check loop ASAP as you find a transition from older to // newer, but use the last entry found to ensure overlap. // if (nonBlock && (sequence != log_time::EPOCH) && timeout) { class LogFindStart { // A lambda by another name private: const pid_t mPid; const unsigned mLogMask; bool mStartTimeSet; log_time mStart; log_time& mSequence; log_time mLast; bool mIsMonotonic; public: LogFindStart(pid_t pid, unsigned logMask, log_time& sequence, bool isMonotonic) : mPid(pid), mLogMask(logMask), mStartTimeSet(false), mStart(sequence), mSequence(sequence), mLast(sequence), mIsMonotonic(isMonotonic) { } static int callback(const LogBufferElement* element, void* obj) { LogFindStart* me = reinterpret_cast(obj); if ((!me->mPid || (me->mPid == element->getPid())) && (me->mLogMask & (1 << element->getLogId()))) { log_time real = element->getRealTime(); if (me->mStart == real) { me->mSequence = real; me->mStartTimeSet = true; return -1; } else if (!me->mIsMonotonic || android::isMonotonic(real)) { if (me->mStart < real) { me->mSequence = me->mLast; me->mStartTimeSet = true; return -1; } me->mLast = real; } else { me->mLast = real; } } return false; } bool found() { return mStartTimeSet; } } logFindStart(pid, logMask, sequence, logbuf().isMonotonic() && android::isMonotonic(start)); logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli), FlushCommand::hasSecurityLogs(cli), logFindStart.callback, &logFindStart); if (!logFindStart.found()) { doSocketDelete(cli); return false; } } android::prdebug( "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d " "start=%" PRIu64 "ns timeout=%" PRIu64 "nsn", cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, logMask, (int)pid, sequence.nsec(), timeout); if (sequence == log_time::EPOCH) { timeout = 0; } LogTimeEntry::wrlock(); auto entry = std::make_unique( *this, cli, nonBlock, tail, logMask, pid, sequence, timeout); //start 开始读当前客户端pid的log if (!entry->startReader_Locked()) { LogTimeEntry::unlock(); return false; } // release client and entry reference counts once done cli->incRef(); mLogbuf.mTimes.emplace_front(std::move(entry)); //设置socket超时 // Set acceptable upper limit to wait for slow reader processing b/27242723 struct timeval t = { LOGD_SNDTIMEO, 0 }; setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t, sizeof(t)); LogTimeEntry::unlock(); return true;}

正在的写logdr地方

systemcorelogdLogTimes.cpp//启动线程threadStartbool LogTimeEntry::startReader_Locked() { pthread_attr_t attr; if (!pthread_attr_init(&attr)) { if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) { if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart, this)) { pthread_attr_destroy(&attr); return true; } } pthread_attr_destroy(&attr); } return false;}//logd.reader.per线程真正启动void* LogTimeEntry::threadStart(void* obj) { prctl(PR_SET_NAME, "logd.reader.per");//set name LogTimeEntry* me = reinterpret_cast(obj); SocketClient* client = me->mClient; LogBuffer& logbuf = me->mReader.logbuf(); bool privileged = FlushCommand::hasReadLogs(client); bool security = FlushCommand::hasSecurityLogs(client); me->leadingDropped = true; wrlock(); log_time start = me->mStart; while (!me->mRelease) { if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) { if (pthread_cond_timedwait(&me->threadTriggeredCondition, ×Lock, &me->mTimeout) == ETIMEDOUT) { me->mTimeout.tv_sec = 0; me->mTimeout.tv_nsec = 0; } if (me->mRelease) { break; } } unlock(); if (me->mTail) { logbuf.flushTo(client, start, nullptr, privileged, security, FilterFirstPass, me); me->leadingDropped = true; } start = logbuf.flushTo(client, start, me->mLastTid, privileged, security, FilterSecondPass, me); wrlock(); if (start == LogBufferElement::FLUSH_ERROR) { break; } me->mStart = start + log_time(0, 1); if (me->mNonBlock || me->mRelease) { break; } me->cleanSkip_Locked(); if (!me->mTimeout.tv_sec && !me->mTimeout.tv_nsec) { pthread_cond_wait(&me->threadTriggeredCondition, ×Lock); } } LogReader& reader = me->mReader; reader.release(client); client->decRef(); LastLogTimes& times = reader.logbuf().mTimes; auto it = std::find_if(times.begin(), times.end(), [&me](const auto& other) { return other.get() == me; }); if (it != times.end()) { times.erase(it); } unlock(); return nullptr;}

3.5 logBuffer流程 3.6 socket logd 交互 3.7 kernel log流程 3.8 selinux log流程 3.9 logd各线程整理

top -H -p 271(logd pid) 查看logd线程信息入下

Threads: 8 total, 0 running, 8 sleeping, 0 stopped, 0 zombie Mem: 3390188K total, 2663680K used, 726508K free, 19460096 buffers Swap: 2097148K total, 0 used, 2097148K free, 733840K cached800%cpu 10%user 1%nice 42%sys 744%idle 0%iow 2%irq 1%sirq 0%host TID USER PR NI VIRT RES SHR S[%CPU] %MEM TIME+ THREAD PROCESS 2947 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:04.40 logd.reader.per logd //LogTimes.cpp里面的线程 283 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:00.95 logd.klogd logd //kernel线程 284 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:00.02 logd.auditd logd //avc selinux线程 277 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:08.91 logd.writer logd // LogListener线程 socket logdw 278 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:00.00 logd.control logd //CommandListener.cpp logd控制线程 socket logd 274 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:00.00 logd.daemon logd //reinit_thread_start线程 prctl(PR_SET_NAME, "logd.daemon"); 276 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:00.00 logd.reader logd //logReader线程 271 logd 30 10 12G 6.7M 2.6M S 0.0 0.2 0:00.02 logd logd //主线程

debuggerd -b 271 命令查看271进程trace

msmnile_gvmq:/ # debuggerd -b 271----- pid 271 at 2022-01-18 21:35:49 -----Cmd line: /system/bin/logdABI: 'arm64'"logd" sysTid=271 #00 pc 000000000009bad8 /apex/com.android.runtime/lib64/bionic/libc.so (__rt_sigsuspend+8) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000005c96c /apex/com.android.runtime/lib64/bionic/libc.so (sigsuspend64+60) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #02 pc 000000000005a050 /apex/com.android.runtime/lib64/bionic/libc.so (pause+36) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #03 pc 0000000000009800 /system/bin/logd (main+1496) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4) #04 pc 00000000000499fc /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: 8d0a10271eef02de6c33b788fec2db37)"logd.daemon" sysTid=274 #00 pc 000000000004b4cc /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000004f0b4 /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #02 pc 000000000005bea4 /apex/com.android.runtime/lib64/bionic/libc.so (sem_wait+116) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #03 pc 0000000000009934 /system/bin/logd (reinit_thread_start(void*)+96) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4) #04 pc 00000000000afecc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #05 pc 0000000000050408 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)"logd.reader" sysTid=276 #00 pc 000000000009c1b4 /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000005a3c0 /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #02 pc 000000000000570c /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #03 pc 00000000000053c4 /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #04 pc 00000000000afecc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #05 pc 0000000000050408 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)"logd.writer" sysTid=277 #00 pc 000000000009c1b4 /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000005a3c0 /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #02 pc 000000000000570c /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #03 pc 00000000000053c4 /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #04 pc 00000000000afecc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #05 pc 0000000000050408 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)"logd.control" sysTid=278 #00 pc 000000000009c1b4 /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000005a3c0 /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #02 pc 000000000000570c /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #03 pc 00000000000053c4 /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #04 pc 00000000000afecc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #05 pc 0000000000050408 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)"logd.klogd" sysTid=283 #00 pc 000000000009ae74 /apex/com.android.runtime/lib64/bionic/libc.so (read+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000001cd0c /system/bin/logd (LogKlog::onDataAvailable(SocketClient*)+156) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4) #02 pc 0000000000005aa8 /system/lib64/libsysutils.so (SocketListener::runListener()+1336) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #03 pc 00000000000053c4 /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #04 pc 00000000000afecc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #05 pc 0000000000050408 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)"logd.auditd" sysTid=284 #00 pc 000000000009c1b4 /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000005a3c0 /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #02 pc 000000000000570c /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #03 pc 00000000000053c4 /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e) #04 pc 00000000000afecc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #05 pc 0000000000050408 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)"logd.reader.per" sysTid=2947 #00 pc 000000000004b4cc /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #01 pc 000000000004f0b4 /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #02 pc 00000000000af2b4 /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_wait+60) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #03 pc 0000000000010508 /system/bin/logd (LogTimeEntry::threadStart(void*)+684) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4) #04 pc 00000000000afecc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37) #05 pc 0000000000050408 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)----- end 271 -----

主线程使用stack命令解析是在pause,等待信号 对应代码TEMP_FAILURE_RETRY(pause());

----- pid 271 at 2022-01-18 21:35:49 -----Cmd line: /system/bin/logdABI: 'arm64'Stack Trace: RELADDR FUNCTION FILE:LINE 000000000009bad8 __rt_sigsuspend+8 out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:1704 000000000005c96c sigsuspend64+60 bionic/libc/bionic/signal.cpp:270 000000000005a050 pause+36 bionic/libc/bionic/pause.cpp:34 0000000000009800 main+1496 system/core/logd/main.cpp:436 00000000000499fc __libc_init+108 bionic/libc/bionic/libc_init_dynamic.cpp:151

logd.reader线程SocketListener::threadStart在poll消息

"logd.reader" sysTid=276Stack Trace: RELADDR FUNCTION FILE:LINE 000000000009c1b4 __ppoll+4 out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:2385 000000000005a3c0 poll+92 bionic/libc/bionic/poll.cpp:48 v--------------> poll(pollfd*, unsigned int pass_object_size1, int) bionic/libc/include/bits/fortify/poll.h:54 000000000000570c SocketListener::runListener()+412 system/core/libsysutils/src/SocketListener.cpp:168 00000000000053c4 SocketListener::threadStart(void*)+8 system/core/libsysutils/src/SocketListener.cpp:146 00000000000afecc __pthread_start(void*)+64 bionic/libc/bionic/pthread_create.cpp:347 0000000000050408 __start_thread+64

logd.writer也是在poll线程

"logd.writer" sysTid=277Stack Trace: RELADDR FUNCTION FILE:LINE 000000000009c1b4 __ppoll+4 out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:2385 000000000005a3c0 poll+92 bionic/libc/bionic/poll.cpp:48 v--------------> poll(pollfd*, unsigned int pass_object_size1, int) bionic/libc/include/bits/fortify/poll.h:54 000000000000570c SocketListener::runListener()+412 system/core/libsysutils/src/SocketListener.cpp:168 00000000000053c4 SocketListener::threadStart(void*)+8 system/core/libsysutils/src/SocketListener.cpp:146 00000000000afecc __pthread_start(void*)+64 bionic/libc/bionic/pthread_create.cpp:347 0000000000050408 __start_thread+64 bionic/libc/bionic/clone.cpp:53

logd.klogd线程收到了数据回调onDataAvailable,正在读取数据

"logd.klogd" sysTid=283Stack Trace: RELADDR FUNCTION FILE:LINE 000000000009ae74 read+4 out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:461 v--------------> read(int, void*, unsigned long pass_object_size0) bionic/libc/include/bits/fortify/unistd.h:159 000000000001cd0c LogKlog::onDataAvailable(SocketClient*)+156 system/core/logd/LogKlog.cpp:235 0000000000005aa8 SocketListener::runListener()+1336 system/core/libsysutils/src/SocketListener.cpp:218 00000000000053c4 SocketListener::threadStart(void*)+8 system/core/libsysutils/src/SocketListener.cpp:146 00000000000afecc __pthread_start(void*)+64 bionic/libc/bionic/pthread_create.cpp:347 0000000000050408 __start_thread+64 bionic/libc/bionic/clone.cpp:53

4、整体流程图

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。