Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性-[Android取经之路]

摘要:本节主要来讲解Android10.0 日志系统的logd、logcat相关指令说明、日志分类和常用日志属性

阅读本文大约需要花费15分钟。

文章首发微信公众号:IngresGe

专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

欢迎关注我的公众号!

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

  1. Android系统架构
  2. Android是怎么启动的
  3. Android 10.0系统启动之init进程
  4. Android10.0系统启动之Zygote进程
  5. Android 10.0 系统启动之SystemServer进程
  6. Android 10.0 系统服务之ActivityMnagerService
  7. Android10.0系统启动之Launcher(桌面)启动流程
  8. Android10.0应用进程创建过程以及Zygote的fork流程
  9. Android 10.0 PackageManagerService(一)工作原理及启动流程
  10. Android 10.0 PackageManagerService(二)权限扫描
  11. Android 10.0 PackageManagerService(三)APK扫描
  12. Android 10.0 PackageManagerService(四)APK安装流程

《日志系统篇》

  1. Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
  2. Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
  3. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
  4. Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现​

《Binder通信原理》

  1. Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
  2. Android10.0 Binder通信原理(二)-Binder入门篇
  3. Android10.0 Binder通信原理(三)-ServiceManager篇
  4. Android10.0 Binder通信原理(四)-Native-C\C++实例分析
  5. Android10.0 Binder通信原理(五)-Binder驱动分析
  6. Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
  7. Android10.0 Binder通信原理(七)-Framework binder示例
  8. Android10.0 Binder通信原理(八)-Framework层分析
  9. Android10.0 Binder通信原理(九)-AIDL Binder示例
  10. Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
  11. Android10.0 Binder通信原理(十一)-Binder总结

  《HwBinder通信原理》

  1. HwBinder入门篇-Android10.0 HwBinder通信原理(一)
  2.  HIDL详解-Android10.0 HwBinder通信原理(二)
  3. HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
  4. HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
  5. HwServiceManager篇-Android10.0 HwBinder通信原理(五)
  6. Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
  7. Native层HIDL服务的获取原理-Android10.0 HwBinder通信原理(七)
  8. JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)
  9. JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)
  10. HwBinder驱动篇-Android10.0 HwBinder通信原理(十)
  11. HwBinder原理总结-Android10.0 HwBinder通信原理(十一)

《编译原理》

  1. 编译系统入门篇-Android10.0编译系统(一)
  2. 编译环境初始化-Android10.0编译系统(二)
  3. make编译过程-Android10.0编译系统(三)
  4. Image打包流程-Android10.0编译系统(四)
  5. Kati详解-Android10.0编译系统(五)

1.概述

    在程序开发中,日志是必不可少的一个调试手段,Android的开发亦是如此。

    在Android的开发中,我们是通过LOGD\SLOGD等方式进行日志的写入,然后通过 logcat 读取相关的日志,但是日志是如何写入和读取的,底层的操作是什么,有时候没有深入研究。

    本节重点从底层源码级来分析一下Android的日志读写原理。

   在Android5.0(Android-L)之前,log由kernel的环形 buffer 保存,在Android5.0 之后,log保存在用户空间,通过Socket进行访问。

    在Android5.0之后,引入了Logd的守护进程用来进行日志的读写操作。

早期的Kernel ring buffer的原理可以参考 老罗-罗升阳的《Android日志系统驱动程序Logger源代码分析》

https://blog.csdn.net/luoshengyang/article/details/6595744

    本节主要来分析logd、logcat的相关实现原理。

2.核心源码

/frameworks/base/core/java/android/util/Log.java
/frameworks/base/core/java/android/util/SLog.java
/frameworks/base/core/java/android/util/EventLog.java
/frameworks/base/core/jni/android_util_Log.cpp
/system/core/logd/main.cpp
/system/core/logd/LogReader.cpp
/system/core/logd/LogWriter.java
/system/core/logcat/logcat.cpp
/system/core/liblog/logd_writer.cpp
/system/core/liblog/logd_reader.cpp

3.logcat相关指令说明

    手机连上电脑,安装adb驱动后,打开开发者模式,选择"USB调试",即可执行adb 命令

 

3.1 命令行语法

    要通过 adb shell 运行 Logcat,一般用法如下:

    [adb] logcat [<option>] ... [<filter-spec>] ...

 

3.2 指令说明

    可以通过 "adb logcat --help" 来看logcat支持的指令。

    详细信息参考  《Logcat 命令行工具》

https://developer.android.google.cn/studio/command-line/logcat

3.3 日志过滤输出

    Android日志分为如下7个等级

  • V:详细(最低优先级)--(Verbose:2)

  • D:调试 --(Debug:3)

  • I :信息 -- (Info:4)

  • W:警告 --(Warning:5)

  • E:错误 --(Error:6)

  • F:严重错误 --(Fatal:7)

  • S:静默(最高优先级,绝不会输出任何内容)--(Silent)

    我们在调试日志时,可以根据不同的等级来控制日志的输出

    下面这是一条正常输出的Android日志

    日志:02-05 12:44:15.357 17533 17545 D ActivityThread: caller system = false

    日志格式:<日期> <时间> <PID>  <TID>  <日志等级> <日志标签TAG>  <日志内容>

    

我们可以通过过滤器只输出相应等级以下的日志:

1)例如:adb logcat  *:I

    指令含义:输出日志等级为Info以上的日志,即只输出Info、Error、Fatal、Silent的日志, Debug、Verbose的日志不会输出

 

2)例如:adb logcat ActivityManager:E ActivityThread:I *:S

    指令含义:该表达式会抑制除标记为“ActivityManager”、优先级不低于“Error”的日志消息,以及标记为“ActivityThread”、优先级不低于“Info”的日志消息以外的所有其他日志消息。

 

3)例如:adb logcat ActivityThread:E *:S

    指令含义:只输出标签为ActivityThread 且日志等级大于等于Error的日志,即只输出ActivityThread的 Error、Fatal的日志

 

3.4 日志输出格式

    除标记和优先级外,日志消息还包含许多元数据字段。您可以修改消息的输出格式,以便它们显示特定的元数据字段。为此,您可以使用 -v 选项,并指定下列某一受支持的输出格式。

  • brief:显示优先级、标记以及发出消息的进程的 PID。

  • long:显示所有元数据字段,并使用空白行分隔消息。

  • process:仅显示 PID。

  • raw:显示不包含其他元数据字段的原始日志消息。

  • tag:仅显示优先级和标记。

  • thread::旧版格式,显示优先级、PID 以及发出消息的线程的 TID。

  • threadtime(默认值):显示日期、调用时间、优先级、标记、PID 以及发出消息的线程的 TID。

  • time:显示日期、调用时间、优先级、标记以及发出消息的进程的 PID。

指令: [adb] logcat [-v <format>]

例如:adb logcat -v threadtime

注意:-v每次只能使用一种格式,默认情况下的threadtime格式即能满足我们现在的需求

 

3.5 日志缓冲区

    Android 日志记录系统为日志消息保留了多个环形缓冲区,而且并非所有的日志消息都会发送到默认的环形缓冲区。要查看其他日志消息,您可以使用 -b 选项运行 logcat 命令,以请求查看备用的环形缓冲区。您可以查看下列任意备用缓冲区:

  • radio:查看包含无线装置/电话相关消息的缓冲区。

  • events:查看已经过解译的二进制系统事件缓冲区消息。

  • main:查看主日志缓冲区(默认),不包含系统和崩溃日志消息。

  • system:查看系统日志缓冲区(默认)。

  • crash:查看崩溃日志缓冲区(默认)。

  • all:查看所有缓冲区。

  • default:报告 main、system 和 crash 缓冲区。

用法1:adb logcat -b main

说明1:上述指令只输出main缓冲区的日志。

用法2:adb logcat -b main,radio,system

说明2:上述指令输出 main、radio、system三个缓冲区的日志

 

4. 日志系统相关属性说明

属性

说明

log.tag.*

setprop log.tag.MyApp D

用来设置应用日志TAG的等级,上面是输出MyApp的Debug日志,主要控制的是isLoggable(MyApp,Debug) 这种方式控制的日志

手动设置后,重启失效

ro.logd.auditd

启动selinux审核守护进程

ro.logd.auditd.dmesg

selinux审核信息发送到dmesg log

ro.logd.kernel

cat “/proc/kmsg” 节点,用来读取kernel日志

ro.logd.size

所有日志缓存区大小的默认大小,默认为256K,可实时修改,重启失效

ro.logd.timestamp

修改日志时间戳,可以实时修改,重启失效

ro.logd.filter

日志黑白名单是否生效,disable为失效,enable为生效

logd.statistics

使能logcat -S statistics,在输出中包含统计信息,以帮助您识别和定位日志垃圾信息发送者

persist.logd.timestamp

修改日志时间戳,只能编译版本的时候修改,或者手机root后修改,重启继续生效

persist.logd.size

所有日志缓存区大小的默认大小,默认为256K只能编译版本的时候修改,或者手机root后修改,重启继续生效

persist.logd.size.main

main日志缓冲区大小,默认为256K

persist.logd.size.system

system日志缓冲区大小,默认为256K

persist.logd.filter

日志黑白名单是否生效,disable为失效,enable为生效,

通过adb logcat -p 来读取黑白名单;

通过logcat -P '<white_and_blacklist>' 来设置黑白名单,通过PID\UID来进行控制

persist.log.tag

setprop persist.log.tag Debug

控制Debug以上等级的日志输出,只有在版本预制,或者root后,设置生效,重启也生效

ro.logd.kernel

setprop ro.logd.kernel true

控制内核日志输出到logd的buffer中,通过lgocat抓取

ro.logd.auditd

setprop ro.logd.auditd true

控制selinux日志输出到logd的buffer中,通过lgocat抓取

 

我们在日常调试或者CTS测试时,会遇到日志丢失或者不全的情况,主要原因是日志量很大,但是日志缓冲区很小,此时只要把日志的缓冲区调大即可。

方法1: setprop ro.logd.size 5120     即把日志缓冲区都调整为5M

方法2:开发者模式->日志记录缓冲区大小-> 选择相应的缓冲区大小,可以选择64K -16M等5个大小

 

5. 日志分类

Android10.0上日志分为8类:

ID

对应值

说明

LOG_ID_MAIN

 

0

main日志缓冲区,这是应用程序唯一可用的日志缓冲区,在应用框架层提供了android.util.Log接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏LOGV、LOGD、LOGI、LOGW、LOGE用来写入main类型的日志。

LOG_ID_RADIO

1

查看包含无线装置/电话相关消息的日志,可以调用android.telephony.Rlog进行打印

LOG_ID_EVENTS

2

类型为events的日志是用来诊断系统问题的,在应用框架层提供了android.util.EventLog接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏LOG_EVENT_INT、LOG_EVENT_LONG、LOG_STRING用来写入event类型的日志。

LOG_ID_SYSTEM

3

类型为system的日志是系统级别的,在应用框架层提供了android.util.SLog接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏SLOGV、SLOGD、SLOGI、SLOGW、SLOGE用来写入system类型的日志。

LOG_ID_CRASH

4

应用或者进程crash日志缓冲区

LOG_ID_STATS

5

统计日志缓冲区

LOG_ID_SECURITY

6

安全日志缓冲区

LOG_ID_KERNEL

7

kernel日志缓冲区

 

我们常用的日志缓冲区为:main、radio、system、events、crash

另外内核的日志,主要是输出到/proc/kmsg, 通过 cat /proc/kmsg 获取内核日志。

 

下一节我们一起来看看<Android 日志系统的架构分析>

微信公众号:IngresGe

 

 

  • 13
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值