logcat通过读/dev/socket/logdr这个socket节点来从logd进程中获取信息,
这个处理在Android 6的logcat代码中很清楚的就可以看到。
但是Android 7里读logdr写的很晦涩,这里我们来看看Android 7里logcat读logdr的处理。
在Android 6中,
可以很清晰的看到使用android_logger_list_read来读logdr
/system/core/logcat/logcat.cpp
int main(int argc, char **argv)
{
… …
while (1) {
struct log_msg log_msg;
log_device_t* d;
int ret = android_logger_list_read(logger_list, &log_msg);
android_logger_list_read定义在
/system/core/liblog/log_read.c
int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
{
int sock = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
在Android 7中
/system/core/logcat/logcat.cpp
同样是调用android_logger_list_read
while (!g_maxCount || (g_printCount < g_maxCount)) {
struct log_msg log_msg;
log_device_t* d;
int ret = android_logger_list_read(logger_list, &log_msg);
但是android_logger_list_read的实现却面目全非了,定义在
/system/core/liblog/logger_read.c
里面
LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
{
struct android_log_transport_context *transp;
struct android_log_logger_list *logger_list_internal =
(struct android_log_logger_list *)logger_list;
int ret = init_transport_context(logger_list_internal);
if (ret < 0) {
return ret;
}
/* at least one transport */
transp = node_to_item(logger_list_internal->transport.next,
struct android_log_transport_context, node);
/* more than one transport? */
if (transp->node.next != &logger_list_internal->transport) {
/* Poll and merge sort the entries if from multiple transports */
struct android_log_transport_context *oldest = NULL;
int ret;
int polled = 0;
do {
if (polled) {
sched_yield();
}
ret = -1000;
polled = 0;
do {
int retval = transp->ret;
if ((retval > 0) && !transp->logMsg.entry.len) {
if (!transp->transport->read) {
retval = transp->ret = 0;
} else if ((logger_list_internal->mode &
ANDROID_LOG_NONBLOCK) ||
!transp->transport->poll) {
retval = transp->ret = (*transp->transport->read)(
logger_list_internal,
transp,
&transp->logMsg);
} else {
int pollval = (*transp->transport->poll)(
logger_list_internal, transp);
if (pollval <= 0) {
sched_yield();
pollval = (*transp->transport->poll)(
logger_list_internal, transp);
}
polled = 1;
if (pollval < 0) {
if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
return -EAGAIN;
}
retval = transp->ret = pollval;
} else if (pollval > 0) {
retval = transp->ret = (*transp->transport->read)(
logger_list_internal,
transp,
&transp->logMsg);
}
}
}
if (ret < retval) {
ret = retval;
}
if ((transp->ret > 0) && transp->logMsg.entry.len &&
(!oldest ||
(oldest->logMsg.entry.sec >
transp->logMsg.entry.sec) ||
((oldest->logMsg.entry.sec ==
transp->logMsg.entry.sec) &&
(oldest->logMsg.entry.nsec >
transp->logMsg.entry.nsec)))) {
oldest = transp;
}
transp = node_to_item(transp->node.next,
struct android_log_transport_context,
node);
} while (transp != node_to_item(
&logger_list_internal->transport,
struct android_log_transport_context,
node));
if (!oldest &&
(logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
return (ret < 0) ? ret : -EAGAIN;
}
transp = node_to_item(logger_list_internal->transport.next,
struct android_log_transport_context, node);
} while (!oldest && (ret > 0));
if (!oldest) {
return ret;
}
memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
(oldest->logMsg.entry.hdr_size ?
oldest->logMsg.entry.hdr_size :
sizeof(struct logger_entry)));
oldest->logMsg.entry.len = 0; /* Mark it as copied */
return oldest->ret;
}
/* if only one, no need to copy into transport_context and merge-sort */
return (transp->transport->read)(logger_list_internal, transp, log_msg);
}
并没有看到logdr
到底是怎么读的呢
init_transport_context
中有
if (list_empty(&__android_log_transport_read) &&
list_empty(&__android_log_persist_read)) {
__android_log_config_read();
}
/system/core/liblog/config_read.c
LIBLOG_HIDDEN void __android_log_config_read() {
#if (FAKE_LOG_DEVICE == 0)
extern struct android_log_transport_read logdLoggerRead;
extern struct android_log_transport_read pmsgLoggerRead;
__android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
__android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
#endif
}
其中logdLoggerRead
/system/core/liblog/logd_reader.c
LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = {
.node = { &logdLoggerRead.node, &logdLoggerRead.node },
.name = "logd",
.available = logdAvailable,
.version = logdVersion,
.read = logdRead,
.poll = logdPoll,
.close = logdClose,
.clear = logdClear,
.getSize = logdGetSize,
.setSize = logdSetSize,
.getReadableSize = logdGetReadableSize,
.getPrune = logdGetPrune,
.setPrune = logdSetPrune,
.getStats = logdGetStats,
};
static int logdRead(struct android_log_logger_list *logger_list,
struct android_log_transport_context *transp,
struct log_msg *log_msg)
{
int ret, e;
struct sigaction ignore;
struct sigaction old_sigaction;
unsigned int old_alarm = 0;
ret = logdOpen(logger_list, transp);
if (ret < 0) {
return ret;
}
memset(log_msg, 0, sizeof(*log_msg));
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
memset(&ignore, 0, sizeof(ignore));
ignore.sa_handler = caught_signal;
sigemptyset(&ignore.sa_mask);
/* particularily useful if tombstone is reporting for logd */
sigaction(SIGALRM, &ignore, &old_sigaction);
old_alarm = alarm(30);
}
/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
e = errno;
里面调用了logdOpen来打开logdr
static int logdOpen(struct android_log_logger_list *logger_list,
struct android_log_transport_context *transp)
{
struct android_log_logger *logger;
struct sigaction ignore;
struct sigaction old_sigaction;
unsigned int old_alarm = 0;
char buffer[256], *cp, c;
int e, ret, remaining;
int sock = transp->context.sock;
if (sock > 0) {
return sock;
}
if (!logger_list) {
return -EINVAL;
}
sock = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
if (sock == 0) {
/* Guarantee not file descriptor zero */
int newsock = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
close(sock);
sock = newsock;
}
if (sock <= 0) {
if ((sock == -1) && errno) {
return -errno;
}
return sock;
}