安卓14剖析SystemUI的ShadeLogger/LogBuffer日志动态控制输出dumpsy机制

背景:

看SystemUI的锁屏相关代码时候发现SystemUI有一个日志打印相关的方法调用,相比于常规的Log.i直接可以logcat查看方式还是比较新颖。

具体日志打印代码如下:
在这里插入图片描述
下面就来介绍一下这个ShadeLogger到底是如何打印的。

分析源码:

源码位置:
frameworks/base/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt

明显是一个kt类,这里就只拿一个logEndMotionEvent方法来进行源码分析

fun logEndMotionEvent(msg: String,forceCancel: Boolean,expand: Boolean,
)
{buffer.log(TAG,LogLevel.VERBOSE,{str1 = msgbool1 = forceCancelbool2 = expand},{ "$str1; force=$bool1; expand=$bool2" })
}

可以看到这里看到实际是调用的buffer.log方法,也有对应TAG和LogLevel等级。
那么下面来看看这个buffer.log中的buffer哪里来的,但是因为这构造都是采用了很多注解drag2方式,所以不方便找,这里找到了一个NotificationPanelViewControllerBaseTest一个测试类有手动进行构造,这里也可以看出相关过程

frameworks/base/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java

具体过程如下:
在这里插入图片描述
再看看mShadeLog构造
在这里插入图片描述再看看logcatLogBuffer方法
在这里插入图片描述这里调用到了LogBuffer类,注意这里test类给的是50,实际的Shader类给的是500
frameworks/base/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
看看log方法:

inline fun log(tag: String,level: LogLevel,messageInitializer: MessageInitializer,noinline messagePrinter: MessagePrinter,exception: Throwable? = null,
) {val message = obtain(tag, level, messagePrinter, exception)messageInitializer(message)commit(message)
}

看看obtain方法:

@Synchronizedoverride fun obtain(tag: String,level: LogLevel,messagePrinter: MessagePrinter,exception: Throwable?,): LogMessage {if (!mutable) {return FROZEN_MESSAGE}val message = buffer.advance()//可以看到这里是buffer中获取,message.reset(tag, level, System.currentTimeMillis(), messagePrinter, exception)return message}

这里其实只是看出来了buffer中搞出了一个message,根据传递来的tag和msg
接下来重点看看commit方法

override fun commit(message: LogMessage) {if (echoMessageQueue != null && echoMessageQueue.remainingCapacity() > 0) {try {echoMessageQueue.put(message)//主要就是放入队列} catch (e: InterruptedException) {// the background thread has been shut down, so just log on this oneechoToDesiredEndpoints(message)}} else {echoToDesiredEndpoints(message)}
}

commit主要就是实现对message放入到echoMessageQueue,那么什么时候取这个队列呢?

这里要看最开始的init方法中有启动一个线程

init {if (logcatEchoTracker.logInBackgroundThread && echoMessageQueue != null) {thread(start = true, name = "LogBuffer-$name", priority = Thread.NORM_PRIORITY) {try {while (true) {//死循环的取出队列echoToDesiredEndpoints(echoMessageQueue.take())//调用echoToDesiredEndpoints来处理消息}} catch (e: InterruptedException) {Thread.currentThread().interrupt()}}}
}

具体echoToDesiredEndpoints方法如下:

 private fun echoToDesiredEndpoints(message: LogMessage) {//获取log打印level,即其实可以通过命令来控制打印level,这里的level本质是来自settings,具体啥settings值下面操作时候会讲解val includeInLogcat =logcatEchoTracker.isBufferLoggable(name, message.level) ||logcatEchoTracker.isTagLoggable(message.tag, message.level)echo(message, toLogcat = includeInLogcat, toSystrace = systrace)//有了上面level后,echo开始处理}private fun echo(message: LogMessage, toLogcat: Boolean, toSystrace: Boolean) {if (toLogcat || toSystrace) {val strMessage = message.messagePrinter(message)if (toSystrace) {echoToSystrace(message, strMessage)//可以看这个日志还支持systrace相关}if (toLogcat) {echoToLogcat(message, strMessage)//这里就是最普通的logcat打印出来}}}
//具体的echoToLogcat其实就是根据传递进来的等级进行普通log打印private fun echoToLogcat(message: LogMessage, strMessage: String) {when (message.level) {LogLevel.VERBOSE -> Log.v(message.tag, strMessage, message.exception)LogLevel.DEBUG -> Log.d(message.tag, strMessage, message.exception)LogLevel.INFO -> Log.i(message.tag, strMessage, message.exception)LogLevel.WARNING -> Log.w(message.tag, strMessage, message.exception)LogLevel.ERROR -> Log.e(message.tag, strMessage, message.exception)LogLevel.WTF -> Log.wtf(message.tag, strMessage, message.exception)}}

到此LogBuffer源码也就大概分析完成,可以得出以下几个结论:

1、所有的埋点日志会保存到buffer中,这个buffer只是在内存中的一个环形buffer,有固定大小

2、buffer中的日志是可以 实现输出到logcat和systrace的功能

那么具体如何控制输出到logcat,还有如何看buffer中的日志呢?接下来看看使用方法

使用方式:

在类的最开始部分有如下的使用注释:

/*** A simple ring buffer of recyclable log messages** The goal of this class is to enable logging that is both extremely chatty and extremely* lightweight. If done properly, logging a message will not result in any heap allocations or* string generation. Messages are only converted to strings if the log is actually dumped (usually* as the result of taking a bug report).** You can dump the entire buffer at any time by running:* ```* $ adb shell dumpsys activity service com.android.systemui/.SystemUIService <bufferName>* ```** ...where `bufferName` is the (case-sensitive) [name] passed to the constructor.** By default, only messages of WARN level or higher are echoed to logcat, but this can be adjusted* locally (usually for debugging purposes).** To enable logcat echoing for an entire buffer:* ```* $ adb shell settings put global systemui/buffer/<bufferName> <level>* ```** To enable logcat echoing for a specific tag:* ```* $ adb shell settings put global systemui/tag/<tag> <level>* ```** In either case, `level` can be any of `verbose`, `debug`, `info`, `warn`, `error`, `assert`, or* the first letter of any of the previous.** In SystemUI, buffers are provided by LogModule. Instances should be created using a SysUI* LogBufferFactory.** @param name The name of this buffer, printed when the buffer is dumped and in some other*   situations.* @param maxSize The maximum number of messages to keep in memory at any one time. Buffers start*   out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches*   the maximum, it behaves like a ring buffer.*/

其实上面已经写的很详细了,主要就是2个核心点,一个可以通过dumpsys看所有日志,一个是可以控制logcat输出

控制dumpsys查看方法

adb shell dumpsys activity service com.android.systemui/.SystemUIService <bufferName>

比如这里的对ShadeLog

adb shell dumpsys activity service com.android.systemui/.SystemUIService ShadeLog

dumpsys后可以查看到相关的Log:
在这里插入图片描述
看到这个dump日志就感觉非常详细的记录了Shade锁屏相关的操作,相关的tag等也是在ShadeLogger.kt定义的
在这里插入图片描述

如果想要普通logcat输出呢?

 adb shell settings put global systemui/tag/ShadeLog v

这里其实就是配置一个settings,然后上面的提到的echoToDesiredEndpoints的 logcatEchoTracker.isBufferLoggable就会去查询这个settings值。
在这里插入图片描述

总结图

在这里插入图片描述

更多framework详细代码和资料参考如下链接
投屏专题部分:
https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg
hal+perfetto+surfaceflinger

https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
其他课程七件套专题:在这里插入图片描述
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频试看:
https://www.bilibili.com/video/BV1wc41117L4/

参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615

更多framework假威风耗:androidframework007

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/429020.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端JavaScript导出excel,并用excel分析数据,使用SheetJS导出excel

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f…

OpenWrt 定时重启

问题 想设置 OpenWrt 定时重启&#xff0c;避免因长期不重启导致的问题。 方法 参考 Scheduling tasks with cronopenwrt设置定时重启&#xff08;天/周/月&#xff09;定时重启openwrt (istoreos) 软路由系统 设置 cron 自启动 System - Start up - 找到 cron - 设置成自…

stm32单片机个人学习笔记5(OLED调试工具)

前言 本篇文章属于stm32单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 STM32入门教程-2023版 细…

深入探究HTTP网络协议栈:互联网通信的基石

在我们日常使用互联网的过程中&#xff0c;HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;扮演着至关重要的角色。无论是浏览网页、下载文件&#xff0c;还是进行在线购物&#xff0c;HTTP协议都在背后默默地支持着这些操作。今天&#x…

go语言中的切片详解

1.概念 在Go语言中&#xff0c;切片&#xff08;Slice&#xff09;是一种基于数组的更高级的数据结构&#xff0c;它提供了一种灵活、动态的方式来处理序列数据。切片在Go中非常常用&#xff0c;因为它们可以动态地增长和缩小&#xff0c;这使得它们比固定大小的数组更加灵活。…

芯片开发(1)---BQ76905---底层参数配置

主要开发思路:AFE主要是采集、保护功能、均衡&#xff0c;所以要逐一去配置芯片的寄存器 采集、均衡功能主要是配置引脚 保护功能主要是参数寄存器配置&#xff0c;至于如何使用命令修改寄存器参数该系列芯片提供了子命令和直接命令两种方式 BQ76905的管脚配置 I、参数配置 …

使用Renesas R7FA8D1BH (Cortex®-M85)和微信小程序App数据传输

目录 概述 1 系统架构 1.1 系统结构 1.2 系统硬件框架结构 1.3 蓝牙模块介绍 2 微信小程序实现 2.1 UI介绍 2.2 代码实现 3 上位机功能实现 3.1 通信协议 3.2 系统测试 4 下位机功能实现 4.1 功能介绍 4.2 代码实现 4.3 源代码文件 5 测试 5.1 编译和下载代码…

Codeforces Round 974 (Div. 3) A-F

封面原图 画师礼島れいあ 下午的ICPC网络赛的难受一晚上全都给我打没了 手速拉满再加上秒杀线段树 这场简直了啊 唯一可惜的是最后还是掉出了1000名 一把上蓝应该没啥希望了吧 A - Robin Helps 题意 侠盗罗宾因劫富济贫而闻名于世 罗宾遇到的 n n n 人&#xff0c;从 1 s …

mysqldump使用cmd窗口和powersell窗口导出sql中文乱码的问题

项目场景 我在使用Mariadb数据库更新数据的时候&#xff0c;由于数据库的表格中含有中文&#xff0c;在使用mysqldump导出sql语句的时候&#xff0c;中文显示乱码&#xff0c;如下图所示&#xff1a; 环境描述 系统&#xff1a;windows10数据库&#xff1a; Mariadb -10.6.16…

linux安装Anaconda3

先将Anaconda3安装包下载好&#xff0c;然后在主文件夹里新建一个文件夹&#xff0c;将Anaconda3安装包拖进去。 打开终端未来不出现缺东西的异常情况&#xff0c;我们先安装 yum install -bzip2然后进入根目录下&#xff0c;在进入Anaconda3文件夹下 sh包安装方式 sh Anac…

动手学深度学习(李沐)PyTorch 第 2 章 预备知识

2.1 数据操作 N维数组样例 N维数组是机器学习和神经网络的主要数据结构 张量表示一个由数值组成的数组&#xff0c;这个数组可能有多个维度。 具有一个轴的张量对应数学上的向量&#xff08;vector&#xff09;&#xff1b; 具有两个轴的张量对应数学上的矩阵&#xff08;…

S-Clustr-Simple 飞机大战:骇入现实的建筑灯光游戏

项目地址:https://github.com/MartinxMax/S-Clustr/releases Video https://www.youtube.com/watch?vr3JIZY1olro 飞机大战 这是一个影子集群的游戏插件&#xff0c;可以将游戏画面映射到现实的设备&#xff0c;允许恶意控制来完成游戏。亦或者设备部署在某建筑物中,来控制…

2024年中国研究生数学建模竞赛A题“风电场有功功率优化分配”全析全解

问题一&#xff1a; 针对问题一&#xff0c;可以采用以下低复杂度模型&#xff0c;来计算风机主轴及塔架的疲劳损伤累积程度。 建模思路&#xff1a; 累积疲劳损伤计算&#xff1a; 根据Palmgren-Miner线性累积损伤理论&#xff0c;元件的疲劳损伤可以累积。因此&#xff0c;…

Android-UI设计

控件 控件是用户与应用交互的元素。常见的控件包括&#xff1a; 按钮 (Button)&#xff1a;用于执行动作。文本框 (EditText)&#xff1a;让用户输入文本。复选框 (CheckBox)&#xff1a;允许用户选择或取消选择某个选项。单选按钮 (RadioButton)&#xff1a;用于在多个选项中…

分享两道算法题

分享两道算法题 王者荣耀分组 题目描述 部门准备举办一场王者荣耀表演赛&#xff0c;有 10 名游戏爱好者参与&#xff0c;分 5 为两队&#xff0c;每队 5 人。 每位参与者都有一个评分&#xff0c;代表着他的游戏水平。 为了表演赛尽可能精彩&#xff0c;我们需要把 10 名参赛…

leetcode练习 二叉树的最大深度

给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3提示&#xff1a; 树中节点的数量在 [0, 104] 区间内。-100 …

RabbitMQ08_保证消息可靠性

保证消息可靠性 一、生产者可靠性1、生产者重连机制&#xff08;防止网络波动&#xff09;2、生产者确认机制Publisher Return 确认机制Publisher Confirm 确认机制 二、MQ 可靠性1、数据持久化交换机、队列持久化消息持久化 2、Lazy Queue 惰性队列 三、消费者可靠性1、消费者…

Springboot 文件上传下载相关问题

文章目录 关于Springboot 文件上传下载问题解决方案注意事项文件上传文件下载文件删除文件在线打开在写练习的时候&#xff0c;发现了一些小小的问题&#xff0c;已经在 上述代码中体现。① 代码路径碰到中文的时候&#xff0c;会有乱码&#xff0c;需要转换&#xff08;内容中…

华润电力最新校招社招润择认知能力测评:逻辑推理数字计算语言理解高分攻略

​ 尊敬的求职者们&#xff0c; 在您准备加入华润电力这个大家庭之前&#xff0c;了解其招聘测评的详细流程和要求是至关重要的。以下是我们为您整理的测评系统核心内容&#xff0c;希望对您的求职之旅有所帮助。 测评系统概览 华润电力的招聘测评系统旨在全面评估求职者的认…

【WEB】序列一下

1、 2、反序列化 <?phpclass Polar{public $url polarctf.com;public $ltsystem;public $bls /;function __destruct(){$a $this->lt;$a($this->b);} }$a new Polar(); echo serialize($a); ?>###O:5:"Polar":3:{s:3:"url";s:12:"…