Log类的路径在/frameworks/base/core/java/android/util/Log.java

Slog类的路径在/frameworks/base/core/java/android/util/Slog.java


目录

一、Log的日志等级

二、Log日志打印的buffer_id

三、主要成员方法

四、JNI调用

五、system/logging/liblog下相关分析

1. 常见的枚举类android_LogPriority的定义

2. properties.cpp中的__android_log_is_loggable()

3. 常见的枚举类log_id的定义

4. __android_log_message结构体定义

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调用

  1. isLoggable()和println_native()对应的jni文件在/frameworks/base/core/jni/android_util_Log.cpp中。
  2. 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;

该结构体中的MINMAX长用来判断传入的日志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为空,取默认TAGif (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;
}

Android Log和Slog类详解--Android 12相关推荐

  1. Android - Vibrator及VibrationEffect类详解

    一.Vibrator类详解 在API级别1(Android1.0)中添加 1.基本概念 在设备上操作振动器的类. 如果您的进程退出,您启动的任何振动都将停止. 必须使用带有Vibrator.class ...

  2. android 数据文件存储,实例详解Android文件存储数据方式

    总体的来讲,数据存储方式有三种:一个是文件,一个是数据库,另一个则是网络.下面通过本文给大家介绍android文件存储数据方式. 1.文件存储数据使用了java中的io操作来进行文件的保存和读取,只不 ...

  3. Android 视频图片 轮播,详解android 视频图片混合轮播实现

    循环添加视频view  图片view for (int i = 0 ;i if (beansarraylist.get(i).gettype()==1){ videoplayer = new nice ...

  4. android 最新消息滚动,Android 滚动操作Scroller类详解

    Scroller这个类理解起来有一定的困难,刚开始接触Scroller类的程序员可能无法理解Scroller和View系统是怎么样联系起来的.我经过自己的学习和实践,对Scroller的用法和工作原理 ...

  5. android用sax解析xml,详解android使用SAX解析XML文件

    解析XML的方式有很多种,大家比较熟悉的可能就是DOM解析. DOM(文件对象模型)解析:解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以根据DOM接口来操作这个树结构了. 优点:整个 ...

  6. android js接口调用方法,详解Android JS相互调用

    最近在研究Android.JS相互调用,之前没怎么接触过,只知道loadUrl()就可以加载一个网页了,研究过之后发现Android可以调JS,JS也可以调Android原生控件,很开心啊.下面小编就 ...

  7. android sdk安装过程,图文详解Android 3.0 SDK安装教程

    [51CTO编者按]我们已经为喜欢Android 3.0的朋友提供Android 3.0 SDK下载,本文我们将向大家介绍Android 3.0 SDK安装教程,本教程与 玩模拟器需要比较好的电脑配置 ...

  8. android教程 - android ui 介绍,多图详解 “Android UI”设计官方教程

    我们曾经给大家一个<MeeGo移动终端设备开发UI设计基础教程>,同时很多朋友都在寻找Android UI开发的教程,我们从Android的官方开发者博客找了一份幻灯片,介绍了一些Andr ...

  9. android sd卡名称,科普详解Android系统SD卡各类文件夹名称

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 15.moji:墨迹天气的缓存目录. 16.MusicFolders:poweramp产生的缓存文件夹. 17.openfeint:openfeint的缓 ...

最新文章

  1. FPGA基础知识极简教程(8)详解三态缓冲器
  2. 圣杯布局简单结构代码!
  3. python讲解from ctypes import *调用C语言动态链接库
  4. 知识中台,驱动产业智能化升级
  5. 亚马逊低调收购Biba 或下月发布视频消息服务
  6. SpringMVC Mybatis Shiro RestTemplate的实现客户端无状态验证及访问控制【转】
  7. cytoscape插件下载_Cytoscape
  8. 公有云退款流程及政策--退款规则及退款流程(阿里云 华为云) --2020-09-03
  9. java的super_Java中的Super()
  10. python print tab_python print tab_Python 字符串 expandtabs() 方法
  11. 漏洞防御方案_越权漏洞原理及防御方案
  12. pandas—pandas.DataFrame.iterrows的使用
  13. 数据结构-03-队列
  14. 项目验收文档模板(一)
  15. 成语答题小程序 开源的成语答题小程序
  16. 如何根据DBC计算CAN与CANFD的负载率
  17. 数字光栅投影技术——相移轮廓术(PSP)
  18. 将centos7打造成桌面系统centos
  19. 中国100句绝美爱情诗
  20. 【论文精读】2016-CVPR-Learning temporal regularity in video sequences

热门文章

  1. 继BAT之后 第四大巨头是谁:京东、360还是小米?
  2. 社区团购大爆发,遵义微红科技社区团购系统助您站在风口!
  3. 安装apk文件时出现错误“程序包似乎已损坏”
  4. 局域网arp攻击_ARP攻击原理
  5. 人有三急!这份如厕指南,能帮你国庆在外快速找到厕所
  6. Unsupported major.minor version 52.0 (unable to load class org.dppc.prototype.AppListener)
  7. 基于 RFID 技术的飞机维修工具管理系统
  8. java中txt文件在线显示中文乱码问题
  9. 手动搜网模式有缺陷么?
  10. oracle12cr2发布时间,Oracle 12cR2初体验(r11笔记第91天)