Android Log系统介绍 (基于Android N)

原文使用有道云笔记创作, 看这个: http://note.youdao.com/noteshare?id=82f88b1c82652b80c27d54aad55af035 ```引言> Android 的log,从操作系统分层上来讲,可以分为“Kernel Log”和“User Log”(这是我个人引入的术语)。> 所谓“Kernel Log”就是操作系统内核打印的...
摘要由CSDN通过智能技术生成

原文使用有道云笔记创作, 看这个: http://note.youdao.com/noteshare?id=82f88b1c82652b80c27d54aad55af035

 


```
引言
> Android 的log,从操作系统分层上来讲,可以分为“Kernel Log”和“User Log”(这是我个人引入的术语)。

> 所谓“Kernel Log”就是操作系统内核打印的log。内核里调用printk等接口请求输出kernel log。
  kernel log最后会被打印到/dev/kmsg文件上。可以通过dmesg查看到

> 所谓“User Log”分为2部分。
  一类是Linux的标准输出设备中打印的log(stderr/stdout).
  另一类是android特有的log流程。如通过android.util.Log类打印的log,eventslog, ALOG() native层log打印.
  
  他们都可以通过logcat看到.

本文基于Android N源码, 对Android的log机制做介绍.
```

先给出一张Android Log系统的总图

![image](https://note.youdao.com/yws/public/resource/61a8527040499b2a0ff58d2fe3aa7bf9/xmlnote/WEBRESOURCE201e2aad89277aeb65c08a26c9b32701/19289)


# 1 Android特有Log流程
```
// java
import android.util.Log;

Log.d("cwj", "test log");
```
==android.util.Log== 是在做Android开发中最常用的log输出手段.这里输出的log, 我们通过"adb logcat"或"adb shell logcat"命令获取.

**那么从"Log.d("cwj", "test log");" 到"logcat"之间到底发生了什么呢?**

```
// C/C++

#define LOG_TAG "fingerprintd"

ALOG(LOG_VERBOSE, LOG_TAG, "lockout\n");

ALOGE("Invalid callback object");

ALOGD("onAcquired(%d), duplicatedFingerId(%d)", 1, 2);
```
**对于Native Code中的 ALOG 等的log打印 到logcat之间, 又发生了什么呢?**

## 1.1 android.util.Log 和 android.util.writeEvent
### 1.1.1 android.util.Log
java类Log的源码在 "frameworks/base/core/java/android/util/Log.java"

Lod中的 Log.d() / Log.v() 等打印不级别的函数, 最终都走到 ==println_native()== native函数.
```
    public static int v(String tag, String msg) {
        return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
    }


    public static int d(String tag, String msg) {
        return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
    }
    
    /** @hide */ public static native int println_native(int bufID,
            int priority, String tag, String msg);

```

println_native 的实现在 "/frameworks/base/core/jni/android_util_Log.cpp"
```
/*
 * JNI registration.
 */
static const JNINativeMethod gMethods[] = {
    /* name, signature, funcPtr */
...
    { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) 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)
{
    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;
}
```
println_native() 对应的jni方法是 ==android_util_Log_println_native()==.

android_util_Log_println_native()很简单,就是简单的Log级别检查后, 就调用 ==__android_log_buf_write()== 做进一步处理.

__android_log_buf_write() 的声明在 "/system/core/include/log/log.h":
```
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
```
__android_log_buf_write() 的定义(实现)在 "/system/core/liblog". 

发现liblog中有多个 __android_log_buf_write() 的实现:
```
logd_write.c
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
  ...

logd_write_kern.c
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
  ...

logger_write.c
LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
  ...
```
那么我们用到的到底是哪个呢? 具体分析在[1.3 /system/core/liblog]介绍. 


### 1.1.2 android.util.writeEvent
分析 writeEvent 到 liblog 的流程高度相似, 细节就不展开了, 这里直接贴下最终的结论:
```

/frameworks/base/core/java/android/util/EventLog.java           writeEvent()  
 --> /frameworks/base/core/jni/android_util_EventLog.cp         android_btWriteLog_xx()
   --> /system/core/include/log/logger.h --> log.h              android_btWriteLog()
    --> /system/core/liblog/logger_write.c                      __android_log_btwrite() -> write_to_log()
```

==__android_log_btwrite()== 后面调用到 ==write_to_log()==. 前面提到的 __android_log_buf_write() 也是直接调用到 write_to_log() .

即结论是: android.util.EvnentLog 跟 Android.util.Log 打印日志的流程相同, 都是转到 /system/core/liblog/logger_write.c 去处理.


android.util.writeEvent.writeEvent() --> android_btWriteLog_xx() (/frameworks/base/core/jni/android_util_EventLog.cpp)
--> android_btWriteLog() (/system/core/include/log/log.h)  -->  __android_log_btwrite() (/system/core/liblog/logger_write.c)  --> write_to_log() 


## 1.2 Native Code : ALOG / ALOGE / ALOGD ..
我们还会看到一些native code(主要是C/C++)也有打印log:
```
// xxx.c / xxx.cpp

#define LOG_TAG "fingerprintd"

ALOG(LOG_VERBOSE, LOG_TAG, "lockout\n");

ALOGE("Invalid callback object");

ALOGD("onAcquired(%d), duplicatedFingerId(%d)", 1, 2);
```

这些形如 "[ASR]LOG[VDIWE]" 的函数的声明在 "/system/core/include/log/log.h":
```
// ALOGD/ALOGE ---> ALOG  ---> LOG_PRI  ---> android_printLog ---> __android_log_print()


/*
 * Basic log message macro.
 *
 * Example:
 *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
 *
 * The second argument may be NULL or "" to indicate the "global" tag.
 */
#ifndef ALOG
#define ALOG(priority, tag, ...) \
    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif

/*
 * Simplified macro to send an error log message using the current LOG_TAG.
 */
#ifndef ALOGE
#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif


/*
 * Simplified macro to send a debug log message using the current LOG_TAG.
 */
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_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() 函数:

ALOGD/ALOGE ---> ALOG  ---> LOG_PRI  ---> android_printLog ---> __android_log_print()


而 ==__android_log_print()== 函数的实现在 "/system/core/liblog":
```
// 只列出其中一个实现.

// /system/core/liblog/logger_write.c

LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
                                          const char *msg)
{
    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}


```
__android_log_print() 函数只是 __android_log_buf_write() 的简单包装.

所以, 形如 "[ASR]LOG[VDIWE]" 的的log输出, 最终跟 android.util.Log 一样, 也是走到 "/system/core/liblog"的 __android_log_buf_write() 处理.


## 1.3 /system/core/liblog
上面2节都提到, 关键函数 __android_log_buf_write() . 以及遗留了一个问题 "__android_log_buf_write() 的多个实现, 到底哪个才是最终的实现? 
结论是 "有 "LIBLOG_ABI_PUBLIC" 宏修饰的, 是最终被使用的实现."
```
// /system/core/liblog/logger_write.c

LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
                                              const char *tag, const char *msg)
{
    // ....

    return write_to_log(bufID, vec, 3);
}
```
那么怎么得道的这个结论呢?

__android_log_buf_write() 分别在 "logd_write.c" / "logd_write_kern.c" / "logger_write.c" 三个文件都有实现.
```
logd_write.c
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
  ...

logd_write_kern.c
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
  ...

logger_write.c
LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
  ...
```

根据liblog模块的mk文件 "/system/core/liblog/Android.mk", 知道前2个都没有参与编译. 只有第三个文件 "logger_write.c" 参与了编译.

另外结合阅读 liblog 模块的代码, 也可以确认, logd_write.c 和 logd_write_kern.c 都是历史残留代码.
在 [1.6 Android 4.4 liblog] 对旧的log逻辑做一些分析.


回到 logger_write.c 的 __android_log_buf_write() 继续跟进.
```
// /system/core/liblog/logger_write.c

LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
                                              const char *tag, const char *msg)
{
    struct iovec vec[3];
    char tmp_tag[32];

    if (!tag)
        tag = "";

    /* XXX: This needs to go! */
    if ((bufID != LOG_ID_RADIO) &&
         (!strcmp(tag, "HTC_RIL") ||
        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
        !strcmp(tag, "AT") ||
        !strcmp(tag, "GSM") ||
        !strcmp(tag, "STK") ||
        !strcmp(tag, "CDMA") ||
        !strcmp(tag, "PHONE") ||
        !strcmp(tag, "SMS"))) {

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值