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 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;
#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,message
struct iovec vec[3];
vec[0].iov_base =
const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
vec[0].iov_len = 1;
vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
vec[1].iov_len = strlen(log_message->tag) + 1;
vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
vec[2].iov_len = strlen(log_message->message) + 1;
//写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_t
struct_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不是此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()) {
/* 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 logdw
GetSocket();
//获取失败返回
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/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;
}
/*
* 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文件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, 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的log
for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
if (!(id_mask & (1 << i))) continue;
const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
if (logger == nullptr) {
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_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 options
android::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;
#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);
/* 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;//mode
unsigned int tail;//尾巴
log_time start;//time
pid_t pid;//pid
uint32_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_list
auto* logger_list = static_cast<struct logger_list*>(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对象,防止泄露
/* 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);
}
#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<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就可以打开多个log
uintptr_t logger = logId;
//logger 正常不是pstore mode时,值是LOGGER_LOGD
logger |= (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);
}
#endif
if (ret <= 0) {
return ret;
}
//检测ret结果省略
...
//末尾设置\0
log_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 socket
int 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,就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; /* 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))个size
char* 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是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.rc
service 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/tasks
service logd-reinit /system/bin/logd --reinit
oneshot
disabled
user logd
group logd
writepid /dev/cpuset/system-background/tasks
# Limit SELinux denial generation to 5/second
service logd-auditctl /system/bin/auditctl -r 5
oneshot
disabled
user logd
group logd
capabilities AUDIT_CONTROL
on 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-tags
on property:sys.boot_completed=1
start 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 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 %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 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
@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://获取socket
static 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.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数组,看是否变化,
@system\core\libsysutils\src\SocketListener.cpp
//backlog默认4,LogListenner默认600
int 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函数方法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一个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<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 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 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 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<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成功后,通知新log
reader->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等,好赋值给logd
int 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 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 != '\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 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<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的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地方
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 name
LogTimeEntry* 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,
×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 cached
800%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/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: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=276
Stack 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=277
Stack 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=283
Stack 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