Android SurfaceFlinger——注册监听调用流程(七)

        这一篇我们介绍一下 IComposer 中的另一个比较重要的方法,通过注册监听 Hal 层实现监听驱动的关键动作。

一、注册监听

        在前面文章 SurfaceFlinger 的 init() 方法中,我们注册了一个 Callback 到 Hal 层中。最终通过 HIDL 调用到 Hal 层。

1、SurfaceFlinger.cpp

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

void SurfaceFlinger::init() {ALOGI(  "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W...");Mutex::Autolock _l(mStateLock);……mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));mCompositionEngine->getHwComposer().setCallback(*this);……ALOGV("Done initializing");
}

        这里通过  getHwComposer() 获取对应的 HWComposer 实例,然后调用 HWComposer 的 setCallback() 方法设置监听。

SurfaceFlinger::getHwComposer

HWComposer& SurfaceFlinger::getHwComposer() const {return mCompositionEngine->getHwComposer();
}

        mCompositionEngine 参数在 SurfaceFlinger.h 中定义。

SurfaceFlinger.h

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

std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;

        所以,上面最终调用的是 CompositionEngine 中的 getHwComposer() 方法。

CompositionEngine::getHwComposer 

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

HWComposer& CompositionEngine::getHwComposer() const {return *mHwComposer.get();
}

        这里最终返回的是一个 HwComposer,在 DisplayDevice.h 中定义。

DisplayDevice.h

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

class HWComposer;
……
HWComposer& mHwComposer;

        所以上面最终调用的是 HWComposer 中的 setCallback() 方法。

2、HWComposer.cpp  

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

void HWComposer::setCallback(HWC2::ComposerCallback& callback) {loadCapabilities();loadLayerMetadataSupport();if (mRegisteredCallback) {ALOGW("Callback already registered. Ignored extra registration attempt.");return;}mRegisteredCallback = true;mComposer->registerCallback(callback);
}

       可以看到这里调用了 Composer 的 registerCallback() 方法,而 HidlComposerHal 继承了 Composer,最终调用的是 HidlComposerHal 的 registerCallback() 方法。

3、HidlComposerHal.cpp

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

void HidlComposer::registerCallback(ComposerCallback& callback) {const bool vsyncSwitchingSupported = isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching);registerCallback(sp<ComposerCallbackBridge>::make(callback, vsyncSwitchingSupported));
}void HidlComposer::registerCallback(const sp<IComposerCallback>& callback) {android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);auto ret = [&]() {if (mClient_2_4) {return mClient_2_4->registerCallback_2_4(callback);}return mClient->registerCallback(callback);}();if (!ret.isOk()) {ALOGE("failed to register IComposerCallback");}
}

        这里的 mClient 为 sp<V2_1::IComposerClient>,所以这里调用到 ComposerClient 的 registerCallback() 方法。

4、ComposerClient.h

源码位置:/hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h

Hal* const mHal;Return<void> registerCallback(const sp<IComposerCallback>& callback) override {// 没有锁,因为我们要求这个函数只被调用一次mHalEventCallback = std::make_unique<HalEventCallback>(mHal, callback, mResources.get());mHal->registerEventCallback(mHalEventCallback.get());return Void();
}

        可以看到在这里面会把 IComposerCallback 再一次包裹成 HalEventCallback 对象(后面回回调的时候会分析),才会注册到 mHal,也就是 HwcHalImpl 对象。

5、HwcHal.h

源码位置:/hardware/interfaces/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcHal.h

void registerEventCallback(hal::ComposerHal::EventCallback* callback) override {mEventCallback = callback;mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,reinterpret_cast<hwc2_function_pointer_t>(refreshHook));mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
}

        此时将会调用 mDispatch 的 registerCallback 方法。其实这个方法是一个模版方法,其实就是调用 mDevice 的 registerCallback 方法,并且把后面几个作为参数设置进去。从上文就解析到 mDevice 其实是 hw2_device_t 结构体也是 HWC2On1Adapter,那么其实就是调用 HWC2On1Adapter 中的注册方法。

6、HWC2On1Adapter

源码位置:/hardware/interfaces/graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp

Error HWC2On1Adapter::registerCallback(Callback descriptor,hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {// 有效性验证if (!isValid(descriptor)) {return Error::BadParameter;}ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(), callbackData, pointer);// 获取互斥锁std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);// 回调注册/注销if (pointer != nullptr) {mCallbacks[descriptor] = {callbackData, pointer};} else {ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());mCallbacks.erase(descriptor);return Error::None;}bool hasPendingInvalidate = false;std::vector<hwc2_display_t> displayIds;std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;// 根据descriptor的类型,收集需要在注册回调后立即处理的待处理事件(如刷新、垂直同步、热插拔)if (descriptor == Callback::Refresh) {hasPendingInvalidate = mHasPendingInvalidate;if (hasPendingInvalidate) {for (auto& displayPair : mDisplays) {displayIds.emplace_back(displayPair.first);}}mHasPendingInvalidate = false;} else if (descriptor == Callback::Vsync) {for (auto pending : mPendingVsyncs) {auto hwc1DisplayId = pending.first;if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId);continue;}auto displayId = mHwc1DisplayMap[hwc1DisplayId];auto timestamp = pending.second;pendingVsyncs.emplace_back(displayId, timestamp);}mPendingVsyncs.clear();} else if (descriptor == Callback::Hotplug) {// 热插拔主显示器pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY], static_cast<int32_t>(Connection::Connected));for (auto pending : mPendingHotplugs) {auto hwc1DisplayId = pending.first;if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d", hwc1DisplayId);continue;}auto displayId = mHwc1DisplayMap[hwc1DisplayId];auto connected = pending.second;pendingHotplugs.emplace_back(displayId, connected);}}// 调用未持有状态锁的挂起回调lock.unlock();// 处理回调if (hasPendingInvalidate) {auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);for (auto displayId : displayIds) {refresh(callbackData, displayId);}}if (!pendingVsyncs.empty()) {auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);for (auto& pendingVsync : pendingVsyncs) {vsync(callbackData, pendingVsync.first, pendingVsync.second);}}if (!pendingHotplugs.empty()) {auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);for (auto& pendingHotplug : pendingHotplugs) {hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);}}return Error::None;
}

        该函数充当 HWC1 与 HWC2 之间的桥梁,转换事件并管理通过注册的回调向 HWC2 客户端传递这些事件,同时确保了正确的同步机制。 

        可以看到有 2 个集合,一个标志位在 Hal 判断是否需要回调当顶层。当 mPendingHotplugs 存在还没有被通知的屏幕热插拔消息的时候将会调用 hotplug。当 mPendingVsyncs 存在还没有通知到的屏幕的同步也会调用 vsync。如果需要刷新则会有 hasPendingInvalidate 设置 true 的标志。但是,如果是 SurfaceFlinger 第一次进来就肯定不会有回调,因为此时还没有任何的拿到底层的任何数据。但是会把当前的监听类型和回调的方法指针都保存到 mCallbacks 数组中。

        此时就会直接转型为每一个回调到上层,此时就是 HwcHalImpl 中的 refreshHook、hotplugHook 和 vsyncHook。

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

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

相关文章

Java从小白到入职 视频教程 下载 因为太大存百度云盘4.zip

Java从小白到入职 视频教程 下载 1---战前准备_00-课程介绍&个人简介.mp4 2---战前准备_00-02-学习方法.mp4 3---战前准备_00-03-你的角色.mp4 4---战前准备_00-04-学习工具.mp4 5---战前准备_00-05-技术岗位概述-Web前端.mp4 6---战前准备_00-06-技术岗位概述-Java语…

Jenkins+gitee流水线部署springboot项目

目录 前言 一、软件版本/仓库 二、准备工作 2.1 安装jdk 11 2.2 安装maven3.9.7 2.3 安装docker 2.4 docker部署jenkins容器 三、jenkins入门使用 3.1 新手入门 3.2 jenkins设置环境变量JDK、MAVEN、全局变量 3.2.1 jenkins页面 3.2.2 jenkins容器内部终端 3.2.3 全…

购物返利系统中的数据处理与优化策略

购物返利系统中的数据处理与优化策略 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 随着电商行业的不断发展&#xff0c;购物返利系统作为一种常见的营销手段…

python-赏月

[题目描述] 在某个星球上看到的月亮大小有一个规律&#xff0c;月亮为每30天一个周期&#xff0c;在这30天的周期里&#xff0c;月亮的大小分别为 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1。 虽然天气很冷&#xff0c;但这个星球上的某个居民今…

MyBatis 源码分析--SqlSessionFactory

前言&#xff1a; 前文我们简单的回顾了 MyBatis 的基本概念&#xff0c;有聊到核心组件&#xff0c;工作流程等&#xff0c;本篇我们开始深入剖析 MyBatis 的核心源码&#xff0c;欢迎大家持续关注。 Mybatis 知识传送门 初识 MyBatis 【MyBatis 核心概念】 MyBatis 源码解…

钒能新材料综合回收利用,钒溶液净化富集工艺之离子交换法

钒电池储能产业作为典型的绿色低碳优势产业&#xff0c;是新型储能领域重要发展方向。钒电池储能具备大规模、长周期等优势&#xff0c;是储能领域的重要组成部分&#xff0c;将成为拓展电能利用、应对可再生能源随机波动、支撑可再生能源高占比电力系统的最佳技术途径之一。 …

力扣1019.链表中的下一个更大节点

力扣1019.链表中的下一个更大节点 从左到右 每个数确定下一个更大节点后 弹出栈中存下标 即res.size() class Solution {public:vector<int> nextLargerNodes(ListNode* head) {vector<int> res;stack<int> st;for(auto ihead;i;ii->next){while(!st.e…

openEuler 24.03 LTS - 华为欧拉开源版(华为 RHEL 兼容发行版)

openEuler 24.03 LTS - 华为欧拉开源版&#xff08;华为 RHEL 兼容发行版&#xff09; 华为红帽企业 Linux 兼容发行版 请访问原文链接&#xff1a;https://sysin.org/blog/openeuler/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sy…

Haproxy部署Web群集

HAProxy是一款开源的、高性能的TCP/HTTP负载均衡器和代理服务器&#xff0c;广泛应用于提高网站和应用的可用性和性能。本篇博客将介绍如何使用HAProxy部署一个高可用的Web集群。 目录 环境准备 安装HAProxy 配置HAProxy 配置解析 配置Web服务器 环境准备 假设我们有以下服…

【C++题解】1026 - 求商数和余数

问题&#xff1a;1026 - 求商数和余数 类型&#xff1a;基础问题 题目描述&#xff1a; 输入 a,b 两个整数&#xff0c;编程求出 a 除以 b 得到的商和余数。 输入&#xff1a; 输入一行&#xff0c;只有两个整数(中间有空格)。 输出&#xff1a; 输出只有一行&#xff0c…

【数学】Leetcode 69. x 的平方根【简单】

x 的平方根 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a; 不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0.5 。 示…

nginx升级漏洞补丁

nginx漏洞补丁升级 1、安装patch patch未找到命令&#xff0c;请先下载patch-2.7.6.tar.gz。下载路径&#xff1a;https://mirrors.aliyun.com/gnu/patch/ # 解压 tar -zxf patch-2.7.6.tar.gz # 编译、检查并安装 Patch time { ./configure --prefix/usr && make &am…

优思学院|质量管理中如何应用5W1H或5W2H方法?

5W1H或者5W2H其实是一种"工作方式"&#xff0c;它不是"思考方法"&#xff0c;这种工作方式是通过回答“什么&#xff08;What&#xff09;&#xff1f;为什么&#xff08;Why&#xff09;&#xff1f;谁&#xff08;Who&#xff09;&#xff1f;何时&#…

信创国产化全家桶(统信UOS操作系统、瀚高数据库、东方通、电科网安、卫士通、海康威视国产视频插件arm、x86、mips)解决方案

序言&#xff1a; 最近由国产化项目&#xff0c;需要全套信创产品序列&#xff0c;涉及国产化软件和硬件的整合集成&#xff0c;后端工程是spring boot2&#xff0c;前端工程是vue2 &#xff0c;记录分享一下&#xff1a; 1、国产化操作系统统信uos 后端java工程spring boot…

求解FAT表大小

540M/1K 540k 540 * 1024 b 512k对应2的19次方<540k<1024k对应2的20次方 取比540k大的1024k 八位一个字节 20对应2.5个字节 所以FAT占用 2.5*5401350k 1.2G/1k1.2M 1M1024k对应2的20次方<1.2M<2M对应2的21次方 取2M 21/8是循环小数不可以直接用 所以四舍五…

动态规划以及分治算法的例子

动态规划&#xff08;Dynamic Programming, DP&#xff09; 是一种在数学、计算机科学和经济学中使用的&#xff0c;通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。 动态规划的核心概念 最优子结构…

什么电脑录屏软件好用?这里有3款超实用推荐!

在当今数字化时代&#xff0c;电脑录屏软件已经成为了人们日常学习和工作中不可或缺的工具。无论是录制游戏实况、制作教程视频&#xff0c;还是保存线上会议的内容&#xff0c;一款好用的电脑录屏软件都显得尤为重要。可是什么电脑录屏软件好用呢&#xff1f;本文将为大家介绍…

Redis-数据类型-Set(不允许重复)

文章目录 1、查看redis是否启动2、通过客户端连接redis3、切换到2数据库4、给key指定的set集合中存入数据&#xff0c;set会自动去重5、返回可以指定的set集合中所有的元素6、返回集合中元素的数量(set cardinality)7、检查当前指定member是否是集合中的元素8、从集合中删除元素…

文件扫描工具哪个好?便捷的文件扫描工具推荐

对于初入职场的大学毕业生&#xff0c;申请就业补贴是一项不可忽视的福利。 它不仅能够为新生活带来经济上的缓解&#xff0c;也有助于职业生涯的顺利起步。面对申请过程中需提交的文件&#xff0c;如纸质劳动合同&#xff0c;不必烦恼。市面上众多文件扫描软件能助你一臂之力…

关于html内嵌vuejs使用iframe无法加载vue实例解决方案,使用bootstrap再iframe

描述&#xff1a;html内嵌vuejs&#xff0c;manage页面也采用vue进行iframe跳转&#xff0c;这个时候无法加载vue实例。具体原因不明&#xff0c;解决方案如下&#xff1a;bootstrap做管理页面&#xff0c;再通过iframe加载html内嵌vue的页面 <!DOCTYPE html> <html …