Android的Log系统

最近看了一点android关于log的代码,小结一下。

对开发者来说,Log读主要调用工具logcat,后面附带一些参数,

写的话JAVA或者C/C++都有相应的接口。

代码位置:

frameworks/base/core/java/android/util/Log.java

system/core/liblog

system/core/logcat

frameworks/base/core/jni/android_util_Log.cpp


写过程:

JAVA层的frameworks/base/core/java/android/util/Log.java通过JNI掉本地方法__android_log_buf_write,

int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
{
    struct iovec vec[3];

    if (!tag)
        tag = "";

    /* XXX: This needs to go! */
    if (!strcmp(tag, "HTC_RIL") ||
        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
        !strcmp(tag, "AT") ||
        !strcmp(tag, "GSM") ||
        !strcmp(tag, "STK") ||
        !strcmp(tag, "CDMA") ||
        !strcmp(tag, "PHONE") ||
        !strcmp(tag, "SMS"))
            bufID = LOG_ID_RADIO;

    vec[0].iov_base   = (unsigned char *) &prio;
    vec[0].iov_len    = 1;
    vec[1].iov_base   = (void *) tag;
    vec[1].iov_len    = strlen(tag) + 1;
    vec[2].iov_base   = (void *) msg;
    vec[2].iov_len    = strlen(msg) + 1;

    return write_to_log(bufID, vec, 3);
}

write_to_log是函数指针,初始化为__write_to_log_init

static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;


__write_to_log_init打开log设备文件,这些设备文件在logger.h中有定义

#define LOGGER_LOG_MAIN     "log/main"
#define LOGGER_LOG_RADIO    "log/radio"
#define LOGGER_LOG_EVENTS   "log/events"
#define LOGGER_LOG_SYSTEM   "log/system"

初始化设备后,write_to_lo指向__write_to_log_kernel

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;
}
log_id指向对应打开的log设备,然后获取文件描述符,将log信息写入文件,id在Log.java中有定义

    /** @hide */ public static final int LOG_ID_MAIN = 0;
    /** @hide */ public static final int LOG_ID_RADIO = 1;
    /** @hide */ public static final int LOG_ID_EVENTS = 2;
    /** @hide */ public static final int LOG_ID_SYSTEM = 3;

对于C/C++,只需引用<utils/Log.h>头文件,并且定义LOG_TAG宏,在log.h中有如下宏定义

#ifndef LOG_TAG                                                               
#define LOG_TAG NULL                                                          
#endif 
因此你注意避免LOG_TAG的定义有冲突

LOG的宏定义如下:

/*
 * Simplified macro to send a debug log message using the current LOG_TAG.
 */
#ifndef LOGD
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif


/*
 * Basic log message macro.
 *
 * Example:
 *  LOG(LOG_WARN, NULL, "Failed with error %d", errno);
 *
 * The second argument may be NULL or "" to indicate the "global" tag.
 */
#ifndef LOG
#define LOG(priority, tag, ...) \
    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif


/*
 * 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, fmt...) \
    __android_log_print(prio, tag, fmt)

__android_log_print最后会调用到__android_log_write函数,完成写入过程。


读过程:

可想而知,读的过程也是打开对应的设备文件,读取里面的log信息。

读log一般都是在minicom或adb shell中执行logcat命令

logcat.cpp里的main函数是该命令的入口

其中-b参数选择对应buffer,也就是对应的设备文件,-c清空buffer,-g获取buffer大小,-f设置log输出设备。

获取命令行里的设备列表之后,打开设备,调用readLogLines从设备中读取log信息到queued_entry_t队列中

static void readLogLines(log_device_t* devices)

            for (dev=devices; dev; dev = dev->next) {
                FD_SET(dev->fd, &readset);
            }
            result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);

android_log_printLogLine负责将queued_entry_t队列中的log打印到g_outFD描述符的设备里,如果-f没有设置,则打印到标准输出。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值