Log类的路径在/frameworks/base/core/java/android/util/Log.java
Slog类的路径在/frameworks/base/core/java/android/util/Slog.java
目录
1. 常见的枚举类android_LogPriority的定义
2. properties.cpp中的__android_log_is_loggable()
5. logger_write.cpp中的__android_log_buf_write()
5. logger_write.cpp中的__android_log_write_log_message()
一、Log的日志等级
以下6个等级是Log日志对应的值,该level用来判断某一level的日志是否能打印,和native boolean isLoggable()相关。
//Priority constant for the println method; use Log.v.
public static final int VERBOSE = 2;
public static final int DEBUG = 3;
public static final int INFO = 4;
public static final int WARN = 5;
public static final int ERROR = 6;
public static final int ASSERT = 7;
二、Log日志打印的buffer_id
public static final int LOG_ID_MAIN = 0;
public static final int LOG_ID_RADIO = 1;
public static final int LOG_ID_EVENTS = 2;
public static final int LOG_ID_SYSTEM = 3;
public static final int LOG_ID_CRASH = 4;
三、主要成员方法
1. public static int v(String tag, String msg)
2. public static int d(String tag, String msg)
3. public static int i(String tag, String msg)
4. public static int w(String tag, String msg)
5. public static int e(String tag, String msg)
以上5个方法都是调用的print_native(),对于Log的各个level日志打印,他的日志打印bufferId使用Log_ID_MAIN。而SLOG各个level的日志打印也是调用的print_native(),只是它指定的bufferId使用Log_ID_SYSTEM。
6. public static native boolean isLoggable(String tag, int level);
7. public static native int println_native(int bufID, int priority, String tag, String msg);
以上两个方法是Log日志打印的最核心的方法,他们是jni调用c++方法,具体参考【四、JNI调用】。
四、JNI调用
- isLoggable()和println_native()对应的jni文件在/frameworks/base/core/jni/android_util_Log.cpp中。
- Log类中isLoggable()对应的JNI方法是android_util_Log_isLoggable(),代码如下:
static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
{
if (tag == NULL) {
return false;
}
const char* chars = env->GetStringUTFChars(tag, NULL);
if (!chars) {
return false;
}
jboolean result = isLoggable(chars, level);
env->ReleaseStringUTFChars(tag, chars);
return result;
}
static jboolean isLoggable(const char* tag, jint level) {
return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO);
}
该JNI方法最终调用/system/logging/liblog/properties.cpp中的__android_log_is_loggable()。该方法在第五部分介绍。
3. Log类中println_native()对应android_util_Log_println_native()
该方法会先对msg、bufID、tag做校验,然后调用/system/logging/liblog/logger_write.cpp中的__android_log_buf_write()实现日志的write。
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
4. 通过JNINativeMethod动态注册JNI方法。
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
};
int register_android_util_Log(JNIEnv* env)
{
//获取Log类
jclass clazz = FindClassOrDie(env, "android/util/Log");
//获取Log类中成员变量
levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I"));
levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I"));
levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I"));
levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I"));
levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I"));
levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));
return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));
}
该register_android_util_log()在AndroidRuntime.cpp中
static const RegJNIRec gRegJNI[] = {
...
REG_JNI(register_android_util_Log),
...
}
五、system/logging/liblog下相关分析
1. 常见的枚举类android_LogPriority的定义
路径:/system/logging/liblog/include/android/log.h
typedef enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;
其中,minimum_log_priority默认值是ANDROID_LOG_DEFAULT,当然minimum_log_priority可以修改。ANDROID_LOG_DEFAULT默认level是ANDROID_LOG_INFO。
2. properties.cpp中的__android_log_is_loggable()
路径:/system/logging/liblog/properties.cpp
int __android_log_is_loggable(int prio, const char*, int) {
int minimum_priority = __android_log_get_minimum_priority();
if (minimum_priority == ANDROID_LOG_DEFAULT) {
minimum_priority = ANDROID_LOG_INFO;
}
return prio >= minimum_priority;
}
判断当前prio等级的日志是否能打印,就是判断日志等级prio>=minimum_priority与否,大于最小level的日志均可以打印。
3. 常见的枚举类log_id的定义
路径:/system/logging/liblog/include/android/log.h
typedef enum log_id {
LOG_ID_MIN = 0,
/** The main log buffer. This is the only log buffer available to apps. */
LOG_ID_MAIN = 0,
LOG_ID_RADIO = 1,
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3, /** The system log buffer. */
LOG_ID_CRASH = 4,
LOG_ID_STATS = 5,
LOG_ID_SECURITY = 6, /** The security log buffer. */
LOG_ID_KERNEL = 7, /** The kernel log buffer. */
LOG_ID_MAX,
LOG_ID_DEFAULT = 0x7FFFFFFF
} log_id_t;
该结构体中的MIN和MAX长用来判断传入的日志bufferId是否有效。
4. __android_log_message结构体定义
路径:/system/logging/liblog/include/android/log.h
struct __android_log_message {
/** Must be set to sizeof(__android_log_message) and is used for versioning. */
size_t struct_size;
int32_t buffer_id; /** {@link log_id_t} values. */
int32_t priority; /** {@linkandroid_LogPriority} values. */
const char* tag;
const char* file; /** Optional file name, may be set to nullptr. */
uint32_t line; /** Optional line number, ignore if file is nullptr. */
const char* message; /** The log message itself. */
};
5. logger_write.cpp中的__android_log_buf_write()
int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
ErrnoRestorer errno_restorer;
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
return -EPERM;
}
__android_log_message log_message = {
sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, msg};
__android_log_write_log_message(&log_message);
return 1;
}
- 首先调用__android_log_is_loggable()判断该等级prio的日志是否能打印;
- 其次把参数封装成__android_log_message结构体的日志;注意:此处结构体中const char* file = nullptr,所以Android原生系统的日志是在buffer中而不持久化文件中。
- 最后调用__android_log_write_log_message()。
5. logger_write.cpp中的__android_log_write_log_message()
void __android_log_write_log_message(__android_log_message* log_message) {
ErrnoRestorer errno_restorer;
//对buffer_id判断有效性
if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
log_message->buffer_id != LOG_ID_CRASH) {
return;
}
//如果tag为空,取默认TAG
if (log_message->tag == nullptr) {
log_message->tag = GetDefaultTag().c_str();
}
#if __BIONIC__
if (log_message->priority == ANDROID_LOG_FATAL) {
android_set_abort_message(log_message->message);
}
#endif
//实际写日志的函数
logger_function(log_message);
}
static __android_logger_function logger_function = __android_log_logd_logger;
void __android_log_logd_logger(const struct __android_log_message* log_message) {
//把bufferID=LOG_ID_DEFAULT,赋值为LOG_ID_MAIN
int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;
//构建iovec结构体数组,长度为3,分别保存日志priority、tag、message。
struct iovec vec[3];
vec[0].iov_base =
const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
vec[0].iov_len = 1;
vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
vec[1].iov_len = strlen(log_message->tag) + 1;
vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
vec[2].iov_len = strlen(log_message->message) + 1;
//具体实现write log的函数
write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
}
static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
int ret;
struct timespec ts;
//不保存kernel日志
if (log_id == LOG_ID_KERNEL) {
return -EINVAL;
}
//获取系统时间
clock_gettime(CLOCK_REALTIME, &ts);
if (log_id == LOG_ID_SECURITY) {
if (vec[0].iov_len < 4) {
return -EINVAL;
}
ret = check_log_uid_permissions();
if (ret < 0) {
return ret;
}
if (!__android_log_security()) {
/* If only we could reset downstream logd counter */
return -EPERM;
}
} else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
if (vec[0].iov_len < 4) {
return -EINVAL;
}
}
ret = LogdWrite(log_id, &ts, vec, nr);
PmsgWrite(log_id, &ts, vec, nr);
return ret;
}