android 13/14高版本SurfaceFlinger出现VSYNC-app/VSYNC-appSf/VSYNC-sf剖析

问题背景:

了解surfaceflinger的vsync同学都可能知道vsync属于一个节拍器,主要用来控制有节奏的渲染,不至于会产生什么画面撕裂等现象。
一般vsync都有会有2部分:
app部分vsync,控制各个app可以有节奏的上帧
surfaceflinger部分vsync,控制surfaceflinger的一个合成画面送显示的节奏

上面2部分其实大家了解vsync都知道,但是近期再看android 13的surfaceflinger trace时候发现有如下情况:

老版本:
systrace查看发现老版本其实只有app和sf的VSYNC情况
在这里插入图片描述

新版本
systrace出现了3个,多了一个VSYNC-appSf:
在这里插入图片描述

这个地方就有学员朋友在群里问这个问题,刚好我近期也在修炼surfaceflinger相关,针对这个问题,其实大部分人我估计态度都是忽略哈,,网上也基本找不到答案,哪怕问人也很难问到哈。
那么这个VSYNC-appSf到底是啥,为啥老版本没有新版本会有这个?这个就是本blog要讲解的重点 。

更多framework干货课程优惠获取相关可以+V(androidframework007)
视频:https://www.bilibili.com/video/BV1ah411d7Y3
在这里插入图片描述

线索追踪及官方解释

在对appSf的修改进行git log追踪时候发现有如下一个commit,这个commit有专门写明原因哈:

appSf产生原因,官方解释:

SurfaceFlinger: decouple EventThread from SF wakeupToday we have two instances of EventThread:1. 'app' - used to wake up Choreographer clients2. 'sf' - used to wake up SF mian thead *and*Choreographer clients that uses sf instanceNow this creates an ambiguity when trying to reason about the expectedvsync time and deadline of 'sf' EventThread:- SF wakes up sfWorkDuration before a vsync and targets that vsync- Choreographer users wakes up with SF main thread but targets thevsync that happens after the next SF wakeup.To resolve this ambiguity we are decoupling SF wakeup from 'sf'EventThread. This means that Choreographer clients that uses 'sf'instance will keep using the EventThread but SF will be waking updirectly by a callback with VSyncDispatch. This allows us to correctthe expected vsync and deadline for both.Test: Interacting with the device and observe systracesTest: new unit test added to SF suiteBug: 166302754Change-Id: I76d154029b4bc1902198074c33d38ff030c4601b

不过比较遗憾哈,全是英文的,这个要看懂可能不难哈,但是要完全领悟贯通那就要很了解surfaceflinger的vsync了。不然那就只能停留在字面意思啦,根本无法理解精华。
下面马哥带大家来理解一下吧,都把相关翻译写下来啦,不一定全对哈。
带马哥注释理解

  SurfaceFlinger: decouple EventThread from SF wakeup//标题就是把EventThread分离出sf,大概意思就是不想让EventThread管sf相关vsyncToday we have two instances of EventThread://这个是解释修改前的现状和背景,目前有两个EventThread实例,一个app一个sf1. 'app' - used to wake up Choreographer clients //app的EventThread属于用来唤醒app端2. 'sf' - used to wake up SF mian thead *and* Choreographer clients that uses sf instance//sf的EventThread有2个责任,一个是自己来唤醒Sf的主线程,另一个也是关键一点,有对应的clients端也需要使用//下面讲述修改背景,本质就是说sf的EventThread因为有2个责任,一个是自己sf的唤醒,一个是client端唤醒,二者共用情况,可能会有时候排查vsync会有模棱两可的情况,即没办法准确确认vsync问题原因Now this creates an ambiguity when trying to reason about the expectedvsync time and deadline of 'sf' EventThread:- SF wakes up sfWorkDuration before a vsync and targets that vsync- Choreographer users wakes up with SF main thread but targets thevsync that happens after the next SF wakeup.//为了解决这类可能导致模棱两可的情况,那么就需要吧sf的EventThread进行相关的分离,sf原本负责的2个功能拆开,把sf自己唤醒自己的转移到了直接让VSyncDispatch进行callback调用,另一个对于client端的功能就保留在EventThread中,这样就不会造成上面的模棱两可疑惑。也就是我们看到的会多了一个appSfTo resolve this ambiguity we are decoupling SF wakeup from 'sf'EventThread. This means that Choreographer clients that uses 'sf'instance will keep using the EventThread but SF will be waking updirectly by a callback with VSyncDispatch. This allows us to correctthe expected vsync and deadline for both.Test: Interacting with the device and observe systracesTest: new unit test added to SF suiteBug: 166302754Change-Id: I76d154029b4bc1902198074c33d38ff030c4601b

总结一下:
简单说就是吧以前的sf的EventTread功能中,自己唤醒触发vsync的部分移除EventTread,让VSyncDispatch直接进行(后面有机会讲解vsync再深入分析),不在使用EventThread来搞对于的sf的vsync了。
但是sf还有一个功能就是对待客户端的,这个部分保留在EventTread中,变成我们看到的appSf

哈其实你是不是有点懂又还是没彻底领悟,特别是为啥sf还有两个功能?以前不是说了只是来产生sf的vsync么?正常哈,因为上面的结论其实都是相当于一个结论哈,要彻底理解还需要其他相关的补充哈。

千里马实战解读理解appSf

理解sf为啥会有两个功能,以前不是只有一个产生sf端的vsync么?
我们注意看看人家的解释哈:

1. 'app' - used to wake up Choreographer clients 
2. 'sf' - used to wake up SF mian thead *and* Choreographer clients that uses sf instance

sf另一个功能是 Choreographer clients 需要使用这个sf的EventThread,这里应该是大家最不可以理解的地方。这里看看上面的app也是用的Choreographer clients ,表面意识就是Choreographer的客户端,其实就是各个需要上帧的应用的Choreographer客户端。
那么这里说的 Choreographer clients that uses sf instance,难道是sf的也有对于的客户端吗?Choreographer也有直接指定sf这个EventTread线程的?哈哈其实确实有的具体可以看以下代码:

    private Choreographer(Looper looper, int vsyncSource) {mLooper = looper;mHandler = new FrameHandler(looper);mDisplayEventReceiver = USE_VSYNC? new FrameDisplayEventReceiver(looper, vsyncSource): null;mLastFrameTimeNanos = Long.MIN_VALUE;mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];for (int i = 0; i <= CALLBACK_LAST; i++) {mCallbackQueues[i] = new CallbackQueue();}// b/68769804: For low FPS experiments.setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));}

大家注意没有这个Choreographer构造时候就有个vsyncSource,这个是不是大家都没有注意过哈,它到底有哪些值呢?

  /*** When retrieving vsync events, this specifies that the vsync event should happen at the normal* vsync-app tick.* <p>* Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h*/public static final int VSYNC_SOURCE_APP = 0;/*** When retrieving vsync events, this specifies that the vsync event should happen whenever* Surface Flinger is processing a frame.* <p>* Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h*/public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;

可以看到有两个
一个最常见的的app
另一个就是sf的
sf这个,也就是app端可以指定vsync是跟随surfaceflinger的合成vsync的,所以这里也就是被叫做Choreographer clients ,这里大家就可以理解了吧,具体有没有谁使用呢?
可以看看有谁使用Choreographer getSfInstance方法:
在这里插入图片描述

可以看到还是有一些场景就是使用的sf的vsync,自然使用vsync就会涉及到回调获取vsync和请求vsync。所以这里就是上面的说的client可能会使用相关的sf vsync情况,sf自身也有请求获取情况,所以这个两个业务混一起了,那确实有时候一些问题就不好排查了。

结合systrace验证

1、确定是不是真的有有clinet链接到了sf的EventThread
这个其实可以通过相关的dumpsys SurfaceFlinger来实现,看看是否appSf是否有对于的connection,不过比较遗憾哈,默认的dumpsys并没有吧appSf的EventThread打印,只打印了app的EventTread,所以这里就需要我们修改一下相关dumpsys如下:

test@test:~/nx563j_xiaomi/frameworks/native/services$ git diff surfaceflinger/SurfaceFlinger.cpp
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b1b31bbd76..04f5b63dc0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5180,6 +5180,7 @@ void SurfaceFlinger::dumpVSync(std::string& result) const {mDebugDisplayModeSetByBackdoor ? "yes" : "no");mScheduler->dump(mAppConnectionHandle, result);
+    mScheduler->dump(mSfConnectionHandle, result);//加入一行吧appSf相关EventTread信息也打一下mScheduler->dumpVsync(result);StringAppendF(&result, "mHWCVsyncPendingState=%s mLastHWCVsyncState=%s\n",to_string(mHWCVsyncPendingState).c_str(), to_string(mLastHWCVsyncState).c_str());

结果如下:

app: state=Idle VSyncState={displayId=0, count=548}//正常只有这个打印pending events (count=0):connections (count=16):Connection{0x747b86b730, VSyncRequest::None,1000}Connection{0x747b879e30, VSyncRequest::None,1000}Connection{0x747b86ffd0, VSyncRequest::None,1000}Connection{0x747b8784d0, VSyncRequest::None,1000}Connection{0x747b86c1b0, VSyncRequest::None,10110}Connection{0x747b8856d0, VSyncRequest::None,10110}Connection{0x747b882db0, VSyncRequest::None,10110}Connection{0x747b87fd90, VSyncRequest::None,10110}Connection{0x747b8839f0, VSyncRequest::None,10111}Connection{0x747b883bb0, VSyncRequest::None,1000}Connection{0x747b8728f0, VSyncRequest::None,1000}Connection{0x747b870350, VSyncRequest::None,10111}Connection{0x747b882870, VSyncRequest::None,10142}Connection{0x747b880570, VSyncRequest::None,10144}Connection{0x747b871150, VSyncRequest::None,10144}Connection{0x747b86da30, VSyncRequest::None,10141}
appSf: state=Idle VSyncState={displayId=0, count=165}//额外加上这个打印pending events (count=0):connections (count=4)://client链接数量Connection{0x747b86ca70, VSyncRequest::None,1000}Connection{0x747b8833d0, VSyncRequest::None,1000}Connection{0x747b877190, VSyncRequest::None,1000}Connection{0x747b87cc90, VSyncRequest::None,10110}
VsyncController:

发现确实appSf也有4个链接,uid 1000是system和10110 是systemui

结合trace打印查看appSf相关的:

回想一下app端如果要请求vsync时候最后是跨进程调用到了如下代码:

frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

binder::Status EventThreadConnection::requestNextVsync() {ATRACE_CALL();mEventThread->requestNextVsync(this);return binder::Status::ok();
}

这里trace中只有个方法的输出,这里可以添加一下,用来区分app还是appSf的EventTread,修改如下:

 std::string toString(const DisplayEventReceiver::Event& event) {
@@ -194,7 +194,10 @@ binder::Status EventThreadConnection::setVsyncRate(int rate) {binder::Status EventThreadConnection::requestNextVsync() {ATRACE_CALL();
+    ATRACE_BEGIN(((impl::EventThread*)mEventThread)->toNameString());//主要线程名字打出到Trace中
+    ALOGE(" EventThreadConnection::requestNextVsync() threadName %s calluid %d",((impl::EventThread*)mEventThread)->toNameString(),(int)mOwnerUid);mEventThread->requestNextVsync(this);
+        ATRACE_END();return binder::Status::ok();}

然后再看trace情况如下:
看sf的clinet端请求vsync
在这里插入图片描述
这里因为tag太小做个标记方便寻找
下面来看具体的apSf的vsync到来

在这里插入图片描述

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

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

相关文章

PyQt学习笔记-获取Hash值的小工具

目录 一、概述1.1 版本信息&#xff1a;1.2 基本信息&#xff1a;1.2.1 软件支持的内容&#xff1a;1.2.2 支持的编码格式 1.3 软件界面图 二、代码实现2.1 View2.2 Controller2.3 Model 三、测试示例 一、概述 本工具居于hashlibPyQtQFileDialog写的小工具&#xff0c;主要是…

【Linux升级之路】8_Linux多线程

目录 一、【Linux初阶】多线程1 | 页表的索引作用&#xff0c;线程基础&#xff08;优缺点、异常、用途&#xff09;&#xff0c;线程VS进程&#xff0c;线程控制&#xff0c;C多线程引入二、【Linux初阶】多线程2 | 分离线程&#xff0c;线程库&#xff0c;线程互斥&#xff0…

【iOS】使用单例封装通过AFNetworking实现的网络请求

这里写目录标题 前言单例封装网络请求1. 首先创建一个继承于NSObject的单例类&#xff0c;笔者这里以Manager对单例类进行命名&#xff0c;然后声明并实现单例类的初始化方法2.实现完单例的创建方法后我们即可通过AFNetworking中的GET方法进行网络请求3.在Controller文件中创建…

免费活动】11月4日敏捷武林上海站 | Scrum.org CEO 亲临现场

活动介绍 过去的几年里&#xff0c;外界的风云变幻为我们的生活增添了一些不一样的色彩。在VUCA世界的浪潮里&#xff0c;每一个人都成为自己生活里的冒险家。面对每一次的变化&#xff0c;勇于探索未知&#xff0c;迎接挑战&#xff0c;努力追逐更好的自己。 七月&#xff0…

Mysql基础与高级汇总

SQL语言分类 DDL:定义 DML&#xff1a;操作 DCL:控制(用于定义访问权限和安全级别) DQL:查询 Sql方言 ->sql&#xff1a;结构化查询语言 mysql:limit oracle:rownum sqlserver:top 但是存储过程&#xff1a;每一种数据库软件一样SQL语法要求: SQL语句可以单行或多行书写&…

【三:Mock服务的使用】

目录 1、工具包2、mock的demo1、get请求2、post请求3、带cookies的请求4、带请求头的请求5、请求重定向 1、工具包 1、&#xff1a;服务包的下载 moco-runner-0.11.0-standalone.jar 下载 2、&#xff1a;运行命令java -jar ./moco-runner-0.11.0-standalone.jar http -p 888…

C# Winform编程(6)高级控件

C# Winform编程&#xff08;6&#xff09;高级控件 RadioButton&#xff08;单选框&#xff09;PictureBox&#xff08;图像框&#xff09;TabControl&#xff08;选项卡&#xff09;ProgressBar(进度条)TrackBar(滑动条)ImageList&#xff08;图像列表控件&#xff09;ToolBar…

Python---死循环概念---while True

在编程中一个靠自身控制无法终止的程序称为“死循环”。 在Python中&#xff0c;我们也可以使用while True来模拟死循环&#xff1a; 代码&#xff1a; while True: print(每天进步一点点) 图示 应用&#xff1a; 比如&#xff0c;在测试里面&#xff0c;自动化测试用例…

Confluence 解决PDF导出乱码问题

1.原因 PDF导出乱码是因为由于服务器缺少必要字体 2.解决办法 下载字体文件将字体文件重命名为simhei.ttf Confluence→管理→PDF导出语言支持&#xff0c;导入字体即可

c#中使用Task.WhenAll

&#x1f680;简介 Task.WhenAll用于等待所有提供的Task对象完成执行。这个方法返回一个新的Task&#xff0c;这个Task将在所有提供的Task完成后完成。如果任何一个Task失败&#xff0c;Task.WhenAll返回的Task也将以异常状态完成。这个方法非常适合在你需要并行执行多个操作&…

垃圾邮件(短信)分类算法实现 机器学习 深度学习 计算机竞赛

文章目录 0 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 垃圾邮件(短信)分类算…

编译安装Nginx+GeoIP2自动更新+防盗链+防爬虫+限制访问速度+限制连接数

此文章是Nginx的GeoIP2模块和MaxMind国家IP库相互结合&#xff0c;达到客户端IP访问的一个数据记录以及分析&#xff0c;同时还针对一些业务需求做出对Nginx中间件的控制&#xff0c;如&#xff1a;防盗链、防爬虫、限制访问速度、限制连接数等 该篇文章是从一个热爱搞技术的博…

SpringSecurity+ Oauth2.0+JWT 0-1

这里写目录标题 准备工作准备SQL添加用户添加依赖准备UserInfoUserMapperUserServiceUserServiceImpl配置SpringDataUserDetailsService 授权服务器&#xff1a;AuthorizationServer配置客户端详细信息管理令牌定义TokenConfig定义AuthorizationServerTokenServices 令牌访问端…

如何让ChatGPT生成图片?

目录 一、那么如何解决让ChatGPT具有画图能力的问题呢&#xff1f; 二、那ChatGPT为什么能生成图片呢&#xff1f; 我们都知道ChatGPT只是个纯文本的AI模型&#xff0c;不具备画图能力。它可以生成文本&#xff0c;但如果让他生成图片就会显示如下的声明&#xff1a; 但通过本…

全网最丑焊锡教程(仅排针焊接心得)

一直以来玩各种开发板&#xff0c;焊接水平太差始终是阻碍我买性价比高的板子的最大原因。淘宝上好多芯片搭载上肥猪流板子是不包排针焊接的。终于下定决心要克服这个困难。不过&#xff0c;只是会焊接排针在高手面前最好不要说自己会焊锡&#xff0c;这应该是两码事。 首先上…

PHP代码审计工具

PHP代码审计工具 1 环境准备 Seay源代码审计系统.exe 和准备靶场的源码php 2 Seay下载地址 https://github.com/f1tz/cnseay安装Seay源代码审计系统.exe报错时&#xff0c;安装.net framework 3.5 # windows插件.net framework 3.5 下砸地址 https://www.microsoft.com/en…

简单秒表设计仿真verilog跑表,源码/视频

名称&#xff1a;简单秒表设计仿真 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 秒表显示最低计时为10ms&#xff0c;最大为59:99&#xff0c;超出返回00&#xff1a;00 具有复位、启动、暂停三个按键 四个数码管分别显示4个时间数字。 演示…

线程是如何在 6 种状态之间转换的?

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 今天我们主要学习线程是如何在 6 种状态之间转换的。 线程的 6 种状态 就像生物从出生到长大、最终死亡的过程一样&#xff0c;线程也有自己的生命周期&#xff0c;在 Java 中线程的生命周期中一共有 6 种状态。 …

在win10上安装配置Hadoop的环境变量

一、背景 在windows10系统中运行seatunnel 二、安装部署 2.1. 下载 Hadoop包 从 Apache Hadoop 官网下载最新版本的 Hadoop&#xff0c;版本号保持与服务端的Hadoop版本一致。 https://hadoop.apache.org/releases.htmlIndex of /apache/hadoop/core/hadoop-3.2.3/ 2.2. 解…

Java持久层框架:MyBatis介绍

MyBatis 概述 概述 MyBatis&#xff0c;是支持定制化 SQL 、存储过程和高级映射的优秀持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用 XML 或注解来配置和映射原生信息&#xff0c;将接口和 Java 的 POJOs&#xff08;Plain …