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

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。

相关文章:

  • 如何最简单的方式使用nodejs中的http-server发布轻量级的html网页
  • settings和toolchains.xml 区别用法配置
  • Android中球体碰撞代码分享-kotlin,入门版
  • 【数据结构与算法】树的存储,森林 详解
  • @PreAuthorize与@Secured注解的区别是什么?
  • 【Java】已解决java.net.HttpRetryException异常
  • html侧导航栏客服栏
  • 【Nprogress】页面跳转进度条
  • 广告联盟流量变现app开发
  • 搜索进入AI蓝海时代:谁在成为新玩家?
  • 小程序项目业务逻辑回忆1
  • 赶紧收藏!2024 年最常见 20道设计模式面试题(九)
  • 【机器学习300问】129、RNN如何在情感分析任务中起作用的?
  • 信息技术课如何禁止学生玩游戏
  • 【Gradio】Custom Components | Gradio组件关键概念 后端
  • ----------
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 讲清楚之javascript作用域
  • 人脸识别最新开发经验demo
  • 事件委托的小应用
  • 算法之不定期更新(一)(2018-04-12)
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 微信小程序开发问题汇总
  • 一个SAP顾问在美国的这些年
  • 用mpvue开发微信小程序
  • 用Python写一份独特的元宵节祝福
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • 湖北分布式智能数据采集方法有哪些?
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • 如何用纯 CSS 创作一个货车 loader
  • ​2021半年盘点,不想你错过的重磅新书
  • ​人工智能书单(数学基础篇)
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • #NOIP 2014# day.1 T2 联合权值
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #vue3 实现前端下载excel文件模板功能
  • #微信小程序:微信小程序常见的配置传旨
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(泛型类的类构造函数)
  • (solr系列:一)使用tomcat部署solr服务
  • (二刷)代码随想录第16天|104.二叉树的最大深度 559.n叉树的最大深度● 111.二叉树的最小深度● 222.完全二叉树的节点个数
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (未解决)macOS matplotlib 中文是方框
  • (五)MySQL的备份及恢复
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET Core 发展历程和版本迭代
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET简谈设计模式之(单件模式)
  • @Bean注解详解
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [.net] 如何在mail的加入正文显示图片
  • [24年新算法]NRBO-XGBoost回归+交叉验证基于牛顿拉夫逊优化算法-XGBoost多变量回归预测