写在前面
由于工作原因最近研究了一下Android的Log实现机制,在这里做一个记录,如果有理解不到位的地方也请各位大哥大姐们指点指点。以下涉及的代码均基于Android N。下面开始咯。
Android N中Log机制的总线:
Log的输出是由不同的进程发起的,但真正实现Log的输入与输出的是一个叫logd的模块,他是一个单独的native进程,当一个应用进程需要打印一条Log时,其实是通过socket与logd模块通信最终由logd来完成Log的处理工作的。本系列文章计划按调用栈的顺序分上下两篇,上篇记录从java中调用常用的log打印接口后一直到连接到logd模块的过程。下篇详细记录logd中处理log信息的过程。
Log Priority
首先,在Android中输出的Log是有优先级的,如下所示列出了Android中Log的所有优先级:
/**
* Priority constant for the println method; use Log.v.
*/
public static final int VERBOSE = 2;
/**
* Priority constant for the println method; use Log.d.
*/
public static final int DEBUG = 3;
/**
* Priority constant for the println method; use Log.i.
*/
public static final int INFO = 4;
/**
* Priority constant for the println method; use Log.w.
*/
public static final int WARN = 5;
/**
* Priority constant for the println method; use Log.e.
*/
public static final int ERROR = 6;
/**
* Priority constant for the println method.
*/
public static final int ASSERT = 7;
Verbose优先级最低,跟着到Debug优先级依次提高,在这里看到的优先级最高的是Assert。后面会说到基于Log的优先级,提供了一套支持设置Log过滤的方法。
从调用开始
我们在平时开发过程中需要在程序中加入一些Log,这个自然大家都知道,Android中为我们提供了以下一些常用的接口实现Log的输出:
/**
* Send a {@link #VERBOSE} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int v(String tag, String msg) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
/**
* Send a {@link #DEBUG} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int d(String tag, String msg) {
return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
}
/**
* Send an {@link #INFO} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int i(String tag, String msg) {
return println_native(LOG_ID_MAIN, INFO, tag, msg);
}
/**
* Send a {@link #WARN} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int w(String tag, String msg) {
return println_native(LOG_ID_MAIN, WARN, tag, msg);
}
/**
* Send an {@link #ERROR} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int e(String tag, String msg) {
return println_native(LOG_ID_MAIN, ERROR, tag, msg);
}
/** @hide */ public static native int println_native(int bufID,
int priority, String tag, String msg);
这几个接口分别实现不同优先级的log的输出,可以看到他们内部都是通过一个native方法println_native实现的。这里需要注意的是println_native函数的第一个参数,它是一个整形,表示当前Log是往哪一个buffer里面去写,后面讲到logd时会看到这里的这个参数控制了我们输出的Log该往logd中的那一块buffer里面填充。println_native的实现在android_util_Log.cpp文件中:
/*
* 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)
{
const char* tag = NULL;
const char* msg = NULL;
if (msgObj == NULL) {
jniThrowNullPointerException(env, "println needs a message");
return -1;
}
if (bufID < 0 || bufID >= LOG_ID_MAX) {
jniThrowNullPointerException(env, "bad bufID");
return -1;
}
if (tagObj != NULL)
tag = env->GetStringUTFChars(tagObj, NULL);
msg = env->GetStringUTFChars(msgObj, NULL);
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
if (tag != NULL)
env->ReleaseStringUTFChars(tagObj, tag);
env->ReleaseStringUTFChars(msgObj, msg);
return res;
}
/*
* JNI registration.
*/
static