配套系列教学视频链接:
说明
系统:Android10.0
设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)
前言
Android系统中日志基本都是通过log系统来实现, 在代码中可以通过相应的接口来输出不同等级的日志, 不同的缓冲区有不同的API, 等级有Verbose, Debug,Info,Warn,Error。本章节主要讲解log日志的API。
一, 日志系统框架
之前的的课程中讲解了整体框架, 此处贴图让大家提升印象:
系统也提供的Java和C++/C语言不同的API:
- 在java层调用import android.util.Log,在需要打印Log的地方执行Log.v,Log.d,Log.i,Log.w,Log.e.
- c、c++层调用:在c,c++层包含此头文件:
老版本包含 #include <cutils/log.h>,代码调用LOGV,LOGD,LOGI,LOGW,LOGE
新版本包含 #include <log/log.h>, 代码调用ALOGV,ALOGD,ALOGI,ALOGW,ALOGE。
二, Android 不同缓冲区的API
Android系统中包含不同缓冲区, 特定缓冲区用的API不同:
main:查看主日志缓冲区(默认),不包含系统和崩溃日志消息。
system:查看系统日志缓冲区(默认)。
radio:查看包含无线装置/电话相关消息的缓冲区。
events:查看已经过解译的二进制系统事件缓冲区消息。
crash:查看崩溃日志缓冲区(默认)。
all:查看所有缓冲区。
default:报告 main、system 和 crash 缓冲区。
Main缓冲区API(JAVA/C/C++):
C/C++:
ALOGV(), ALOGD(),ALOGI(),ALOGW(),ALOGE()
Log.java
Log.v(),Log.d(),Log.i(),Log.w(),Log.e(),
Radio缓冲区API(JAVA/C/C++):
C/C++
RLOGV(), RLOGD(),RLOGI(),RLOGW(),RLOGE()
当然还有一种条件日志: ALOGD_IF(),RLOGD_IF(),
RLog.java: 普通app是无法使用该接口的
RLog.v(),RLog.d(),RLog.i(),RLog.w(),RLog.e(),
System缓冲区API(JAVA): 普通app是无法使用该接口的
import android.util.Slog; //frameworks/base/core/java/android/util/Slog.java
Slog.d(TAG, “xxxx”);
Events缓冲区API(JAVA):
import android.util.EventLog;
int writeEvent(int tag, Object... list);
使用:EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
Crash缓冲区:主要是由system/core/debuggered守护进程打印(如输出tombstone文件的内容)
01-12 03:52:39.196 22371 22371 F DEBUG #78 pc 0028f6ef /
system/core/debuggerd/libdebuggerd/utility.cpp
_LOG()==> __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, msg.c_str());
三,所有API的底层实现
虽然缓冲区不同,API不同,其实内部实现都会有一些通用参数, 如:
java层buferID Log.LOG_ID_SYSTEM
C/C++层buferID: LOG_ID_RADIO
C/C++层Log级别: ANDROID_LOG_DEBUG
C/C++所有接口实现在liblog中, 可以在Android.mk或者Android.bp中加入liblog, 并引入头文件和宏定义:
#define LOG_TAG "xxxx"
#include <log/log.h>
而system/core/include/log/log.h 有如下包含, 说明不同缓冲区的接口都被包含到了log.h中:
各个缓冲区的写日志的API其实最终是调用:
int __android_log_print(int prio, const char* tag, const char* fmt, ...)
|//system/core/liblog/logger_write.cpp
int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg)
这个函数就没有可变参数
在NDK编写jni时, 你会常看见如下定义, 其实就是最终调用了上面的统一接口:
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__) // 定义LOGE类型
四:总结
不同语言使用不通的API, 其实都不是太复杂, 最终都是写入到不同缓冲区中。