当前位置: 首页 > news >正文

Android实战经验篇-log工具

详细代码实现及系列文章请转如下链接

Android实战经验篇-系列文章汇总

Android Display Graphics系列文章-汇总

一、基础知识

1.1 Logging简述

我们写的第一个计算机C程序一般是printf(“Hello world!”);这就是一个log输出。Linux内核有Kernel log以及配套的Log工具,Android系统中也设计了一套日志系统方便应用程序的Debug。

Logging由于其简单快捷,行之有效,并且各种编程语言和操作系统都提供了对Logging的支持,以便跟踪程序行为,快速定位问题所在,所以其一直是调试过程中应用最普遍,使用频率最高的手法。

但是,一个基于Android系统的手机平台,系统的各个部分都有不同的log机制,例如,Kernel部分沿用了Linux Kernel的Log机制;Android部分实现了4个buffer用来分别对Android应用(包含Native层的应用和Java层的应用)做Logging;而搭配的modem则有另外的机制和工具进行Logging。当然,除此之外蓝牙,网络等等也有自己的机制。

而对应的获取log的工具也是种类繁多的,这往往会给大家带来困扰,在什么时候用什么样的工具抓取哪些log呢?这事关问题处理的效率。

本文将专注于Kernel/Android/Modem各个部分Log机制以及配套工具的使用,针对用到的log工具做出简明介绍,以让大家了解各个Log工具的使用场景以及应用上的局限性,使大家能够在遇到问题的时候准确的拿到对应的Log来做分析。

1.2 Kernel Log

开发Linux device Driver或者跟踪调试内核行为的时候经常要通过Log API来trace整个过程,Kernel API printk() 是整个Kernel Log机制的基础API,几乎所有的Log方式都是基于printk来实现的。

利用printk,我们可以像开发C应用中printf接口一样印log,最简单的方式,我们只要把需要打印的内容传给printk函数就可以了,如下:

printk("This is just an example!!");

当然使用printk还有一些需要注意的地方,在详细讲述之前我们先分析一下printk()实现,其流程大致如下图所示:

从上图可以看出,printk的流程大致可以分为两步:

1、将所有Log输出到内核的Log buffer,该Log Buffer是一个循环缓冲区,其地址可以在内核中用log_buf变量访问。

2、根据设定的Log级别决定是否将Log输出到Console。

所以我们打印的log会走向两个位置:

1、Log Buffer,该Buffer的内容可以在user space通过/proc/kmsg来访问。

2、Console,Console的实现可以有很多,目前我们用到的有UART Console和RAM Console。拿UART Console来说,通向UART Console的log会在对应的UART端口打印出来。而RAM Console也是我们一种重要的Debug手段。

对于console log,不可避免的对系统的性能有损失,尤其是像UART Log这种收到硬件传输效率影响的。所以对于console log设置了两道关卡。第一个是对Log级别进行过滤,只能输出高优先级的log;第二个是为UART Console设置单独的开关,在不必要的时候可以将其关闭以提高系统性能。

在这里我们提到了Log Level的概念,那什么是Log Level呢?

LOG 优先级

Log Level,也叫做Log优先级,为了能够区分各个Log的重要程度,printk机制设计了若干Log级别以作区分。当我们读取log buffer (adb shell cat /proc/kmsg)的时候可以看到如下的log,在每一行Log的前面有一对尖角号,里面包含一个数字,这个数字即为这行Log优先级。

01-01 00:02:59.697     0     0 W kmsg    : <4>[   24.512158][  T303] msm-dai-q6-hdmi soc:qcom,msm-dai-q6-dp: DAI driver id is not set
01-01 00:02:59.702     0     0 W kmsg    : <4>[   24.513851][  T303] msm-dai-q6-hdmi soc:qcom,msm-dai-q6-dp1: ASoC: sink widget Display Port1 Playback overwritten
01-01 00:02:59.710     0     0 W kmsg    : <6>[   24.524825][    C0] CAM_ERR: CAM-CCI: cam_cci_irq: 304 Base:00000000ff02efc8,cci: 1, M0_Q1 NACK ERROR: 0x10000000
01-01 00:02:59.714     0     0 W kmsg    : <6>[   24.525221][  T916] CAM_ERR: CAM-CCI: cam_cci_read: 1389 
01-01 00:02:59.755     0     0 W kmsg    : <6>[   24.570790][ T1117] ipa-wan ipa3_lcl_mdm_ssr_notifier_cb:3037 IPA BEFORE_POWERUP handling is complete
01-01 00:02:59.880     0     0 W kmsg    : <3>[   24.681150][ T1126] jack_detect_work_events val = 1
01-01 00:02:59.924     0     0 W kmsg    : <6>[   24.738219][ T1360] binder: 1360:1360 ioctl 40046210 7fc2d97ef0 returned -22

尖括号中橙色字体就是log的打印等级;

完整的8个级别的定义可以参考下表,值越小级别越高:

宏定义

级别

描述

KERN_EMERG

"<0>"

紧急信息,此信息会引起系统崩溃

KERN_ALERT

"<1>"

提示要马上采取某些行动

KERN_CRIT

"<2>"

关键信息,通常有严重的软件或者硬件问题发生了

KERN_ERR

"<3>"

通常用来报告错误,例如设备驱动通常会用来报告硬件操作失败等

KERN_WARNING

"<4>"

警告信息,用来警告那些并不会造成严重的系统异常的问题

KERN_NOTICE

"<5>"

用于正常但是值得注意的情况,比如大量安全相关的log

KERN_INFO

"<6>"

信息,许多驱动程序都会在硬件启动的时候使用这个级别打印Log

KERN_DEBUG

"<7>"

用于调试信息的打印

那优先级是怎么应用的呢?

我们可以为将要打印的log指定优先级,举例如下,可以在我们要打印的log前面简单的添加上Log优先级的宏定义即可,这个优先级在printk API里面会去解析处理,以判断是否要打印到console中去。

printk(KERN_ERR"This is an error message!!");

如果不指定优先级会怎样呢?

如果在印Log的时候不指定Log的优先级,printk会为这行Log采用默认的优先级。通常系统默认的优先级是4,即warning级别。

系统默认的优先级可以通过读取/proc文件来得到,如下所示,其中读回来的第2个参数即为未指定Log Level的时候printk默认的Log级别。

E:\>adb shell cat /proc/sys/kernel/printk
4       6       1       7

/proc/sys/kernel/printk里面的参数意义是什么?

前面我们使用cat读取了/proc/sys/kernel/printk里面的内容,读取的这4个数字的含义分别是:

1.第一个参数表示console log level,即只有优先级大于这个级别的Log才可以打印到Console。

2.第二个参数表示默认Log级别,即打印Log未明确指定Log level的时候默认采用的Log级别。

3.第三个参数表示最小可用的Log Level,用于do_syslog()系统调用。

4.第四个参数表示默认的Console Log Level,未找到使用的地方。

Console Log 输出控制

从前面的图例以及讲述都有提到,console_loglevel 决定了哪些级别的log可以输出到console。而console_loglevel的值可以通过 /proc/sys/kernel/printk 来读取出来。

除此之外,我们还可以通过/proc/sys/kernel/printk设置console_loglevel来达到控制 console log 输出的目的,方法如下(修改这个参数需要有root权限):

E:\>adb shell cat /proc/sys/kernel/printk
4       6       1       7
E:\>adb shell "echo 8 > /proc/sys/kernel/printk"
E:\>adb shell cat /proc/sys/kernel/printk
8       6       1       7

上面echo 8 一行命令将console_loglevel设置8,即所有级别的log(因为定义的最低优先级的Log Level是7)都可以输出到console。当然通过这个命令也可以禁止一些低优先级的log输出到console,只要将console_loglevel的值设置小一些即可。

UART Console 的控制

对于UART Console单独设置了开关主要是因为其对系统性能的影响比较大,因为UART Console是同步的方式通过硬件以固定的传输速率印Log,如果Log量比较大的时候,印Log不可避免会花费系统较多的时间,这样就会引起较多的Performance问题,如UI卡顿等。另外由于往UART Console印Log会关闭中断,严重的时候可能会引起系统无法响应或者重启。

也正因为此,我们在user版本上面默认是关闭UART Console Log的。

那么如何在runtime控制UART Console 的打开和关闭呢?可以使用如下命令(执行该命令需要有root权限):

MTK上可以通过如下命令控制

E:\>adb shell "echo 1 > /sys/module/printk/parameters/disable_uart"  
E:\>adb shell "echo 0 > /sys/module/printk/parameters/disable_uart"  

通过将disable_uart参数设置为1来关闭UART Console,反之通过将disable_uart参数设置为0来打开UART Console。

1.3 Android Log

任何一本讲述Android开发的教科书在讲如何用模拟器调试应用程序的时候都会用到Log类的Java API以及配套工具logcat或者DDMS。这是Android系统里面单独设计的一整套Log机制,与Kernel Log机制类似,也有优先级 (Priority) 的概念,虽然优先级的定义稍有不同。除此之外,还对Log添加了对应的TAG,以此来对Log的类别作区分。后面我们将详细讲述该Logging机制。

Android Logging System Architecture

Android Logging System对Java层以及Native层都提供了对应的API,我们通过下图先看一下Android Logging System整体架构。

从上图我们可以看出

1. 在 Kernel 层,设计了4个 Logger 设备及相应的驱动程序,这4个 Logger 设备分别采用了一块内存区域作为循环缓冲区,用于存放 main/system/event/radio log。详细的实现代码可以参考文件 kernel/drivers/staging/adroid/logger.c

2. 在 Native 层封装了对 kernel log buffer 的写入操作,并且在写入前根据传入的TAG决定是否将log写入到 Radio Log Buffer。作为Library向上层提供API。详细的实现可以参考文件夹 system/core/liblog/ 下面的文件。

3. 为了方便 Native 应用程序以及共享库的开发,提供了 macro 定义的 Log wrapper,这样在 Native 层可以直接使用 LOGV/LOGD/LOGI/LOGW/LOGE 以及相关的 API 打印 Log 到 Log Buffer. 详细的定义以及其他相关的 macro 可以参考文件 system/core/include/log/log.h

4. 为了给 Java层提供接口,在 Native 层实现了JNI接口,为 Java 层服务。详细的实现可以参考文件夹 frameworks/base/core/jni/ 下面的 android_utils_Log.cpp 和 android_utils_EventLog.cpp 文件。

5. 在 Java 层对 JNI 接口进行了封装,分别实现了 android.util.Log 和 android.util.EventLog 类,用于给 Java Application 以及 Java library 提供 Log 接口。详细的实现可以参考 frameworks/base/core/java/android/util/ 下面的 Log.java 和 EventLog.java 文件。

API 与优先级

和 Kernel Log 机制类似,Android Logging System 也有优先级的概念。相关的优先级定义可以参考下表。

优先级

含义

描述

V

Verbose

仅在eng版本中打印,在user和userdebug版本都不会打印。最低优先级。

D

Debug

Debug信息,常用于应用程序的调试。

I

Information

用于打印通知信息的Log。

W

Warning

用于打印警告信息。

E

Error

用于打印一般的错误信息。

F

Fatal

表示信息会引起致命性的错误。

S

Silent

最高优先级,主要用于logcat过滤Log,S优先级所有Log都不会输出。

优先级的设置有两个用途,一是可以利用优先级来揭示Log的重要程度,自然越致命的信息越重要。二是Log工具可以根据不同的Log级别来过滤掉不关心的Log。

搭配不同的Log级别,就衍生出了各个级别的Log API。

例如,在Native层定义了如下的Macro,LOGV / LOGD / LOGI / LOGW / LOGE,用来打印不同级别的log。(此处举例的API并非 Native层定义的所有的API,请参考 system/core/include/log/log.h 文件查阅完整的定义)

而在Java层的 android.util.Log 类则定义了 Log.v / Log.d / Log.i / Log.w / Log.e 接口,用于在Java层打印Log。更完整的API定义请参考文件 frameworks/base/core/java/android/util/Log.java

1.4 Logging Tools

一个完整的日志系统除了Log保存机制以外,还要有Log查看机制。不管是Kernel Log还是Android Log都会将Log打印到buffer,那么Log工具则会将Buffer里面的Log拿出来做相应的处理,或者打印到终端,或者对Log做解析以及过滤等等。而Kernel Log除了打印到buffer以外还会打印到Console,那么从console获取Log也是一种常见的方式。

那到底都有哪些Log工具和方法呢?常用的Log工具和方法可以参考下表,有些可以抓取Kernel Log,有些可以抓取Android Log,有些则可以同时抓取两种Log。下表列出了各种工具和方法对Android Log和Kernel Log的支持情况,以及使用时需要注意的事项。

Android Log

Kernel Log

NOTE

kmsg

NO

YES

需要adb连接

dmesg

NO

YES

需要adb连接

UART Log

YES

YES

需要UART Cable连接

logcat

NO

YES

需要adb连接

自定义工具

YES

YES

Kernel & logcat log自动存储到指定目录,并限定log文件个数和行数

在上面的表格中 kmsg/dmesg 和 UART Log 都是标准Linux Kernel支持的方式。而 logcat/DDMS 是Android提供的标准debug方式。后面我们将详细介绍每一种Log工具。

二、深度解析

2.1 kmsg

在前面 Kernel Log 章节我们有讲过,所有的 Kernel Log 都会输出到 Kernel 里面的一个循环的缓冲区 'log_buf',为了能够方便的在 user space 读取 Kernel log,Kernel driver 里面将这个 buffer 映射到了 /proc 目录下的文件节点 /proc/kmsg

所以读取 /proc/kmsg 文件其实就是在访问 Kernel Log 的循环缓冲区。虽然 Log buffe的大小是固定的,但是可以通过不断的访问 /proc/kmsg 将所有的log都备份下来。

如下是一个例子,我们可以通过 adb shell cat /proc/kmsg 不断的将log打印到shell里面。

除此之外,还可以通过重定向将 Log 转存到文件中。例如,下面的命令将 kmsg buffer 的内容保存到windows D盘的 kernel_kmsg.log 文件中

D:\> adb shell cat /proc/kmsg > d:\kernel_kmsg.log

使用限制

在访问 /proc/kmsg 的时候有一些限制,主要是

1、由于 Kernel log buffer 循环缓冲区只有一个读指针,所以当一个程序在读 buffer 的时候会不断的移动 buffer 的读指针,这样当有多个程序读取 buffer 的时候每个程序得到的log都不是完整的。所以当访问 /proc/kmsg 的时候务必保证没有其它程序读取 Kernel Log Buffer。

2、/proc/kmsg 的 Owner 是 root,群组属于 System,所以在 user 版本上面是无法通过 adb shell 读取 Kernel Log Buffer 的。安装在手机上的应用也是无法读取这个 buffer 的。

3、如果只是想看看当前 Log Buffer 里面的内容,而不是一直录 Log 下去,那么请参考下面的章节 “dmesg”。

此方式并不仅仅限于 Android 系统,/proc/kmsg 是 Linux 内核标准实现的部分,所以任何采用了 Linux 内核的系统都可以用这种方式获取 Kernel Log。

2.2 dmesg

前面 kmsg 的章节讲述了通过 /proc/kmsg 访问 Kernel log buffer 的方式,其主要限制是不能有多读者,即不能多个程序同时访问 Kernel Log Buffer,否则每一个访问程序得到的结果都是不完整的。

但有些时候我们可能并不知道系统里面有哪些后台进程在读取 Kernel Log Buffer,这个时候我们如何获取到可信的 Kernel Log呢?

系统(Android 或者大多数 Linux 发行版)里面还有另外一个工具,dmesg。dmesg是一个二进制可执行程序,我们可以在 adb shell 执行它,例如:

adb shell dmesg

上述命令会将整个 Log Buffer 从头到尾 dump 到输出设备,然后就退出了。它不会操作读指针,它只根据写指针把从最旧的 log 到最新的 log 完完整整的输出来。所以这种方式也不会受到其它 Log Buffer 读者的影响。

dmesg 的输出与 /proc/kmsg 的输出是一致的,区别是 dmesg dump 完 Kernel Log Buffer 就直接退出了。如下是 dmesg 的输出。

lahaina:/ # dmesg
[   10.895995] drv_probe, pdata base_mem=00000000c6aa4667, mac_regs=000000003e07e69a
[   10.904406] FXGMAC_DRV_NAME:fuxi-gmac, FXGMAC_DRV_VERSION:1.0.21-1122-4
[   10.911930] read mac from eFuse
[   10.918469] register desc_ops and hw ops
[   10.923805] CHIP_RESET 0x80000001
[   10.938252] check mac regs, get offset 0x110,ver=0x1052,mac_regs=000000003e07e69a
[   10.946662] HWFR3: 268435488
[   10.950349]
[   10.952610] =====================================================
[   10.959600]
[   10.961862] HW support following features,ver=0x1052
[   10.967689]
[   10.969962] VLAN Hash Filter Selected                   : NO
[   10.976516] SMA (MDIO) Interface                        : YES
[   10.983143] PMT Remote Wake-up Packet Enable            : YES
[   10.989772] PMT Magic Packet Enable                     : YES
[   10.996397] RMON/MMC Module Enable                      : YES
[   11.003020] ARP Offload Enabled                         : YES

应用场景

dmesg 的使用场景与 /proc/kmsg 的场景是大致相同的,同样,不适合调试 Kernel BUG,当 Kernel 出现 BUG 的时候 dmesg 作为 user space 程序首先就无法正常执行了,所以没办法录取到有效的 log 来分析问题。

其适用的场合主要是跟踪调试内核的逻辑,或者监测硬件模块的内核行为等等。

dmesg 会完完整整的 dump 一次 Kernel Log Buffer,所以不会丢失掉任何的 Log。

使用限制

使用 dmesg 来获取 Kernel Log 也有一些限制,如下:

1、dmesg 只会一次性 dump Kernel log buffer,所以只能得到当下的 log 部分,由于 Log buffer 的大小是有限制的,在很短的时间内就可能把旧的 Log 覆盖掉,所以有可能来不及抓到旧的部分,如果 Log 量比较大,那么能够抓到的 Log 时间就很短了。所以不适合 Log 量比较大的情况,也不适合长时间跟踪内核行为。

2、dmesg 的执行需要有 root 权限才行。所以 Android user 版本是无法使用这个工具的。

3、如果需要长时间录取 Log,那就需要访问 /proc/kmsg 的方式。

此方式并不仅仅限于 Android 系统,绝大多数的 Linux 发行版都内置了这个应用程序。所以大多数采用 Linux 内核的系统都可以使用此工具。

2.3 UART Log

/proc/kmsg 文件节点映射 Kernel Log Buffer,或者 dmesg dump Kernel Log Buffer 实际都是直接从 Buffer 里面获取 Log。在 Kernel Log 章节有讲过,所有的 Kernel Log 都会一字不漏的全部写入的 Buffer 中,所以通过访问 Log Buffer 的方式获取的 Kernel Log 是最完整的。

在 Kernel Log 章节也有提到 Kernel Log 除了输出到 Buffer 之外,还会将一部分 Log 输出的到 Console。所以通过 UART 也是可以获取 Kernel Log的。(具体输出哪些 Log 取决于设定的 log level。更详细的信息请参考 Kernel Log 章节。)

UART 用于 Logging 是极其广泛的,除了 Linux Kernel 默认将其作为 Console 以外,系统其它的部分,如 bootloader 的 Debug 也和 UART Log 紧密相关。所以 UART Log 对于整个系统的 Debug,尤其是开机和关机流程至关重要。

但是 Phone 或者 Tablet 通常都不会留出直接的 UART 接口,而只是在电路板上面留出 UART 测试点,所以抓取 UART Log 就会相对麻烦一点,首先就要准备 UART cable 以及搭建抓取 UART Log 的环境。

2.4 Logcat

Logcat 是 Android SDK 里面提供的命令行下的 Logging 工具,用法简单,使用方便,相关的介绍可以参考 Android Developer 链接: http://developer.android.com/tools/help/logcat.html

用法

命令格式如下,在<option>可以指定一些选项,比如输出格式,指定 buffer 等;而在<filter-spec>中可以指定过滤规则。

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

logcat 可以作为 adb command 来执行,利用 target 上面的 adb daemon 来操作 log buffer。

adb logcat -v threadtime

也可以通过 adb 建立的 shell,在 shell 里面执行 target 上面的 logcat 程序来操作 log buffer。

adb shell logcat -v threadtime

常用操作

详细的使用方式请参考 Android Developer 上面的介绍,这里仅对常用操作进行举例。

1. 如何抓取有效 log?

adb logcat -v threadtime > main_log.txt

此种方式为最常用的抓取方式,会将 log 的 PID,TID,TAG 以及时间戳都打印在一行 log 里面。优先使用此种方式抓取 log,一定不要仅仅敲 adb logcat 来抓取 log,adb logcat 仅仅会将一些基本的信息打印出来,缺少时间戳信息对于分析问题是困难的。

2. 如何仅仅抓取某个 TAG 的 Log?

可以使用<filter-spec>来过滤某一些 log,<filter-spec>的格式是 <TAG>:<Priority>.

adb logcat -v threadtime ActivityManager:D *:S

上面的命令可以仅打印 ActivityManager 等于和高于 debug 级别的log,它指定了 ActivityManager 最低 Log 级别为 debug,用 * 来匹配其他所有 TAG,并将其它所有 TAG 设置为 silent 级别,即不输出任何 Log。

三、自定义工具

在实际的项目中,把Android系统的kernel log 和logcat log 的输出存储到flash上,是非常有用的,可以定位问题。实际的生产项目中,这一点是必不可少的。

3.1 aplog工具

上面说的logcat工具 可以实现文件的保存,并且可以指定保存文件大小和个数。当超出这个设置时,自动覆盖。

通过logcat --help查看

$ logcat --help
Usage: logcat [options] [filterspecs]General options:-b, --buffer=<buffer>       Request alternate ring buffer(s):main system radio events crash default allAdditionally, 'kernel' for userdebug and eng builds, and'security' for Device Owner installations.Multiple -b parameters or comma separated list of buffers areallowed. Buffers are interleaved.Default -b main,system,crash,kernel.-L, --last                  Dump logs from prior to last reboot from pstore.-c, --clear                 Clear (flush) the entire log and exit.if -f is specified, clear the specified file and its related rotatedlog files instead.if -L is specified, clear pstore log instead.-d                          Dump the log and then exit (don't block).--pid=<pid>                 Only print logs from the given pid.--wrap                      Sleep for 2 hours or when buffer about to wrap whichevercomes first. Improves efficiency of polling by providingan about-to-wrap wakeup.Formatting:-v, --format=<format>       Sets log print format verb and adverbs, where <format> is one of:brief help long process raw tag thread threadtime timeModifying adverbs can be added:color descriptive epoch monotonic printable uid usec UTC year zoneMultiple -v parameters or comma separated list of format and formatmodifiers are allowed.-D, --dividers              Print dividers between each log buffer.-B, --binary                Output the log in binary.Outfile files:-f, --file=<file>           Log to file instead of stdout.-r, --rotate-kbytes=<n>     Rotate log every <n> kbytes. Requires -f option.-n, --rotate-count=<count>  Sets max number of rotated logs to <count>, default 4.--id=<id>                   If the signature <id> for logging to file changes, then clear theassociated files and continue.Logd control:These options send a control message to the logd daemon on device, print its return message ifapplicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.-g, --buffer-size           Get the size of the ring buffers within logd.-G, --buffer-size=<size>    Set size of a ring buffer in logd. May suffix with K or M.This can individually control each buffer's size with -b.-S, --statistics            Output statistics.--pid can be used to provide pid specific stats.-p, --prune                 Print prune rules. Each rule is specified as UID, UID/PID or /PID. A'~' prefix indicates that elements matching the rule should be prunedwith higher priority otherwise they're pruned with lower priority. Allother pruning activity is oldest first. Special case ~! represents anautomatic pruning for the noisiest UID as determined by the currentstatistics.  Special case ~1000/! represents pruning of the worst PIDwithin AID_SYSTEM when AID_SYSTEM is the noisiest UID.-P, --prune='<list> ...'    Set prune rules, using same format as listed above. Must be quoted.Filtering:-s                          Set default filter to silent. Equivalent to filterspec '*:S'-e, --regex=<expr>          Only print lines where the log message matches <expr> where <expr> isan ECMAScript regular expression.-m, --max-count=<count>     Quit after printing <count> lines. This is meant to be paired with--regex, but will work on its own.--print                     This option is only applicable when --regex is set and only useful if--max-count is also provided.With --print, logcat will print all messages even if they do notmatch the regex. Logcat will quit after printing the max-count numberof lines that match the regex.-t <count>                  Print only the most recent <count> lines (implies -d).-t '<time>'                 Print the lines since specified time (implies -d).-T <count>                  Print only the most recent <count> lines (does not imply -d).-T '<time>'                 Print the lines since specified time (not imply -d).count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...''YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.--uid=<uids>                Only display log messages from UIDs present in the comma separate list<uids>. No name look-up is performed, so UIDs must be provided asnumeric values. This option is only useful for the 'root', 'log', and'system' users since only those users can view logs from other users.filterspecs are a series of<tag>[:priority]where <tag> is a log component tag (or * for all) and priority is:V    Verbose (default for <tag>)D    Debug (default for '*')I    InfoW    WarnE    ErrorF    FatalS    Silent (suppress all output)'*' by itself means '*:D' and <tag> by itself means <tag>:V.
If no '*' filterspec or -s on command line, all filter defaults to '*:V'.
eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.If not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.If not specified with -v on command line, format is set from ANDROID_PRINTF_LOG
or defaults to "threadtime"

具体命令如下:

/system/bin/logcat -b system -b events -b main -b radio -b crash -v uid -f /data/logs/aplog -r 5000 -n 30

-b system -b events -b main -b radio -b crash 表示选择保存这些模块的log;

-v uid 显示uid;

-f /data/logs/aplog 存储路径为/data/logs/ 保存文件名为aplog,

-r 5000 存储的aplog文件每个5000 kbytes;

上述命令,会覆盖存储,也就是只保存最近的31 x 5000 kbytes 大小的log;

3.2 Aplog的selinux策略

上述服务配置放到一个rc文件中即可,但需要调试selinux策略,这块比较繁琐耗时;

关于selinux的详解,后边文章介绍。此处文末给出相关patch。

3.3 kernel log工具

前面有说过,如果需要长时间录取 Log,那就需要访问 /proc/kmsg 。这里自定义实现的Kernel log工具就是访问/proc/kmsg,

        static const char proc_kmsg[] = "/proc/kmsg";fd = android_get_control_file(proc_kmsg);

但需要解决 服务启动后 读取已经缓存到cache的内容,和现有内容的衔接。同样也实现和aplog类似功能,指定保存最近log的文件个数,并且指定文件大小。

例如:如下命令

/system/bin/kernel_log -f /data/logs/kernel_kmsg -r 1000 -n 50 -v threadtime -K

-f 指定log路径及文件名

-r 指定每个文件的字节数kbytes

-n 表示文件后缀到 kernel_kmsg.50

-v threadtime  显示格式设置,显示线程时间

-K 使能dmesg输出

lahaina:/data/logs# ls aplog* kernel_kmsg*
aplog     aplog.12  aplog.24        kernel_kmsg.13  kernel_kmsg.24  kernel_kmsg.35  kernel_kmsg.46
aplog.01  aplog.13  aplog.25        kernel_kmsg.14  kernel_kmsg.25  kernel_kmsg.36  kernel_kmsg.47
aplog.02  aplog.14  aplog.26        kernel_kmsg.15  kernel_kmsg.26  kernel_kmsg.37  kernel_kmsg.48
aplog.03  aplog.15  aplog.27        kernel_kmsg.16  kernel_kmsg.27  kernel_kmsg.38  kernel_kmsg.49
aplog.04  aplog.16  aplog.28        kernel_kmsg.17  kernel_kmsg.28  kernel_kmsg.39  kernel_kmsg.5
aplog.05  aplog.17  aplog.29        kernel_kmsg.18  kernel_kmsg.29  kernel_kmsg.4   kernel_kmsg.50
aplog.06  aplog.18  aplog.30        kernel_kmsg.19  kernel_kmsg.3   kernel_kmsg.40  kernel_kmsg.6
aplog.07  aplog.19  kernel_kmsg     kernel_kmsg.2   kernel_kmsg.30  kernel_kmsg.41  kernel_kmsg.7
aplog.08  aplog.20  kernel_kmsg.1   kernel_kmsg.20  kernel_kmsg.31  kernel_kmsg.42  kernel_kmsg.8
aplog.09  aplog.21  kernel_kmsg.10  kernel_kmsg.21  kernel_kmsg.32  kernel_kmsg.43  kernel_kmsg.9
aplog.10  aplog.22  kernel_kmsg.11  kernel_kmsg.22  kernel_kmsg.33  kernel_kmsg.44
aplog.11  aplog.23  kernel_kmsg.12  kernel_kmsg.23  kernel_kmsg.34  kernel_kmsg.45

详细实现见文末代码实现

3.4 Kernel log工具的selinux策略

一般新增的bin工具,都新增一个label;

此处新增一个 kernel_kmsg;

--- /dev/null
+++ b/QSSI.13/device/qcom/sepolicy/testlog/private/file_contexts
@@ -0,0 +1,2 @@
+/data/logs(/.*)?                u:object_r:method_trace_data_file:s0
+/system/bin/kernel_kmsg         u:object_r:kernel_kmsg_exec:s0

所有详细代码实现如下:

  1. aplog的selinux
  2. Kernel_kmsg源码实现
  3. Kernel_kmsg 的selinux实现

见如下链接

Android实战经验篇-系列文章汇总

Android Display Graphics系列文章-汇总

相关文章:

Android实战经验篇-log工具

详细代码实现及系列文章请转如下链接 Android实战经验篇-系列文章汇总 Android Display Graphics系列文章-汇总 一、基础知识 1.1 Logging简述 我们写的第一个计算机C程序一般是printf(“Hello world!”);这就是一个log输出。Linux内核有Kernel log以及配套的Log工具&#x…...

DPU编程技术解析与实践应用

一、引言 1.1 研究背景与目的 随着信息技术的飞速发展&#xff0c;数据中心在现代社会中的地位日益凸显&#xff0c;成为支撑各行业数字化转型的关键基础设施。在数据中心内部&#xff0c;数据的处理速度、效率和安全性成为了影响整体性能的核心要素。为了应对不断增长的数据…...

红帽认证的含金量和价值如何?怎么报名红帽认证考试?

红帽企业 Linux&#xff08;RHEL&#xff09;是由红帽公司提供的一款商业支持、专为生产环境设计的Linux发行版。随着IT系统和工作负载日益复杂化&#xff0c;底层基础设施及操作系统必须兼具可靠性、可扩展性&#xff0c;并能有效促进性能提升。红帽认证在全球范围享有盛誉&am…...

VS Code Copilot 与 Cursor 对比

选手简介 VS Code Copilot&#xff1a;算是“老牌”编程助手了&#xff0c;虽然Copilot在别的编辑器上也有扩展&#xff0c;不过体验最好的还是VS Code&#xff0c;毕竟都是微软家的所以功能集成更好一些&#xff1b;主要提供的是Complete和Chat能力&#xff0c;也就是代码补全…...

蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)

一、工程模版创建流程 第一步 创建新项目 第二步 选择型号和管脚封装 第三步 RCC使能 外部时钟&#xff0c;高速外部时钟 第四步晶振时钟配置 由数据手册7.1可知外部晶振频率为24MHz 最后一项设置为80 按下回车他会自动配置时钟 第五步&#xff0c;如果不勾选可能程序只会…...

取多个集合的交集

1.我们取多个集合的交集&#xff0c;先把各个集合放入list中 List < Set < String > > listnew ArrayList<>();HashSet<String> set1new HashSet<>();set1.add( "A" );set1.add("B" );set1.add("C" );HashSet<…...

如何实现电子发票XML文件的合规性存档?

随着国家税务改革的推进&#xff0c;企业对电子发票的管理和存档要求越来越高。尤其是《财政部 国家税务总局关于进一步深化增值税发票管理改革的通知》&#xff08;财会〔2023〕18号文&#xff09;的发布&#xff0c;明确规定了电子发票的存档要求。这为企业在财务管理中的电子…...

IOT、MES、WMS、MOM 和 EPMS 系统综合技术与业务文档

IOT、MES、WMS、MOM 和 EPMS 系统综合技术与业务文档 一、引言 在现代制造业和工业管理领域&#xff0c;IOT&#xff08;物联网&#xff09;、MES&#xff08;制造执行系统&#xff09;、WMS&#xff08;仓库管理系统&#xff09;、MOM&#xff08;制造运营管理系统&#xff…...

IntelliJ IDEA Docker集成

一、概述 Docker是一种用于在隔离和可复制环境中部署和运行可执行文件的工具。这可能很有用&#xff0c;例如&#xff0c;在与生产相同的环境中测试代码。 IntelliJ IDEA集成了Docker功能&#xff0c;并为创建Docker映像、运行Docker容器、管理Docker Compose应用程序、使用公…...

【react项目】从零搭建react项目[nodejs安装]

〇、模板git下载地址 下载即用的模板地址&#xff1a; http:https://e.coding.net/uijiio/init_app/react_init_app.git ssh:gite.coding.net:uijiio/init_app/react_init_app.git 目前更新至:登录与主页跳转&#xff0c;主页包含菜单和容器区 一、搭建基础空白React项目 1.准备…...

【专题】2024年悦己生活消费洞察报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p38654 在当今时代背景下&#xff0c;社会发展日新月异&#xff0c;人们的生活方式与消费观念正经历深刻变革。MoonFox 月狐数据的《2024 年悦己生活消费洞察报告》聚焦于这一充满活力与变化的消费领域。随着就业、婚姻等社会压力的…...

Github——网页版上传文件夹

第一步&#xff1a;创建一个新的仓库或进入已存在的仓库页面 第二步&#xff1a;点进对应的文件夹下&#xff0c;然后 点击 “Upload files” 第三步&#xff1a;将文件夹拖拽到上传区域 打开资源管理器&#xff0c;将要上传的文件夹从计算机中拖拽到上传区域。 注意&#xf…...

LMDeploy 量化部署进阶实践

1 配置LMDeploy环境 1.1 InternStudio开发机创建与环境搭建 打开InternStudio平台&#xff0c;进入如下界面创建环境 在终端中&#xff0c;让我们输入以下指令&#xff0c;来创建一个名为lmdeploy的conda环境&#xff0c;python版本为3.10&#xff0c;创建成功后激活环境并安…...

MFC/C++学习系列之简单记录9——简单加法

MFC/C学习系列之简单记录9——简单加法 前言界面设计控件添加添加变量添加事件 后台代码总结 前言 基本的一些使用已经了解&#xff0c;那么就做个简单的加法来练手吧&#xff01; 界面设计 控件添加 在工具箱中选择Edit control和Static Text两个控件&#xff0c;分别设置为…...

二分查找题目:两球之间的磁力

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;两球之间的磁力 出处&#xff1a;1552. 两球之间的磁力 难度 5 级 题目描述 要求 在代号为地球 C-137 的世界中&#xff0c;Rick 发现如果他将两个…...

OpenCV相机标定与3D重建(28)估计两个三维点集之间的最优平移变换函数estimateTranslation3D()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算两个3D点集之间的最优平移。 它计算 [ x y z ] [ X Y Z ] [ b 1 b 2 b 3 ] \begin{bmatrix} x\\ y\\ z\\ \end{bmatrix} \begin{bmatri…...

UE5仿漫威争锋灵蝶冲刺技能

这两天玩了一下漫威争锋Marvel Rivals&#xff0c;发现是UE5做的&#xff0c;对里面一些角色技能挺感兴趣的&#xff0c;想简单复刻一下技能功能&#xff0c;顺便复习一下学过的知识 首先把摄像机设置调整一下 CameraBoom里搜索lag 把摄像机延迟关掉 &#xff0c;这样摄像机就…...

CSS盒子模型(溢出隐藏,块级元素和行级元素的居中对齐,元素样式重置)

overflow&#xff1a;值 规定了内容溢出元素框时所发生的事情 visible&#xff1a;内容不会被修剪&#xff0c;会显示在元素框之外&#xff0c;默认值 overflow: visible; hidden&#xff1a;内容会被修剪&#xff0c;溢出内容不可见 overflow: hidden; scroll&#xff1a;内…...

语音增强的损失函数选择

一、最优尺度不变信噪比&#xff08;OSISNR&#xff09;损失函数 参考&#xff1a;论文解读 --Optimal scale-invariant signal-to-noise ratio and curriculum learning for monaural multi-spea   最优尺度不变信噪比&#xff08;OSI-SNR&#xff09;是一种用于评估信号质量…...

【python自动化六】UI自动化基础-selenium的使用

selenium是目前用得比较多的UI自动化测试框架&#xff0c;支持java&#xff0c;python等多种语言&#xff0c;目前我们就选用selenium来做UI自动化。 1.selenium安装 安装命令 pip install selenium2.selenium的简单使用 本文以chrome浏览器为例&#xff0c;配套selenium中c…...

【习题答案】让您的应用拥有领先的位置服务能力

判断题 1.在使用&#xff08;逆&#xff09;地理编码前&#xff0c;需要使用isGeocoderAvailable检查服务状态。 正确(True) 错误(False) 2.当同时配置定位场景和优先级策略时&#xff0c;会优先使用优先级策略。 正确(True) 错误(False) 单选题 1.获取精准定位需要申请哪个权…...

java中list和map区别

在Java中&#xff0c;List和Map是两种不同类型的集合接口&#xff0c;它们用于不同的场景并且具有不同的特性和用途。以下是List和Map的主要区别&#xff1a; 1. 数据结构 List&#xff1a;是一个有序的集合&#xff0c;允许重复元素。它实现了Collection接口&#xff0c;并且…...

java后端传时间戳给前端的三种方式

一. 后端传时间戳给前端的几种方式 使用System.currentTimeMillis() 这是最简单的方式&#xff0c;返回自1970年1月1日&#xff08;UTC&#xff09;以来的毫秒数&#xff0c;可以直接传递给前端。 long timestamp1 System.currentTimeMillis();使用java.time.Instant Java…...

【机器学习与数据挖掘实战】案例06:基于Apriori算法的餐饮企业菜品关联分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…...

oracle: create new database

用database configuration Assistant 引导创建数据库。记得给system,sys 设置自己的口令&#xff0c;便于添加新操作用户。 创建操作用户&#xff1a; -- 别加双引号&#xff0c;否则&#xff0c;无法用 create user geovindu identified by 888888; create user geovin identi…...

混合开发环境---使用编程AI辅助开发Qt

文章目录 [toc]1、说明2、演示视频 1、说明 新时代的浪潮早就已经来临&#xff0c;上不了船的人终将被抛弃&#xff0c;合理使用AI辅助开发、提升效率是大趋势 注意&#xff1a;不要被AI奴隶 合理使用AI辅助编程&#xff0c;十倍提升效率。 大部分的编程AI都有vs code插件&…...

Sigrity SystemSI仿真分析教程文件路径

为了方便读者能够快速上手和学会Sigrity SystemSI 的功能&#xff0c;将Sigrity SystemSI仿真分析教程专栏所有文章对应的实例文件上传至以下路径 https://download.csdn.net/download/weixin_54787054/90171488?spm1001.2014.3001.5503...

【YashanDB知识库】Oracle pipelined函数在YashanDB中的改写

本文内容来自YashanDB官网&#xff0c;原文内容请见 https://www.yashandb.com/newsinfo/7802940.html?templateId1718516 【问题分类】功能使用 【关键字】pipelined 【问题描述】 Oracle PL/SQL中包含pipelined函数的对象迁移到YashanDB会出现不兼容现象。 【问题原因分…...

【开发实战】QT5+ 工业相机 + OpenCV工作流集成演示

学习《OpenCV应用开发&#xff1a;入门、进阶与工程化实践》一书 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; 概述 基于OpenCV工作流引擎SDK Qt5 海康工业相机实现了从图像采集到OpenCV工作流运行的完整流程。其中工业相机采图是一个单…...

各种电机原理介绍

1&#xff0c;直流电机 &#xff08;1&#xff09;基本原理 直流电动机由直流电驱动电池或外部电源为其供电。在最简单的直流电动机中&#xff0c;定子为永磁体(即红蓝磁体外壳)&#xff0c;转子是一个电磁体(即线圈)&#xff0c;电流通过碳刷和一个换向器作用于转动的线圈。…...