zoukankan      html  css  js  c++  java
  • android系统中的log定向

    http://blog.csdn.net/knock/article/details/5511255
    为了调试,必须要将log怎么打印的搞清楚,于是有了以下的分析。


    我们通常在程序中插入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);
    }


    static void open_console()
    {
        int fd;
        if ((fd = open(console_name, O_RDWR)) < 0) {
            fd = open("/dev/null", O_RDWR);
        }
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
        close(fd);
    }
    zap_stdio()比较狠,直接将STDIN,STDOUT,STDERR都干掉了,而open_console()则只是在/dev/console


    不存在的情况下才干掉STDIN,STDOUT,STDERR,如果/dev/console存在,则将所有输入输出重定向到它



    调用哪个取决于needs_console,
    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
    而svc->flags关于SVC_CONSOLE的部分来自于system/core/init/parser.c
    static void parse_line_service(struct parse_state *state, int nargs, char **args)
    {
           case K_console:
            svc->flags |= SVC_CONSOLE;
            break;


    }
    这也就是说如果init.rc中service部分有请求console,则可以打印到console。


    但怎么样才能打印到系统的log中,可以使用logcat来查看呢?这就需要用到logwrapper。
    system/core/logwrapper/logwrapper.c中,logwrapper先打开/dev/ptmx,查询到设备名后
    fork()一个子进程并将STDOUT,STDERR定向到查询到的设备。
            // redirect stdout and stderr
            close(parent_ptty);
            dup2(child_ptty, 1);
            dup2(child_ptty, 2);
            close(child_ptty);
    然后开始执行要运行的程序
     child(argc - 1, &argv[1]);




    总结:
    系统中的程序中输出log一般是到/dev/log/下的三个设备中,可以用logcat查看。
    对于init运行的程序则有两种方法查看到log信息:
    1.添加/system/bin/logwrapper,可以用logcat查看,例如
     service /system/bin/logwrapper /system/bin/rild
    2.添加console,像sh一样直接输出到console
     service console /system/bin/sh
          console
  • 相关阅读:
    Android ExpandableListView的下拉刷新实现
    Android 使用shape来画线
    三种常见的子查询(三十一)
    数据的准备(三十)
    LIMIT语句解析及本章简单回顾(二十九)
    WHERE、ORDER BY、GROUP BY、HAVING语句解析(二十八)
    查询表达式解析(二十七)
    单表的更新UPDATE和删除记录DELETE(二十六)
    插入记录INSERT(二十五)
    修改数据表——修改列定义和更名数据表(二十四)
  • 原文地址:https://www.cnblogs.com/eustoma/p/2415796.html
Copyright © 2011-2022 走看看