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

Android12 显示框架之Transaction----client端

目录:Android显示终极宝典

在前面的章节中,应用通过createSurface()在surfaceflinger中创建了一层layer,紧接着要做的事情就是对这个layer设置一些属性(或者叫状态),常设置的属性有位置、大小、z-order等等。那么,client端是如何设置到surfaceflinger中的呢?Android12引入了Transaction机制来传递这些属性到surfaceflinger对应的layer中。

画个简图如下:

本节先从client端开始看,client端主要看三个内容:

  • layer_state_t
  • registerSurfaceControlForCallback()
  • apply()

这三个内容是Transaction的核心,我们逐一来看一下。

layer_state_t

Transaction中还有一类直接针对display设置状态的接口,这里我们就不看了,主要看下layer的内容。

Transaction所有针对layer的接口的共性目的都是在设置layer_state_t这个结构体,对应到surfaceflinger中,则是将所设置的属性保存到layer的mDrawingState中。

//frameworks/native/libs/gui/SurfaceComposerClient.cpp
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer(const sp<SurfaceControl>& sc, int32_t z) {layer_state_t* s = getLayerState(sc);if (!s) {mStatus = BAD_INDEX;return *this;}s->what |= layer_state_t::eLayerChanged;s->what &= ~layer_state_t::eRelativeLayerChanged;s->z = z;registerSurfaceControlForCallback(sc);return *this;
}

另外一点,从代码中可以看到,大部分接口都会去调用registerSurfaceControlForCallback()这个接口,这个接口看似代码量很少,但是由其牵扯出的逻辑还是比较复杂的,需要一点一点展开来看一看吧。

registerSurfaceControlForCallback()

//frameworks/native/libs/gui/SurfaceComposerClient.cpp
void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(const sp<SurfaceControl>& sc) {auto& callbackInfo = mListenerCallbacks[TransactionCompletedListener::getIInstance()];callbackInfo.surfaceControls.insert(sc);TransactionCompletedListener::getInstance()->addSurfaceControlToCallbacks(sc, callbackInfo.callbackIds);
}

看代码可以得到的信息有:只要只调用了这个接口,那么mListenerCallbacks就会有值,且将SurfaceControl保存到其CalllbackInfo的SurfaceControls成员中。

然后进程中还创建了一个TransactionCompletedListener单例,后面会传递给surfaceflinger,而surfaceflinger在处理完transaction后则会回调这个listener。

接着看下addSurfaceControlToCallbacks():

//frameworks/native/libs/gui/SurfaceComposerClient.cpp
void TransactionCompletedListener::addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds) {std::lock_guard<std::mutex> lock(mMutex);for (auto callbackId : callbackIds) {mCallbacks[callbackId].surfaceControls.emplace(std::piecewise_construct,std::forward_as_tuple(surfaceControl->getHandle()),std::forward_as_tuple(surfaceControl));}
}

这个函数的目的是依据registerSurfaceControlForCallback()传进来的SurfaceControl和callbackIds用来构建出listener内部成员mCallbacks的value(callbackTranslation)中的surfaceControls。但是,一般情况下传进来的callbackIds是空值,所以addSurfaceControlToCallbacks()在一般情况下什么也不会做。只有等到addTransactionCallback()被调用后,callbackIds中才有值,在此后addSurfaceControlToCallbacks()才会做有意义的事情。

接着看看addTransactionCallback():

//frameworks/native/libs/gui/SurfaceComposerClient.cpp
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback(TransactionCompletedCallbackTakesContext callback, void* callbackContext,CallbackId::Type callbackType) {auto listener = TransactionCompletedListener::getInstance();auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1,std::placeholders::_2, std::placeholders::_3);const auto& surfaceControls =mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls;CallbackId callbackId =listener->addCallbackFunction(callbackWithContext, surfaceControls, callbackType);mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(callbackId);return *this;
}

先不急着分析它内部的代码,先来看看这个函数被谁调用。搜索code发现它会被addTransactionCompletedCallback()和addTransactionCommittedCallback()调用,而:

  • addTransactionCommittedCallback()会被CTS测试code调用。
  • addTransactionCompletedCallback()会被BLASTBufferQueue和CTS测试code调用。

BLASTBufferQueue会在processNextBufferLocked()的时候将transactionCallbackThunk()注册传递给addTransactionCompletedCallback()函数。第一个参数就是transactionCallbackThunk(),第二个参数是BLASTBufferQueue的this指针,第三个参数是CallbackId::Type::ON_COMPLETE。

现在正式来看addTransactionCallback()的代码做的事情:

  • 首先,它会将传进来的callback重新打包成callbackWithContext;
  • 再者,获取Transaction的mListenerCallbacks内部保存的surfaceControls;
  • 然后,调用addCallbackFunction()将构建的callbackWithContext和获取到的surfaceControls分别保存到CallbackTranslation中并且返回一个callbackId;
  • 最后,将上面返回的callbackId保存到Transaction的mListenerCallbacks的CallbackInfo的callbackIds成员中。

到这里,registerSurfaceControlForCallback()就结束了,它的主要作用是将BLASTBufferQueue和TransactionCompletedListener联系起来。TransactionCompletedListener是基于binder实现的,它被传递给surfaceflinger,完成传递步骤则是在apply()方法内了。

apply()

//frameworks/native/libs/gui/SurfaceComposerClient.cpp
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {if (mStatus != NO_ERROR) {return mStatus;}sp<ISurfaceComposer> sf(ComposerService::getComposerService());bool hasListenerCallbacks = !mListenerCallbacks.empty();std::vector<ListenerCallbacks> listenerCallbacks;// For every listener with registered callbacksfor (const auto& [listener, callbackInfo] : mListenerCallbacks) {auto& [callbackIds, surfaceControls] = callbackInfo;if (callbackIds.empty()) {continue;}if (surfaceControls.empty()) {listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds));} else {// If the listener has any SurfaceControls set on this Transaction update the surface// statefor (const auto& surfaceControl : surfaceControls) {layer_state_t* s = getLayerState(surfaceControl);if (!s) {ALOGE("failed to get layer state");continue;}std::vector<CallbackId> callbacks(callbackIds.begin(), callbackIds.end());s->what |= layer_state_t::eHasListenerCallbacksChanged;s->listeners.emplace_back(IInterface::asBinder(listener), callbacks);}}}cacheBuffers();Vector<ComposerState> composerStates;Vector<DisplayState> displayStates;uint32_t flags = 0;mForceSynchronous |= synchronous;for (auto const& kv : mComposerStates){composerStates.add(kv.second);}displayStates = std::move(mDisplayStates);if (mForceSynchronous) {flags |= ISurfaceComposer::eSynchronous;}if (mAnimation) {flags |= ISurfaceComposer::eAnimation;}// If both mEarlyWakeupStart and mEarlyWakeupEnd are set// it is equivalent for noneif (mEarlyWakeupStart && !mEarlyWakeupEnd) {flags |= ISurfaceComposer::eEarlyWakeupStart;}if (mEarlyWakeupEnd && !mEarlyWakeupStart) {flags |= ISurfaceComposer::eEarlyWakeupEnd;}sp<IBinder> applyToken = mApplyToken? mApplyToken: IInterface::asBinder(TransactionCompletedListener::getIInstance());sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,hasListenerCallbacks, listenerCallbacks, mId);mId = generateId();// Clear the current states and flagsclear();mStatus = NO_ERROR;return NO_ERROR;
}

apply()一般不会传入参数,所以通常它的参数固定为false。

第一个for循环的作用很单纯,就是将transaction中保存的listener存入Surfacecontrol对应layer_state_t(即listeners成员)中去。

cacheBuffers()实际上是做了一个策略,如果这个surface是带buffer的,那么会在transaction内部创建一个BufferCache保存buffer的mId,并且后面随transaction一起传递的也是这个mId(保存在cachedBuffer.id成员中)。

接下来是对flags的设定:eSynchronous的值由apply()的参数和setDisplayProjection()接口来决定,一般情况不会设定。eAnimation、eEarlyWakeupStart和eEarlyWakeupEnd都是由WMS来设定的,在WMS处理窗口动画效果的时候会去设置。

然后调用surfaceflinger的setTransactionState()接口,将应用设置的所有信息传递给它,传递的最后一个参数是一个自增的mId,可以通过这个id值来快速确认client和server直接的调用对应关系。

最后,调用clear()清理掉该transaction涉及到传递的所有成员变量的值。也就是说一个进程在apply()完以后要重新使用这个transaction,则必须重新设置layer_state_t(和DisplayState)。

到此,client端的Transaction就讲完了,后面继续学习下surfaceflinger端是如何处理transaction的。

TransactionCompletedListener

这里简单描述下TransactionCompletedListener是如何被回调的。

surfaceflinger端这里不讲,这里直接掐头去尾直接讲和本节相关的。在setClientStateLocked()函数中会调用TransactionCallbackInvoker的startRegistration()方法将listener保存到mCompletedTransactions中。然后在surfaceflinger处理完transaction后会在handleMessageInvalidate()中调用TransactionCallbackInvoker的sendCallbacks()去回调TransactionCompletedListener的onTransactionCompleted()函数。接着回调callbackFunction(),一路回调到BLASTBufferQueue再到JAVA层。

总结

Transaction的作用是提供给应用统一设置所有需要设置的layer或者display的状态值,以原子操作的形式发送给surfacefinger进行处理,如果应用设置了回调,那么surfacefinger在处理完transaction后会将消息回调到上层。

相关文章:

Android12 显示框架之Transaction----client端

目录&#xff1a;Android显示终极宝典 在前面的章节中&#xff0c;应用通过createSurface()在surfaceflinger中创建了一层layer&#xff0c;紧接着要做的事情就是对这个layer设置一些属性&#xff08;或者叫状态&#xff09;&#xff0c;常设置的属性有位置、大小、z-order等等…...

在Windows上使用FRP搭建内网穿透:

FRP服务器端配置&#xff08;公网服务器&#xff09; 下载FRP&#xff1a; 访问FRP的GitHub发布页面&#xff1a;https://github.com/fatedier/frp/releases下载对应系统架构的frp_<version>_linux_amd64.tar.gz&#xff08;如果你的服务器是Linux系统&#xff09;或者f…...

TypeError: Cannot read properties of undefined (reading ‘scrollIntoView‘)(已解决)

问题复现&#xff1a;眨眼睛使用vitevue3实现跳转dom功能时使用了scrollIntoView方法&#xff0c;在打包上传以后使用该功能报错 小友可能会陷入误区&#xff0c;以为是函数方法有问题&#xff0c;毕竟在开发时是没有问题的&#xff0c; 而实际上呢问题出在获取节点失败了 在这…...

【解决】Unity Inspector 视窗脚本中文乱码问题

开发平台&#xff1a;Unity 2020 编程平台&#xff1a;Visual Studio 2022   问题描述 开发过程中&#xff0c;为便利化快速审阅代码内容&#xff0c;通过 Unity Inspector 确认代码内容与逻辑。但对于默认安装的 Visual Studio 编程平台&#xff0c;保存的 UTF- 8 脚本文件在…...

使用 C/C++访问 MySQL

目录 准备工作 尝试链接 MySQL Client MySQL 接口介绍 准备工作 保证 MySQL 服务有效。下载MySQL开发包&#xff08;可以在MySQL官网下载安装也可以在软件源安装&#xff09; MySQL 开发包通常会包含一些特定的头文件和库文件。您可以检查以下常见的路径&#xff1a; /us…...

Linux 网络套接字解析:实现网络通信

目录 一.网络基础1.协议2.OSI与TCP/IP模型3.网络通信流程4.IP与Mac地址 二.网络编程套接字1.端口号2.网络字节序3.tcp、udp协议4.socket编程5.sockaddr结构解析6.实现Udp_socket7.实现Windows与Linux通信8.Linux下远程执行指令9.实现tcp_socket10.守护进程 一.网络基础 1.协议…...

vue3 组合式API

<!-- 深度监听 deep 点击按钮控制台&#xff0c;才输出count变化了: 1, 老值: 0;否则控制台不输出 --> <script setup>import { ref,watch } from vueconst state ref({count:0})const setCount () > {state.count.value}watch(state, () > {console.log(…...

二、什么是Vue中的响应式?Vue的响应式原理

什么是Vue中的响应式 Vue中的响应式&#xff0c;简而言之就是当数据发生变化时&#xff0c;页面跟随变化。使用过Vue的v-model都有比较深刻的感受&#xff0c;我们在代码中修改双向绑定的数据后&#xff0c;页面上的数据也会自动更新&#xff0c;页面跟随变化 我们看个例子&am…...

快9月了才开始强化,跟张宇还是武忠祥?

快9月了才开始强化&#xff0c;跟张宇还是武忠祥&#xff01; 说真的&#xff0c;我也替这位同学着急&#xff0c;但是考研数学越是进度慢&#xff0c;就越不能急&#xff01;急着赶进度&#xff0c;容易出事&#xff01;遇到这个问题的朋友肯定不止一位&#xff0c;那我就帮大…...

SSM好易学学习平台---附源码92142

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设好易学学习平台。本文…...

对于mp4 ios和mac safari不能播放问题处理

直接对原mp4文件进行重新转码就可以了 ffmpeg -i origin.mp4 -vcodec h264 -profile:v high -level 4.1 orgin_hl.mp4 原因源文件不符合苹果基本规则 苹果官网文档...

开发同城交友找搭子系统app前景分析

开发同城交友系统APP的背景 社交需求多样化&#xff1a; 随着城市化的加速和人们生活节奏的加快&#xff0c;现代人的社交圈子往往较为狭窄&#xff0c;难以结识新朋友。传统的线下交友方式受限于时间、地点等因素&#xff0c;难以满足现代人对于交友的多样化需求。互联网和智…...

faiss向量数据库测试《三体》全集,这家国产AI加速卡,把性能提了7倍!

在人工智能和机器学习技术的飞速发展中&#xff0c;向量数据库在处理高维数据方面扮演着日益重要的角色。近年来&#xff0c;随着大型模型的流行&#xff0c;向量数据库技术也得到了进一步的发展和完善。 向量数据库为大型模型提供了一个高效的数据管理和检索平台&#xff0c;…...

负载均衡---相关概念介绍(一)

负载均衡&#xff08;Load Balance&#xff09;是集群技术的一种重要应用&#xff0c;旨在将负载&#xff08;工作任务&#xff09;进行平衡、分摊到多个操作单元上进行运行&#xff0c;从而提高系统的并发处理能力、增加吞吐量、加强网络处理能力&#xff0c;并提供故障转移以…...

计算机基础知识复习8.14

子线程抛异常主线程能否catch 在不做任何处理的情况下&#xff0c;主线程不能catch 解决方式&#xff1a; 子线程使用try catch来捕获异常 为线程设置未捕获异常处理器UncaughtExceptionHandler 通过future的get方法捕获异常 JVM相关参数 显示指定堆内存-Xms和-Xmx指定最…...

【io深层理解】

io深层理解 1.内核态2.用户态3. select IO多路复用执行原理4. select io多路复用限制和不足 1.内核态 一个进程会涉及多文件的修改&#xff0c;比如说。那么在内核态就会维护一个表&#xff0c;这个表叫文件描述符bitmap&#xff0c;这个表会传递给内核态&#xff0c;当然肯定传…...

【懒人工具】指定新文件,替换全盘旧文件

没辙&#xff0c;就是懒 最近在调整.clang-format&#xff0c;这个format文件要跟着项目走&#xff0c;只换本地默认的还不够。调整好以后一个项目一个项目的换&#xff0c;有时候会漏掉&#xff0c;索性全盘一次性换完。 基于自己操作的流程&#xff0c;写了个脚本&#xff0…...

React+Vis.js(02):设置节点样式

文章目录 1、修改vis.js的节点和关系颜色2、修改vis.js节点的字体颜色2.1 统一设置节点字体颜色2.2 自定义某个节点的字体颜色3、设置vis.js节点的边框颜色和宽度3.1 设置单个节点3.2 统一设置1、修改vis.js的节点和关系颜色 在vis.js中,可以通过color属性,来给node节点添加…...

3G网络要彻底没了

2月21日,三大运营商公布了最新的用户数据,移动联通电信三家5G套餐用户数合计超过了7.5亿。信通院早前公布的数据显示,一月份,国内市场5G手机出货量2632.4万部,占同期手机出货量的79.7%。 这两项数据,说明我们已经进入到了5G时代,5G的普及速度远超很多人的想象。就在5G逐…...

如何配置ESXI主机的IP地址管理

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

【SpringBoot自动化部署】

SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一&#xff0c;能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时&#xff0c;需要添加Git仓库地址和凭证&#xff0c;设置构建触发器&#xff08;如GitHub…...