赞
踩
最近看了一点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);
- }

static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
- #define LOGGER_LOG_MAIN "log/main"
- #define LOGGER_LOG_RADIO "log/radio"
- #define LOGGER_LOG_EVENTS "log/events"
- #define LOGGER_LOG_SYSTEM "log/system"
- 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);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。