Log机制
APP打印日志,最简单的是使用Log类(android.util.Log),所以我就从一句简单的log.d开始我的路线。在APP中如果调用Log.d(“test”,“print test”); ,那么可以在Android中使用logcat看到一句我们打印的日志,如下:
01-01 00:03:35.122 2990 3505 D test: print test
那么这个过程是怎么样的呢,简单的看看Log.java
Log 写
Log.java中定义了log的buffer ID
/** @hide */ public static final int LOG_ID_MAIN = 0; 主要使用的类android.util.Log
/** @hide */ public static final int LOG_ID_RADIO = 1; 主要使用的类android.telephony.Rlog
/** @hide */ public static final int LOG_ID_EVENTS = 2; 主要使用的类android.util.EventLog
/** @hide */ public static final int LOG_ID_SYSTEM = 3; 主要使用的类android.util.Slog(hide)
/** @hide */ public static final int LOG_ID_CRASH = 4; 主要使用的类com.andoid.internal.os.RuntimeInit
和libdebugged/utility.cpp
简单的调用流程如下:
调用public static int d(String tag, String msg), 这方法调用的是println_native(LOG_ID_MAIN, DEBUG, tag, msg, tr),传入了一个LOG_ID_MAIN。然后println_native的实现交给了在frameworks/base/core/jni/android_util_Log.cpp中的android_util_Log_println_native
/*
* In class android.util.Log:
* public static native int println_native(int buffer, int priority, String tag, String msg)
*/
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
...省略
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); //关键代码
...省略
return res;
}
__android_log_buf_write的实现在system/core/liblog/logger_write.c中(其他一些系统模块,例如debuggered等C++代码都会直接封装或者调用__android_log_buf_write来打印日志)
LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
const char* tag, const char* msg) {
struct iovec vec[3];
...省略一大坨
vec[0].iov_base = (unsigned char*)&prio; // 例如通过Log.v调用过来,这里是2(VERBOSE)
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; 默认调用__write_to_log_init
static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
int ret, save_errno = errno;
__android_log_lock();
if (write_to_log == __write_to_log_init) {
ret = __write_to_log_initialize(); //点1
if (ret < 0) {
__android_log_unlock();
if (!list_empty(&__android_log_persist_write)) {
__write_to_log_daemon(log_id, vec, nr);
}
errno = save_errno;
return ret;
}
write_to_log = __write_to_log_daemon;
}
__android_log_unlock();
ret = write_to_log(log_id, vec, nr); //点2
errno = save_errno;
return ret;
}
这个函数中有两个点,先看一下点1,里面为集合__android_log_transport_write设置各类writer,例如logdLoggerWrite,pmsgLoggerWrite等,然后依次调用writer的open方法,logdLoggerWrite#logdOpen方法,如果打开失败,则关闭。简单的看下logdLoggerWrite的实现在system/core/liblog/logd_writer.c中
static int logdOpen() {
...省略
strcpy(un.sun_path, "/dev/socket/logdw");
if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un,
sizeof(struct sockaddr_un))) < 0) {
...省略
}
大概意思就是建立socket连接
然后继续看流程就走到了点2的地方,实际的实现是__write_to_log_daemon,这个函数比较长,看一下关键的几个点
static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
struct android_log_transport_write* node;
int ret, save_errno;
struct timespec ts;
size_t len, i;
...
clock_gettime(android_log_clockid(), &ts); //获取时间戳
if (log_id == LOG_ID_SECURITY) {
if (vec[0].iov_len < 4) {
errno = save_errno;
return -EINVAL;
}
ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len,
ANDROID_LOG_VERBOSE);
if (f) { /* local copy marked for close */
android_closeEventTagMap(f);
}
if (!ret) {
errno = save_errno;
return -EPERM;
}
} else {
/* Validate the incoming tag, tag content can not split across iovec */
char prio = ANDROID_LOG_VERBOSE;
const char* tag = vec[0].iov_base;
size_t len = vec[0].iov_len;
// 变量prio存储vec[0].iov_base,例如2(VERBOSE),tag存储vec[1].iov_base
if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
//如果当前打印的log级别低于系统设置的级别,会直接返回,不会打印。默认是ANDROID_LOG_VERBOSE(2),系统设置的级别来自于属性:persist.log.tag 或 log.tag,tag就是你Log.d(TAG,“”)一般来说使用方式为
adb shell s