Android系统中的log定向

为了调试,必须要将log怎么打印的搞清楚,于是有了以下的分析。

避免Android开发中的ANR

我们通常在程序中插入LOGD(..),LOGE(..)之类的语句,但什么情况下可以查看这些打印消息呢?
首先,来到定义处:system/core/include/cutils/log.h,在开头就可以看到
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
所以程序中#include "log.h"之前要定义LOG_TAG,不然就为空.
再看LOGD的定义
#ifndef LOGD
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
跟进
#ifndef LOG
#define LOG(priority, tag, ...) \
    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
继续
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
    android_printLog(priority, tag, __VA_ARGS__)
#endif
再跟进
#define android_printLog(prio, tag, fmt...) \
    __android_log_print(prio, tag, fmt)

__android_log_print()是位于system/core/liblog/logd_write.c内
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
{
    va_list ap;
    char buf[LOG_BUF_SIZE];   

va_start(ap, fmt);
    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
    va_end(ap);

return __android_log_write(prio, tag, buf);
}
看__android_log_write()
int __android_log_write(int prio, const char *tag, const char *msg)
{
    ......

return write_to_log(log_id, vec, 3);
}
write_to_log定义如下
static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) =
    __write_to_log_init;
查看一下
static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
{
#ifdef HAVE_PTHREADS
    pthread_mutex_lock(&log_init_lock);
#endif

if (write_to_log == __write_to_log_init) {
        log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
        log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
        log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);

write_to_log = __write_to_log_kernel;

if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
                log_fds[LOG_ID_EVENTS] < 0) {
            log_close(log_fds[LOG_ID_MAIN]);
            log_close(log_fds[LOG_ID_RADIO]);
            log_close(log_fds[LOG_ID_EVENTS]);
            log_fds[LOG_ID_MAIN] = -1;
            log_fds[LOG_ID_RADIO] = -1;
            log_fds[LOG_ID_EVENTS] = -1;
            write_to_log = __write_to_log_null;
        }
    }

#ifdef HAVE_PTHREADS
    pthread_mutex_unlock(&log_init_lock);
#endif

return write_to_log(log_id, vec, nr);
}
这段的主要意思是打开/dev/log/main,/dev/log/radio,/dev/log/events三个设备都成功则将

write_to_log指向__write_to_log_kernel,否则指向__write_to_log_null。
下面就分别看看这两个
static int __write_to_log_null(log_id_t log_fd, struct iovec *vec, size_t nr)
{
    return -1;
}

static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
{
    ssize_t ret;
    int log_fd;

if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
        log_fd = log_fds[(int)log_id];
    } else {
        return EBADF;
    }

do {
        ret = log_writev(log_fd, vec, nr);
    } while (ret < 0 && errno == EINTR);

return ret;
}
__write_to_log_null()什么也不做,表示丢弃log信息。__write_to_log_kernel会调用log_writev()

将log写进对应的设备(/dev/log/*).

为什么写进init.rc里由init来执行的程序不能输出log呢?下面再来探究一番。。
system/core/init/init.c中,
void service_start(struct service *svc)函数启动服务,有这么一句
        if (needs_console) {
            setsid();
            open_console();
        } else {
            zap_stdio();
        }
而这两个函数为:
static void zap_stdio(void)
{
    int fd;
    fd = open("/dev/null", O_RDWR);
    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);
    close(fd);
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwfgwz.html