Android的Log系统
16lz
2021-12-04
最近看了一点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;
#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没有设置,则打印到标准输出。
更多相关文章
- NPM 和webpack 的基础使用
- 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
- android的adb详解(多设备时adb调用)
- Android(安卓)Drawable Resource学习(一)、Drawable Resource简介
- 接触Android
- Android内核的简单分析
- android下 抓包
- assets android 获取流 转为string
- Android(安卓)音频系统(二)之 AudioFlinger