Android SurfaceFlinger——通知消费流程(三十五)

         上一篇文章介绍了 onFrameAvailable() 函数的流程,最终回调到了 BLASTBufferQueue 中,这里测处理跟 Android 老版本还是有区别的,在 BLASTBufferQueue 中通过提交事务的方式通知 SurfaceFlinger 进行更新,而不是老版本中的直接调用 SurfaceFlinger 中的对应函数。这里我们就来看一下 提交事务的通知流程。

一、提交事务

        上一篇文章中的  t->setApplyToken(mApplyToken).apply() 其实调用的就是 SurfaceComposerClient 中的 apply() 函数。

1、SurfaceComposerClient.cpp 

源码位置:/frameworks/native/libs/gui/SurfaceComposerClient.cpp 

status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay) {……// 获取 SurfaceComposer 服务sp<ISurfaceComposer> sf(ComposerService::getComposerService());bool hasListenerCallbacks = !mListenerCallbacks.empty();std::vector<ListenerCallbacks> listenerCallbacks;// 处理监听器回调for (const auto& [listener, callbackInfo] : mListenerCallbacks) {auto& [callbackIds, surfaceControls] = callbackInfo;……if (surfaceControls.empty()) {listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds));} else {// 如果侦听器在此事务上设置了任何surfacecontrol,则更新Surface状态for (const auto& surfaceControl : surfaceControls) {layer_state_t* s = getLayerState(surfaceControl);……std::vector<CallbackId> callbacks(callbackIds.begin(), callbackIds.end());s->what |= layer_state_t::eHasListenerCallbacksChanged;s->listeners.emplace_back(IInterface::asBinder(listener), callbacks);}}}……// 提交事务sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,hasListenerCallbacks, listenerCallbacks, mId);……
}

        该方法是 SurfaceFlinger 客户端与服务端通信的关键部分,用于提交所有待处理的层和显示更改。通过这个方法,客户端可以控制层的显示属性、动画、同步模式以及监听器回调等,确保所有更改被原子性地应用到系统中。 

2、SurfaceFlinger.cpp

源码位置:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

setTransactionState

status_t SurfaceFlinger::setTransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {……IPCThreadState* ipc = IPCThreadState::self();const int originPid = ipc->getCallingPid();const int originUid = ipc->getCallingUid();// 记录事务状态。创建一个 TransactionState 结构体,封装了事务的所有必要信息TransactionState state{frameTimelineInfo,  states,displays,           flags,applyToken,         inputWindowCommands,desiredPresentTime, isAutoTimestamp,uncacheBuffer,      postTime,permissions,        hasListenerCallbacks,listenerCallbacks,  originPid,originUid,          transactionId};……if (mTransactionTracing) {mTransactionTracing->addQueuedTransaction(state);}// 将事务加入队列,准备处理。queueTransaction(state);// 检查挂起状态以确保事务是同步的.if (state.transactionCommittedSignal) {waitForSynchronousTransaction(*state.transactionCommittedSignal);}return NO_ERROR;
}

        该方法是 SurfaceFlinger 服务端处理来自客户端事务请求的关键入口点。它不仅处理事务数据,还执行必要的权限检查,确保只有授权的客户端才能执行特定的操作。此外,它还支持事务的同步和异步执行,以及事务的追踪,这对于系统稳定性和性能优化至关重要。 

queueTransaction 

void SurfaceFlinger::queueTransaction(TransactionState& state) {state.queueTime = systemTime();Mutex::Autolock lock(mQueueLock);……// 加入事务队列mTransactionQueue.emplace_back(state);ATRACE_INT("TransactionQueue", mTransactionQueue.size());// 根据事务的标志位(state.flags)调用schedule lambda函数,确定事务的调度策略const auto schedule = [](uint32_t flags) {if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart;return TransactionSchedule::Late;}(state.flags);const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;// 设置事务标志setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
}

        该方法是 SurfaceFlinger 处理事务队列的核心部分,它不仅负责将事务加入队列,还根据事务的特性和需求调整了事务的调度策略,确保了事务能够按照预期的顺序和优先级得到处理。通过这种方式,SurfaceFlinger 能够有效地管理多个并发事务,保证系统的响应性和稳定性。 

3、Scheduler

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.h

schedule

// 在主线程上调度异步或同步任务
template <typename F, typename T = std::invoke_result_t<F>>
[[nodiscard]] std::future<T> schedule(F&& f) {// 创建Taskauto [task, future] = makeTask(std::move(f));// 接收一个任务对象,并将其发送到消息队列中postMessage(std::move(task));return std::move(future);
}

        该函数允许用户以一种简洁的方式异步执行代码,并通过 std::future 管理异步操作的结果。这种设计模式在多线程编程中非常常见,尤其是在需要处理大量异步事件和任务的场景中。这里调用了 makeTask() 创建任务并将其发送到消息队列中。

Scheduler

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp

Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features): impl::MessageQueue(compositor), mFeatures(features), mSchedulerCallback(callback) {}

        可以看到 Scheduler 继承 MessageQueue,所以上面调用的是 MessageQueue 中的 makeTask() 函数。

4、MessageQueue

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.h

makeTask

template <typename F>
inline auto makeTask(F&& f) {sp<Task<F>> task = new Task<F>(std::move(f));return std::make_pair(task, task->mTask.get_future());
}

        这里将一个可调用对象 f 封装成一个可以异步执行的任务,并返回一个包含任务对象和一个 std::future 对象的 std::pair。

template <typename F>
class Task : public MessageHandler {template <typename G>friend auto makeTask(G&&);explicit Task(F&& f) : mTask(std::move(f)) {}void handleMessage(const Message&) override { mTask(); }using T = std::invoke_result_t<F>;std::packaged_task<T()> mTask;
};

        这里可以看到上面的任务消息最终会在 handleMessage() 函数中进行处理。即 Scheduler.cpp 的  handleMessage() 函数中。

handleMessage

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp

MessageQueue::MessageQueue(ICompositor& compositor): MessageQueue(compositor, sp<Handler>::make(*this)) {}void MessageQueue::Handler::handleMessage(const Message&) {// 更新帧待处理状态mFramePending.store(false);const nsecs_t frameTime = systemTime();auto& compositor = mQueue.mCompositor;// 提交当前帧if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {return;}// 合成帧compositor.composite(frameTime, mVsyncId);// 采样compositor.sample();
}

        该方法的流程反映了典型的帧渲染管线的一部分,包括帧提交、合成和采样等关键步骤。这些操作通常在接收到 VSync 信号或其他触发消息时执行,确保了屏幕内容的及时更新和渲染效率。而这里的 ICompositor 是 SurfaceFlinger 在初始化 Scheduler 时传进来的参数。

5、SurfaceFlinger.cpp

initScheduler

void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {mScheduler = std::make_unique<scheduler::Scheduler>(static_cast<ICompositor&>(*this),static_cast<ISchedulerCallback&>(*this), features);{auto configs = display->holdRefreshRateConfigs();……mScheduler->createVsyncSchedule(features);mScheduler->setRefreshRateConfigs(std::move(configs));}setVsyncEnabled(false);mScheduler->startTimers();……
}

        所以上面的 compositor.XXX() 调用的是 SurfaceFlinger 总的对应方法,这就与 SurfaceFlinger 核心类建立了连接。

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

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

相关文章

学习React(描述 UI)

React 是一个用于构建用户界面&#xff08;UI&#xff09;的 JavaScript 库&#xff0c;用户界面由按钮、文本和图像等小单元内容构建而成。React 帮助你把它们组合成可重用、可嵌套的 组件。从 web 端网站到移动端应用&#xff0c;屏幕上的所有内容都可以被分解成组件。在本章…

netty应用-手写RPC

文章目录 手写RPC之案例定位与通信过程介绍RPC框架案例定位服务端与客户端架构通信过程1. 服务注册与发现2. 请求序列化与传输3. 请求处理与响应4. 响应反序列化与结果处理实现细节1. 服务端2. 客户端技术选型关键挑战总结手写RPC之请求响应通信协议定制协议结构示例消息头格式…

GO集成方式、Java文字识别接口集成方法

我们现在经常使用到的那些软件、APP、微信小程序产品来说&#xff0c;在注册的时候需要手动填写一些证件信息的时候已经可以通过上传证件照片自动填写信息了&#xff0c;这就是OCR API的功劳&#xff0c;接入翔云OCR API的系统可以自动识别用户上传的证件信息并填写到相应的栏目…

优化医疗数据管理:Kettle ETL 数据采集方案详解

在现代医疗保健领域&#xff0c;数据的准确性、完整性和及时性对于提高医疗服务质量和患者护理至关重要。为了有效管理和利用医疗数据&#xff0c;Kettle ETL&#xff08;Extract, Transform, Load&#xff09;数据采集方案成为了许多医疗机构的首选工具之一。本文将深入探讨Ke…

【基础算法总结】队列 + 宽搜(BFS)

队列 宽搜BFS 1.N 叉树的层序遍历2.二叉树的锯齿形层序遍历3.二叉树最大宽度4.在每个树行中找最大值 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#…

MySQL作业五

1. 创建表goods&#xff0c;orders 2. 向商品表中插入商品记录 3. 触发器操作 3.1 建立触发器&#xff0c;订单表中增加订单数量后&#xff0c;商品表商品数量同步减少对应的商品订单出数量,并测试 3.2 建立触发器&#xff0c;实现功能:客户取消订单&#xff0c;恢复商品表对应…

C语言文件锁Linux

在C语言中&#xff0c;flock 是一个用于文件锁定的函数&#xff0c;定义在 sys/file.h 头文件中。它的主要目的是在对文件进行读写操作时&#xff0c;避免其他进程同时访问文件&#xff0c;以实现文件的并发控制。 flock 函数的原型 #include <sys/file.h>int flock(in…

java数据结构之排序

前言&#xff1a; 排序在我们日常生活中随处可见&#xff0c;这里将介绍java数据结构里面常见的几种排序。 ps: swap函数的实现&#xff1a; public void swap(int[] arr, int i, int j) {int tmp arr[i];arr[i] arr[j];arr[j] tmp; } 1.直接插入排序 &#xff08;1&a…

类与对象(补充)

初始化列表 1. 之前我们实现构造函数时&#xff0c;初始化成员变量主要使用函数体内赋值&#xff0c;构造函数初始化还有一种方式&#xff0c;就是初始化列表&#xff0c;初始化列表的使用方式是以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个…

【OpenCV C++20 学习笔记】序列化——XML和YAML文件处理

序列化——XML和YAML文件处理 序列化和反序列化代码实现XML/YAML文件的打开和关闭写入或读取文本和数字写入或读取OpenCV数据写入或读取数组以及map读取和写入自定义数据类型 输出结果 序列化和反序列化 如果希望永久保存某些对象&#xff0c;而不是每次运行程序的时候重新创建…

经典文献阅读之--LIV-GaussMap(实时3D辐射场地图渲染的LiDAR惯性视觉融合算法)

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…

如何优化网站以提升UX设计质量

什么叫 UX 设计&#xff1f;UX 设计&#xff0c;即用户体验设计&#xff0c;是指为提升用户体验而进行的产品设计。 UX 在设计中&#xff0c;设计师通过调查和研究用户来掌握用户的需求和喜好&#xff0c;并利用这些信息来设计产品。设计师还会测试产品&#xff0c;以确保它们能…

【Python】成功解决读文件错误:`IOError: [Errno 0] Error`

【Python】成功解决读文件错误&#xff1a;IOError: [Errno 0] Error 在Python编程中&#xff0c;处理文件是常见的任务之一&#xff0c;但偶尔也会遇到各种错误&#xff0c;包括IOError。尽管Python 3.x中IOError已被OSError和FileNotFoundError等更具体的异常所取代&#xf…

【原创】【C++继承】【考法总结】派生类对象隐式转换为基类对象

&#xff08;一&#xff09;背景引入 尽管派生类对象也是基类对象&#xff0c;但派生类类型和基类类型是不同的。在公用继承&#xff08;public继承&#xff09;中&#xff0c;派生类对象能作为基类对象处理。由于派生类具有对应每个基类成员的成员&#xff08;派生类的成员通常…

爬虫基本原理入门

在互联网时代&#xff0c;数据是驱动一切业务的核心资源之一。而爬虫技术&#xff0c;作为获取互联网数据的重要手段&#xff0c;被广泛应用于数据分析、信息聚合、搜索引擎优化等多个领域。本文将带你走进爬虫世界&#xff0c;了解爬虫的基本原理和基本概念&#xff0c;帮助你…

学习笔记之Java篇(0725)

p this 普通方法中&#xff0c;this总是指向调用该方法的对象。 构造方法中&#xff0c;this总是指向正要初始化的对象。 this&#xff08;&#xff09;调用必须重载的构造方法&#xff0c;避免相同地址初始化代码&#xff0c;但只能在构造方法中用&#xff0c;比企鹅必须位…

不让录制的屏幕如何绕开?轻松突破录屏限制:三招搞定App录屏难题

在数字时代&#xff0c;屏幕录制已成为分享知识和记录重要信息的必备技能。然而&#xff0c;有些应用程序出于版权保护或其他原因&#xff0c;限制了屏幕录制功能。这是否意味着我们束手无策呢&#xff1f;当然不是&#xff01;本文将为您揭秘三种简单易行的方法&#xff0c;让…

html+css前端作业 王者荣耀官网1个页面(带报告)

htmlcss前端作业 王者荣耀官网1个页面&#xff08;带报告&#xff09; 下载地址 https://download.csdn.net/download/qq_42431718/89575045 目录1 目录2 项目视频 王者荣耀首页1个页面&#xff08;无js&#xff09; 页面1

【QT】SARibbon编译安装开启frameless(QWindowkit)

1.cmake开启frameless 2.检查cmakecache 3.下载编译qwindowkit 拉取saribbon时请 git clone https://github.com/czyt1988/SARibbon.git --recursive使用--recursive可以拉取第三方库 手动下载&#xff1a;https://github.com/stdware/qwindowkit 4.cmake构建 和 visual stu…

2024-07-24 Linux C語言使用inotify进行文件变化检测

一、在Linux中&#xff0c;用C语言检测文件内容变化的方法有几种&#xff0c;最常用的包括以下几种&#xff1a; 轮询&#xff08;Polling&#xff09;&#xff1a;周期性地读取文件并检查内容是否变化。inotify&#xff1a;使用Linux内核提供的inotify接口&#xff0c;这是一…