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

news2024/9/22 11:29:40

目录: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 callbacks
    for (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
            // state
            for (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 none
    if (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 flags
    clear();

    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后会将消息回调到上层。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RM悬挂系统

悬挂系统是汽车的车架与车桥或车轮之间的一切传力连接装置的总称&#xff0c;其作用是传递作用在车轮和车架之间的力和力扭&#xff0c;并且缓冲由不平路面传给车架或车身的冲击力&#xff0c;并衰减由此引起的震动&#xff0c;以保证汽车能平稳地行驶。 其主要由减震器和弹簧组…

PictureSelector自定义路径首页不显示数据的问题

1、依赖导入和源码查看 网址&#xff1a;https://github.com/LuckSiege/PictureSelector/tree/version_component 使用PictureSelector 2、自定义路径的实现&#xff1a; 使用方法&#xff1a;setLoaderFactoryEngine进行设置 见[read.md] (https://github.com/LuckSiege/Pi…

C++ wxWidgets图形界面开发用什么IDE最好?

在主流免费的IDE工具中&#xff0c;我们可以想到的支持cmake项目的工具就只有QtCreator&#xff0c;VisualStudio&#xff0c;VSCode这三个。其中QtCreator和VSCode支持WIndows&#xff0c;Mac&#xff0c;WIndows三大主流平台。但是VSCode在Ubuntu等系统下的支持并没有在WIndo…

VMware Esxi 7.0 安装P40显卡疑难杂症小诊断

第一章、小叙 今天安装一台X99主板的机器&#xff0c;操作系统是VMware Esxi 7.0&#xff0c;配备一张P40显卡&#xff0c;显卡已在Esxi硬件中识别到&#xff0c;但是无法安装驱动&#xff0c;安装完驱动之后无法分配给虚拟机&#xff0c;如图所示为识别的硬件。 第二章、安装显…

Spark-SparkSubmit详细过程

一、概览 《Spark-环境启动》中讲了Spark环境的启动&#xff0c;以及Master和多个Worker之间时基于Endpoint之间的Netty通信&#xff0c;也被称为Spark的RpcEnv。在此基础上我们来看下spark-submit是如何将我们写的Spark程序调起的 二、启动脚本示例&#xff1a; spark-subm…

css通过keyframes实现文字定时向上滚动

一、效果 二、代码 <!DOCTYPE html> <html lang="en"><head>

软考软件设计师-备考须知

&#x1f939;‍♀️潜意识起点&#xff1a;个人主页 &#x1f399;座右铭&#xff1a;得之坦然&#xff0c;失之淡然。 &#x1f48e;擅长领域&#xff1a;大前端 是的&#xff0c;我需要您的&#xff1a; &#x1f9e1;点赞❤️关注&#x1f499;收藏&#x1f49b; 是我…

【hot100篇-python刷题记录】【矩阵置零】

R5-矩阵篇 印象题&#xff0c;思路即可&#xff1a; 手动置0 无非就是行和列都置0 使用thex和they将该元素的i和y存储起来&#xff0c;再分别遍历thex&#xff0c;将所有y的位置置0 遍历they&#xff0c;将所有x 置0 class Solution:def setZeroes(self, matrix: List[List…

【机器学习】(基础篇六) —— 数据集的划分和过拟合问题

数据集的划分 训练集和测试集 在机器学习中&#xff0c;数据集通常会被划分为训练集&#xff08;Training Set&#xff09;和测试集&#xff08;Test Set&#xff09;&#xff0c;有时还会包括一个验证集&#xff08;Validation Set&#xff09;。这样的划分是为了能够更好地…

Ⅰ、基于 WebGPU 从 0 到 1 渲染 GLTF:第一个三角形

Ⅰ、基于 WebGPU 从 0 到 1 渲染 GLTF&#xff1a;第一个三角形 WebGPU 是一种面相网页的现代图形 API&#xff0c;由主要浏览器供应商开发。与 WebGL 相比&#xff0c;WebGPU 对 GPU 提供了更直接的控制&#xff0c;使应用程序能更有效地利用硬件&#xff0c;类似于 Vulkan 和…

深度学习设计模式之外观模式

文章目录 前言一、介绍二、特点三、详细分析1.核心组成2.代码示例3.优缺点优点缺点 4.使用场景 总结 前言 外观模式是结构型设计模式&#xff0c;定义一个高层接口&#xff0c;用来访问子系统中的众多接口&#xff0c;使系统更加容易使用。 一、介绍 外观设计模式&#xff08…

低代码与AI:赋能企业数字化转型

引言 随着全球经济的快速发展和科技的飞速进步&#xff0c;数字化转型已成为各个行业和企业发展的重要趋势。数字化转型的背景不仅是提升效率和竞争力的手段&#xff0c;更是适应市场变化、满足客户需求的必由之路。 在当今信息化时代&#xff0c;技术的变革推动了企业运营方式…

【Python机器学习】MapReduce(分布式计算的框架)

MapReduce的优缺点&#xff1a; 优点&#xff1a;可在短时间内完成大量工作&#xff1b; 缺点&#xff1a;算法必须经过重写&#xff0c;需要对系统工程有一定的理解&#xff1b; 适用数据类型&#xff1a;数值型和标称型数据。 MapReduce是一个软件框架&#xff0c;可以将单个…

SQL UA注入 (injection 第十八关)

简介 SQL注入&#xff08;SQL Injection&#xff09;是一种常见的网络攻击方式&#xff0c;通过向SQL查询中插入恶意的SQL代码&#xff0c;攻击者可以操控数据库&#xff0c;SQL注入是一种代码注入攻击&#xff0c;其中攻击者将恶意的SQL代码插入到应用程序的输入字段中&a…

[Python学习日记-10] Python中的流程控制(if...else...)

简介 假如把写程序比做走路&#xff0c;那我们到现在为止&#xff0c;一直走的都是直路&#xff0c;还没遇到过分叉口&#xff0c;想象现实中&#xff0c;你遇到了分叉口&#xff0c;然后你决定往哪拐必然是有所动作的。你要判断那条岔路是你真正要走的路&#xff0c;如果我们想…

合宙LuatOS AIR700 IPV6 TCP 客户端向NodeRed发送数据

为了验证 AIR700 IPV6 &#xff0c;特别新建向NodeRed Tcp发送的工程。 Air700发送TCP数据源码如下&#xff1a; --[[ IPv6客户端演示, 仅EC618系列支持, 例如Air780E/Air600E/Air780UG/Air700E ]]-- LuaTools需要PROJECT和VERSION这两个信息 PROJECT "IPV6_SendDate_N…

Leetcode面试经典150题-155.最小栈

解法都在代码里&#xff0c;不懂就留言或者私信 我写了两种解法&#xff0c;建议选择双栈的&#xff0c;感觉这才是考察点 /**一般解法&#xff1a;过个笔试没问题&#xff0c;建议用双栈的方法 */ class MinStack2 {/**至少应该有一个栈用于保存数据 对于push和pop以及top的话…

STM32之SPI读写W25Q128芯片

SPI简介 STM32的SPI是一个串行外设接口。它允许STM32微控制器与其他设备&#xff08;如传感器、存储器等&#xff09;进行高速、全双工、同步的串行通信。通常包含SCLK&#xff08;串行时钟&#xff09;、MOSI&#xff08;主设备输出/从设备输入Master Output Slave Input&…

【React Hooks - useState状态批量更新原理】

概述 所谓批量处理就是当在同时更新多个状态下&#xff0c;能够统一批量处理更新&#xff0c;避免了重复渲染。在React17及之前版本&#xff0c;React只会在合成事件以及生命周期内部进行批量处理&#xff0c;在setTimeout、Promise、Fetch等异步请求中&#xff0c;则不会自动…

【GH】【EXCEL】P1: Write DATA SET from GH into EXCEL

文章目录 WriteFast WriteGH data material :GH process and components instructionFast Write DataFast Write Data & Clear DataFast Write to Cell EXCEL written results Write by ColumnGH data material :Compile ColumnGH process and components instructionWrite…