文章目录

  • 0. 相关文件目录
  • 1. ALOGD写log流程
    • 1.1 ALOGD打印log,传入可变参数
    • 1.2 logdw socket写log
    • 1.3 pmsg写入 /dev/pmsg0
  • 2. logcat读取流程
    • 2.1 logcat调用liblog流程
    • 2.2 logformat_ 申请和释放
    • 2.3 logger_list申请和释放
    • 2.4 android_logger_open打开设备log
    • 2.5 android_logger_list_read获取buffer
    • 2.6 android_log_printLogLine写log文件
  • 3. logd流程
    • 3.1 logd进程启动
    • 3.2 logd-reinit进程和 re-init线程
    • 3.3 LogListener监测socket logdw
    • 3.4 LogReader监测socket logdr
    • 3.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_log
system\core\liblog\include\log\log_main.h
system\core\liblog\logger_write.cpp
//写内容到pmsg /dev/pmsg0
system\core\liblog\pmsg_writer.cpp
//写内容到logdw /dev/socket/logdw
system\core\liblog\logd_writer.cpp### logcat read
system\core\liblog\logger_read.cpp
system\core\logcat\logcat.cpp
system\core\liblog\logd_reader.cpp### logd
system\core\logd\main.cpp
//LogListener监听socket logdw把log写到logBuffer
system\core\logd\LogListener.h
system\core\logd\LogListener.cpp
//SocketListener socket的监听类
system\core\libsysutils\src\SocketListener.cpp
system\core\libsysutils\include\sysutils\SocketListener.h
//记录每个使用LOG的pid客户端
system\core\libsysutils\src\SocketClient.cpp
system\core\logd\FlushCommand.cpp
//LogBuffer类
system\core\logd\LogBuffer.cpp//LogReader监听logdr类
system\core\logd\LogReader.cpp

1. ALOGD写log流程

1.1 ALOGD打印log,传入可变参数

@system\core\liblog\include\log\log_main.h

//ALOGD调用到ALOG
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif//最终使用到android_printLog
/** Log macro that allows you to specify a number for the priority.*/
#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,然后调用写

@system\core\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;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 idif (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;}//设置tagif (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透传messagelogger_function(log_message);
}//logger_function是函数__android_log_logd_logger
#ifdef __ANDROID__
static __android_logger_function logger_function = __android_log_logd_logger;
#else
static __android_logger_function logger_function = __android_log_stderr_logger;
#endif//__android_log_logd_logger继续转message到数组,最后write_to_log
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;//io vector: iovec io数组申请3个,分别设置优先级,tag,messagestruct 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;//写log,参数分别是强转的log_id_t, 消息数组,和数组长度write_to_log(static_cast<log_id_t>(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_tstruct_size;   /** Must be set to sizeof(__android_log_message) and is used for versioning. */int32_t buffer_id; /** {@link log_id_t} values. */int32_t priority;  /** {@link android_LogPriority} values. */const char* tag;   /** The tag for the log message. */const char* file;  /** Optional file name, may be set to nullptr. */uint32_t line;     /** Optional line number, ignore if file is nullptr. */const char* message; /** The log message itself. */
};
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不是此idif (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;
}

1.2 logdw socket写log

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

@system\core\liblog\logd_writer.cpp
static 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<sockaddr*>(&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 logdwGetSocket();//获取失败返回if (logd_socket <= 0) {return -EBADF;}//logd本身不能用/* 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;}//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文件

@android\system\core\liblog\pmsg_writer.cpp
static 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<uint32_t*>(vec[0].iov_base)) {return -EPERM;}}}//获取fd /dev/pmsg0GetPmsgFd();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_fdret = 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;
}/** Virtual pmsg filesystem** Payload will comprise the string "<basedir>:<basefile>\0<content>" to a* maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the* file.** Will hijack the header.realtime.tv_nsec field for a sequence number in usec.*/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;
}/* Write a buffer as filename references (tag = <basedir>:<basename>) */
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];/* Make sure the logId value is not a bad idea */if ((logId == LOG_ID_KERNEL) ||   /* Verbotten */(logId == LOG_ID_EVENTS) ||   /* Do not support binary content */(logId == LOG_ID_SECURITY) || /* Bad idea to allow */((unsigned)logId >= 32)) {    /* fit within logMask on arch32 */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.cpp
int Logcat::Run() {//reset文件fdoutput_fd_.reset();//设置格式threadtimeSetLogFormat("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, decltype(&android_logger_list_free)> logger_list{nullptr, &android_logger_list_free};logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));//android_logger_open打开 logid的logfor (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) {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_msgint 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,支持打印到中途或者写到文件fdProcessBuffer(&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 {//处理buffererr = 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_list
3. android_logger_open打开各个logid
4. android_logger_list_read读取log到log_msg
5. 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 {/* Verbs */FORMAT_OFF = 0,FORMAT_BRIEF,FORMAT_PROCESS,FORMAT_TAG,FORMAT_THREAD,FORMAT_RAW,FORMAT_TIME,FORMAT_THREADTIME,FORMAT_LONG,/* Adverbs. The following are modifiers to above format verbs */FORMAT_MODIFIER_COLOR,     /* converts priority to color */FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */FORMAT_MODIFIER_YEAR,      /* Adds year to date */FORMAT_MODIFIER_ZONE,      /* Adds zone to date, + UTC */FORMAT_MODIFIER_EPOCH,     /* Print time as seconds since Jan 1 1970 */FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */FORMAT_MODIFIER_UID,       /* Adds uid */FORMAT_MODIFIER_DESCRIPT,  /* Adds descriptive *//* private, undocumented */FORMAT_MODIFIER_TIME_NSEC, /* switches from msec to nsec time precision */
} AndroidLogPrintFormat;
@logcat.hpp// Used for all optionsandroid::base::unique_fd output_fd_{dup(STDOUT_FILENO)};std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{android_log_format_new(), &android_log_format_free};

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

AndroidLogFormat* android_log_format_new() {AndroidLogFormat* p_ret;p_ret = static_cast<AndroidLogFormat*>(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;
#elsep_ret->monotonic_output = false;
#endifp_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);/* Free conversion resource, can always be reconstructed */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.cpp
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);
}

直接设置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.cpp
std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{nullptr, &android_logger_list_free};
logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));

logger_list定义

@system\core\liblog\logger.h
struct logger_list {atomic_int fd;//原子操作int,多线程不用锁确保安全int mode;//modeunsigned int tail;//尾巴log_time start;//timepid_t pid;//piduint32_t log_mask;//mask
};
@system\core\liblog\logger_read.cpp
struct 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_listauto* logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(struct logger_list)));if (!logger_list) {return nullptr;}//赋值初始化logger_listlogger_list->mode = mode;logger_list->start = start;logger_list->tail = tail;logger_list->pid = pid;return logger_list;
}//关闭log,主要是关闭fd,然后释放logger_list对象,防止泄露
/* Close all the logs */
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);}
#endiffree(logger_list);
}

2.4 android_logger_open打开设备log

@logcat.cppfor (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) {ALOGE("android_logger_open error! ");continue;}}

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

/* Open the named log and add it to the logger list */
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就可以打开多个loguintptr_t logger = logId;//logger 正常不是pstore mode时,值是LOGGER_LOGDlogger |= (logger_list->mode & ANDROID_LOG_PSTORE) ? LOGGER_PMSG : LOGGER_LOGD;return reinterpret_cast<struct logger*>(logger);
}

2.5 android_logger_list_read获取buffer

struct log_msg定义,包含buffer, entry

@system\core\liblog\include\log\log_read.h
struct log_msg {union {unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];struct logger_entry entry;} __attribute__((aligned(4)));
#ifdef __cplusplus/* Matching log_time operators */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<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;}/* packet methods */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
};

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

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 */
};
@logger_read.cpp
//读取log到log_msg,logger_list包含需要读取的logid
int 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);}
#endifif (ret <= 0) {return ret;}
//检测ret结果省略
...//末尾设置\0log_msg->buf[log_msg->entry.len + log_msg->entry.hdr_size] = '\0';return ret;
}
@logd_reader.cpp
/* Read from the selected logs */
int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg) {
//open会让打开的/dev/socket/loddr赋值给logger_list,然后write socketint ret = logdOpen(logger_list);if (ret < 0) {return ret;}//recv读取socket logdr的内容到log_msg里面/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */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,就returnsock = atomic_load(&logger_list->fd);if (sock > 0) {return sock;}//连接/dev/socket/logdr,把fd给socksock = 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_listret = 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;      /* 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 */
};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\0  | msgbuffer\0  |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;/** format: <priority:1><tag:N>\0<message:N>\0** tag str*   starts at buf + buf->hdr_size + 1* msg*   starts at buf + buf->hdr_size + 1 + len(tag) + 1** The message may have been truncated.  When that happens, we must null-terminate the message* ourselves.*/if (buf->len < 3) {/** An well-formed entry must consist of at least a priority* and two null characters*/fprintf(stderr, "+++ LOG: entry too small\n");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_entry\n");return -1;}//msg表示buf偏移hdr_size(sizeof(struct logger_entry))个sizechar* msg = reinterpret_cast<char*>(buf) + buf->hdr_size;entry->uid = buf->uid;//通过有效长度len,和\0来找msgstart 和end
//第一个\0是因为\0前面是tag
//msgstart 和end中间才是真正log内容for (i = 1; i < buf->len; i++) {if (msg[i] == '\0') {if (msgStart == -1) {msgStart = i + 1;} else {msgEnd = i;break;}}}if (msgStart == -1) {/* +++ LOG: malformed log message, DYB */for (i = 1; i < buf->len; i++) {/* odd characters in tag? */if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {msg[i] = '\0';msgStart = i + 1;break;}}if (msgStart == -1) {msgStart = buf->len - 1; /* All tag, no message, print truncates */}}if (msgEnd == -1) {/* incoming message not null-terminated; force it */msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */msg[msgEnd] = '\0';}//msg0是优先级entry->priority = static_cast<android_LogPriority>(msg[0]);entry->tag = msg + 1;//偏移1是tagentry->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考到outBUfferoutBuffer =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.rc
service logd /system/bin/logd//定义需要的3个socket,已经对应权限socket logd stream 0666 logd logdsocket logdr seqpacket 0666 logd logdsocket logdw dgram+passcred 0222 logd logdfile /proc/kmsg rfile /dev/kmsg w   //文件是干啥的?user logd  //用户是logdgroup logd system package_info readproccapabilities SYSLOG AUDIT_CONTROLpriority 10 //优先级,有用?writepid /dev/cpuset/system-background/tasksservice logd-reinit /system/bin/logd --reinitoneshotdisableduser logdgroup logdwritepid /dev/cpuset/system-background/tasks# Limit SELinux denial generation to 5/second
service logd-auditctl /system/bin/auditctl -r 5oneshotdisableduser logdgroup logdcapabilities AUDIT_CONTROLon fs
//writewrite /dev/event-log-tags "# content owned by logd
"
//改文件权限,这样其他组没有访问event-log-tags的权限chown logd logd /dev/event-log-tagschmod 0644 /dev/event-log-tagson property:sys.boot_completed=1start logd-auditctl
  • 1 设置时区timezone环境变量为UTC
  • 2 获取kernel 节点fd /dev/kmsg
  • 3 启动re-init线程
  • 4 创建logBuffer, 创建LogReader并且监听logdr,创建LogListener监听logdw,创建CommandListener监听socket logd
  • 5 LogAudit并监听selinux ,创建LogKlog监听kernel
@main.cpp
int 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 fdDmesgstatic 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 %s\n", 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 Threadsem_init(&reinit, 0, 0);pthread_attr_t attr;if (!pthread_attr_init(&attr)) {struct sched_param param;memset(&param, 0, sizeof(param));pthread_attr_setschedparam(&attr, &param);pthread_attr_setschedpolicy(&attr, SCHED_BATCH);//创建reinit_threadif (!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.//创建logBufferlogBuf = 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.//初始化logListenerLogListener* swl = new LogListener(logBuf, reader);// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large valueif (swl->startListener(600)) {return EXIT_FAILURE;}// Command listener listens on /dev/socket/logd for incoming logd// administrative commands.//CommandListener初始化监听logd socketCommandListener* 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.//selinuxLogAudit* 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);}//读取dmesgreadDmesg(al, kl);// failure is an option ... messages are in dmesg (required by standard)//LogKlog和LogAudit都启动listenerif (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 --reinitoneshotdisableduser logdgroup logdwritepid /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

@system\core\logd\LogListener.h
#include <sysutils/SocketListener.h>
#include "LogReader.h"class LogListener : public SocketListener {LogBuffer* logbuf;LogReader* reader;public:LogListener(LogBuffer* buf, LogReader* reader);protected:virtual bool onDataAvailable(SocketClient* cli);private://获取socketstatic int getLogSocket();
};

LogListener构造器就会获取socket logdw

//SocketListener传入socket etLogSocket()
//buffer 和reader也赋值到 logbuf, reader
LogListener::LogListener(LogBuffer* buf, LogReader* reader): SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {}//获取到socket
int LogListener::getLogSocket() {static const char socketName[] = "logdw";int sock = android_get_control_socket(socketName);if (sock < 0) {  // logd started up in init.shsock = 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数组,看是否变化,

@system\core\libsysutils\src\SocketListener.cpp
//backlog默认4,LogListenner默认600
int SocketListener::startListener(int backlog) {//mSock是fd,不走这两个ifif (!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函数方法runListener
void *SocketListener::threadStart(void *obj) {SocketListener *me = reinterpret_cast<SocketListener *>(obj);me->runListener();pthread_exit(nullptr);//正常不会退出return nullptr;
}//运行监听
void SocketListener::runListener() {while (true) {//fd数组std::vector<pollfd> fds;//上锁,防止释放等操作冲突pthread_mutex_lock(&mClientsLock);//reserve对vector扩容,避免内存重新分配。客户端size + 2,客户端size是使用logd的进程数fds.reserve(2 + mClients.size());//数组push一个piplefds.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,传入SocketClietnpthread_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<SocketClient*> 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 mapSLOGV("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 our sockets are connection-based, remove and destroy it */if (mListen && c) {/* Remove the client from our map */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.cpp
bool 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 receivedchar 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 socketint 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里面,此时值就是bufferif (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<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 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成功后,通知新logreader->notifyNewLog(static_cast<log_mask_t>(1 << logId));}return true;
}

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

@android\system\core\logd\LogReader.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等,好赋值给logdint len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);if (len <= 0) {doSocketDelete(cli);return false;}buffer[len] = '\0';// 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 timestart.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 != '\0') {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<strncmp>(buffer, "dumpAndClose", 12)) {// Allow writer to get some cycles, and wait for pending notificationssched_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 nameprivate: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<LogFindStart*>(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 "ns\n",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<LogTimeEntry>(*this, cli, nonBlock, tail, logMask, pid, sequence, timeout);//start 开始读当前客户端pid的logif (!entry->startReader_Locked()) {LogTimeEntry::unlock();return false;}// release client and entry reference counts once donecli->incRef();mLogbuf.mTimes.emplace_front(std::move(entry));//设置socket超时// Set acceptable upper limit to wait for slow reader processing b/27242723struct timeval t = { LOGD_SNDTIMEO, 0 };setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,sizeof(t));LogTimeEntry::unlock();return true;
}

正在的写logdr地方

system\core\logd\LogTimes.cpp
//启动线程threadStart
bool 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 nameLogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(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,&timesLock, &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, &timesLock);}}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 zombieMem:  3390188K total,  2663680K used,   726508K free,  19460096 buffersSwap:  2097148K total,         0 used,  2097148K free,   733840K cached
800%cpu  10%user   1%nice  42%sys 744%idle   0%iow   2%irq   1%sirq   0%hostTID USER         PR  NI VIRT  RES  SHR S[%CPU] %MEM     TIME+ THREAD          PROCESS2947 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 logdw278 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:00.00 logd.control    logd  //CommandListener.cpp logd控制线程 socket logd274 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/logd
ABI: '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/logd
ABI: 'arm64'Stack Trace:RELADDR           FUNCTION           FILE:LINE000000000009bad8  __rt_sigsuspend+8  out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:1704000000000005c96c  sigsuspend64+60    bionic/libc/bionic/signal.cpp:270000000000005a050  pause+36           bionic/libc/bionic/pause.cpp:340000000000009800  main+1496          system/core/logd/main.cpp:43600000000000499fc  __libc_init+108    bionic/libc/bionic/libc_init_dynamic.cpp:151

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

"logd.reader" sysTid=276Stack Trace:RELADDR           FUNCTION                                            FILE:LINE000000000009c1b4  __ppoll+4                                           out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:2385000000000005a3c0  poll+92                                             bionic/libc/bionic/poll.cpp:48v-------------->  poll(pollfd*, unsigned int pass_object_size1, int)  bionic/libc/include/bits/fortify/poll.h:54000000000000570c  SocketListener::runListener()+412                   system/core/libsysutils/src/SocketListener.cpp:16800000000000053c4  SocketListener::threadStart(void*)+8                system/core/libsysutils/src/SocketListener.cpp:14600000000000afecc  __pthread_start(void*)+64                           bionic/libc/bionic/pthread_create.cpp:3470000000000050408  __start_thread+64

logd.writer也是在poll线程

"logd.writer" sysTid=277Stack Trace:RELADDR           FUNCTION                                            FILE:LINE000000000009c1b4  __ppoll+4                                           out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:2385000000000005a3c0  poll+92                                             bionic/libc/bionic/poll.cpp:48v-------------->  poll(pollfd*, unsigned int pass_object_size1, int)  bionic/libc/include/bits/fortify/poll.h:54000000000000570c  SocketListener::runListener()+412                   system/core/libsysutils/src/SocketListener.cpp:16800000000000053c4  SocketListener::threadStart(void*)+8                system/core/libsysutils/src/SocketListener.cpp:14600000000000afecc  __pthread_start(void*)+64                           bionic/libc/bionic/pthread_create.cpp:3470000000000050408  __start_thread+64                                   bionic/libc/bionic/clone.cpp:53

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

"logd.klogd" sysTid=283Stack Trace:RELADDR           FUNCTION                                           FILE:LINE000000000009ae74  read+4                                             out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:461v-------------->  read(int, void*, unsigned long pass_object_size0)  bionic/libc/include/bits/fortify/unistd.h:159000000000001cd0c  LogKlog::onDataAvailable(SocketClient*)+156        system/core/logd/LogKlog.cpp:2350000000000005aa8  SocketListener::runListener()+1336                 system/core/libsysutils/src/SocketListener.cpp:21800000000000053c4  SocketListener::threadStart(void*)+8               system/core/libsysutils/src/SocketListener.cpp:14600000000000afecc  __pthread_start(void*)+64                          bionic/libc/bionic/pthread_create.cpp:3470000000000050408  __start_thread+64                                  bionic/libc/bionic/clone.cpp:53

4. 整体流程图

AndroidR Logd原理相关推荐

  1. android logd 原理及实现

    一.logd介绍 logd 是Android L版本提出来的概念,其作用是保存Android运行期间的log(日志).在Android L之前,log由kernel的ring buffer 保存,在A ...

  2. 安卓日志系统初探(带你了解Android日志系统的概貌)

    目录 1 介绍 2 ADB的原理 2.1 adbd服务进程 2.2 ADB 服务端 2.2.1 USB方式 2.2.2 网络方式 2.2.3串口方式 2.3 ADB 客户端 3 安卓框架中日志的收集和 ...

  3. android log丢失(一)使用logd丢失log原理

    之前我们分析过关于Android log机制,在这里我们再详细说下,log丢失的原理. 一.统计log logd监听了logdw的socket来保存从log打印函数通过logdw socket传过来的 ...

  4. Android logd日志原理

    一. 概述 无论是Android系统开发,还是应用开发,都离不开log,Androd上层采用logcat输出log. 1.1 logcat命令说明 可通过adb命令直接输出指定的log: logcat ...

  5. MySQL索引背后的数据结构及算法原理【转】

    http://blog.codinglabs.org/articles/theory-of-mysql-index.html MySQL索引背后的数据结构及算法原理[转] 摘要 本文以MySQL数据库 ...

  6. Mysql 索引原理及优化

    本文内容主要来源于互联网上主流文章,只是按照个人理解稍作整合,后面附有参考链接. 一.摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引 ...

  7. HwBinder原理总结-Android10.0 HwBinder通信原理(十一)

    摘要:本节主要来进行Android10.0 HwBinder的原理总结 阅读本文大约需要花费14分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设 ...

  8. HwBinder驱动篇-Android10.0 HwBinder通信原理(十)

    摘要:本节主要来讲解Android10.0 HwBinder驱动的流程 阅读本文大约需要花费24分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设 ...

  9. JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)

    摘要:本节主要来讲解Android10.0 JAVA层HIDL服务的获取原理 阅读本文大约需要花费19分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的 ...

最新文章

  1. nginx http转https_Nginx处理访问www域名跳转到不带www域名的配置方法
  2. mint-ui的Loadmore组件使用示例
  3. 分布式系统的事务处理
  4. LeetCode4. Median of Two Sorted Arrays(二分法)
  5. mysql 创建数据库文件_mysql学习之通过文件创建数据库以及添加数据
  6. 枚举求解:试把一个正整数n拆分为若干个(不少于2个)连续正整数之和。例如:n=15,有3种拆分:15=1+2+3+4+5,15=4+5+6,15=7+8。 对于给定的正整数n,求出所有符合这种拆分要求
  7. 阿里全盘调整组织架构意味着什么?| 畅言
  8. PHP 扩展 Mongo 与 MongoDB
  9. 博图os更新_PCS7和TIA博图软件有什么区别?
  10. 内蒙古一个不起眼的小城,藏着中国最大火力发电厂
  11. SketchUp Pro 2022草图大师27个最常用的快捷键(含PC和Mac)
  12. python:求100以内素数的和
  13. JS实现页面字体繁简转换
  14. 安卓仿苹果键盘输入法_iphone输入法安卓版下载
  15. VTP(VLAN中继协议)简单介绍
  16. 社会工程管理——股权分配
  17. SSM+网上书城系统 毕业设计-附源码180919
  18. org.springframework.dao.InvalidDataAccessApiUsageException:The given object has a null identifi的解决方案
  19. splay的一些操作
  20. 小波阈值去噪的原理及程序

热门文章

  1. 【图像识别】简单验证码识别
  2. PowerPoint 2007双显示输出技巧
  3. 【无限滚动加载数据】—infinite-scroll插件的使用
  4. 【游戏课】技术片段之——四元数与旋转矩阵的关系
  5. 数学建模配送中心选址问题
  6. html与摄像头怎么链接,HTML5将DSLR连接为网络摄像头(HTML5 connect DSLR as webcam)
  7. 哪些明星大咖是隐藏的程序员?
  8. 香港考研计算机大学排名,香港学校研究生专业排名2019年情况如何?
  9. 管理类联考——英语——技巧篇——阅读理解
  10. 在python语言中可作为源文件后缀名的是_Python中的标识符不区分大小写。