【android bluetooth 框架分析 02】【Module詳解 7】【VendorSpecificEventManager 模塊介紹】

1. 背景

我們在 gd_shim_module 介紹章節中,看到 我們將 VendorSpecificEventManager 模塊加入到了 modules 中。

// system/main/shim/stack.cc
modules.add<hci::VendorSpecificEventManager>();

在 ModuleRegistry::Start 函數中我們對 加入的所有 module 挨個初始化。
而在該函數中啟動一個 module 都要執行那下面幾步:

  1. 創建module 實體

    • Module* instance = module->ctor_();
  2. 將 當前 module 實體和 gd_stack_thread 線程綁定

    • set_registry_and_handler(instance, thread);
  3. 啟動當前模塊所依賴的所有子模塊。

    • instance->ListDependencies(&instance->dependencies_);
    • Start(&instance->dependencies_, thread);
  4. 最后調用自己的 Start() 函數

    • instance->Start();
  5. 將module 實體加入到 started_modules_

    • started_modules_[module] = instance;

本篇文章就拿 hal::VendorSpecificEventManager 模塊來具體分析一下 他的啟動。

2. modules.add

我們先來看一下 在調用 modules.add 時, 到底做了那些事情。

modules.add<hal::VendorSpecificEventManager>();
class ModuleList {friend Module;friend ModuleRegistry;public:template <class T>void add() {list_.push_back(&T::Factory); // add 時 添加的是 hal::VendorSpecificEventManager::Factory}private:std::vector<const ModuleFactory*> list_;
};
  • 從代碼中不難發現, 我們是將 hal::HciLayer::Factory 加入到 list_ 中的。
// system/gd/hci/vendor_specific_event_manager.cc
const ModuleFactory VendorSpecificEventManager::Factory =ModuleFactory([]() { return new VendorSpecificEventManager(); });// 這里在創建 ModuleFactory 對象時, 傳入了一個 函數, 這個函數 去 new VendorSpecificEventManager 對象
  • 這里在創建 ModuleFactory 對象時, 傳入了一個 函數,但是并沒有去調用這個函數。
    • 這個函數的目的是 去 new VendorSpecificEventManager 對象
class ModuleFactory {friend ModuleRegistry;friend FuzzTestModuleRegistry;public:ModuleFactory(std::function<Module*()> ctor);private:std::function<Module*()> ctor_;
};//  system/gd/module.cc
ModuleFactory::ModuleFactory(std::function<Module*()> ctor) : ctor_(ctor) {
}
  • 在創建 ModuleFactory 對象時, 也僅僅是將 如下的函數賦值給了 ModuleFactory::ctor_ 函數指針。
[]() { return new VendorSpecificEventManager(); }

3. 模塊具體啟動流程

1. 創建module 實體

  1. 創建module 實體
    • Module* instance = module->ctor_();
[]() { return new VendorSpecificEventManager(); }
  • 這里就會去實際觸發 該函數,去創建 VendorSpecificEventManager 對象。
  • 也就是說, modules.addhal::VendorSpecificEventManager() 模塊對應的 實體其實是 VendorSpecificEventManager 對象。
class VendorSpecificEventManager : public ::bluetooth::Module {}
  • VendorSpecificEventManager 繼承 Module
VendorSpecificEventManager::VendorSpecificEventManager() {pimpl_ = std::make_unique<impl>(this);
}
  • 在 VendorSpecificEventManager 構造函數里面, 創建了 VendorSpecificEventManager::impl 對象。

2. 將 當前 module 實體和 gd_stack_thread 線程綁定

  1. 將 當前 module 實體和 gd_stack_thread 線程綁定
    • set_registry_and_handler(instance, thread);
void ModuleRegistry::set_registry_and_handler(Module* instance, Thread* thread) const {instance->registry_ = this;instance->handler_ = new Handler(thread);
}
  • 將我們的 gd_stack_thread 對應的 handle 直接保存在 Module->handler_ 中。
Handler* Module::GetHandler() const {ASSERT_LOG(handler_ != nullptr, "Can't get handler when it's not started");return handler_;
}
  • 通過 Module::GetHandler() 來獲取當前 handler_

3.啟動當前模塊所依賴的所有子模塊

  1. 啟動當前模塊所依賴的所有子模塊。
    • instance->ListDependencies(&instance->dependencies_);
    • Start(&instance->dependencies_, thread);
// system/gd/hci/vendor_specific_event_manager.cc
void VendorSpecificEventManager::ListDependencies(ModuleList* list) const {list->add<hci::HciLayer>();list->add<hci::Controller>();
}
  • 從上面的代碼中可以看到 VendorSpecificEventManager 模塊依賴
    • HciLayer 模塊, 在之前已經啟動了。
    • Controller 模塊,之前沒有啟動。 此時就會觸發 Controller 模塊的 啟動流程。 這個我們在下節討論。

4. 最后調用自己的 Start() 函數

  1. 最后調用自己的 Start() 函數
    • instance->Start();

1. VendorSpecificEventManager::Start

void VendorSpecificEventManager::Start() {pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
}
  • 直接調用了 VendorSpecificEventManager::impl::start 函數。

2. VendorSpecificEventManager::impl::start

// 如下是 VendorSpecificEventManager::impl::start 的實現void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {module_handler_ = handler;hci_layer_ = hci_layer;controller_ = controller;hci_layer_->RegisterEventHandler(EventCode::VENDOR_SPECIFIC, handler->BindOn(this, &VendorSpecificEventManager::impl::on_vendor_specific_event)); // 向 hciLayer 層,注冊 VENDOR_SPECIFIC 事件的回調vendor_capabilities_ = controller->GetVendorCapabilities(); // 獲取 contoller 芯片支持的能力}
1. 注冊 VENDOR_SPECIFIC 事件的回調

我們在介紹 hciLayer 模塊時, 就介紹過 RegisterEventHandler 的使用。 這里不再贅述。
當我們收到 VENDOR_SPECIFIC 相關的事件后,就會回調 VendorSpecificEventManager::impl::on_vendor_specific_event 方法

2. on_vendor_specific_event
void on_vendor_specific_event(EventView event_view) {auto vendor_specific_event_view = VendorSpecificEventView::Create(event_view);ASSERT(vendor_specific_event_view.IsValid());VseSubeventCode vse_subevent_code = vendor_specific_event_view.GetSubeventCode();if (subevent_handlers_.find(vse_subevent_code) == subevent_handlers_.end()) {LOG_WARN("Unhandled vendor specific event of type 0x%02hhx", vse_subevent_code);return;}// 會從 subevent_handlers_ 中繼續找到 子事件的回調。subevent_handlers_[vse_subevent_code].Invoke(vendor_specific_event_view);}
3. subevent_handlers_

std::map<VseSubeventCode, common::ContextualCallback<void(VendorSpecificEventView)>> subevent_handlers_;
  • subevent_handlers_ 是一個 map.

那么 subevent_handlers_ 中的子事件 回調是怎么注冊進來的?


// VendorSpecificEventManager::impl::register_eventvoid register_event(VseSubeventCode event, common::ContextualCallback<void(VendorSpecificEventView)> handler) {ASSERT_LOG(subevent_handlers_.count(event) == 0,"Can not register a second handler for %02hhx (%s)",event,VseSubeventCodeText(event).c_str());subevent_handlers_[event] = handler;}

void VendorSpecificEventManager::RegisterEventHandler(VseSubeventCode event, common::ContextualCallback<void(VendorSpecificEventView)> handler) {CallOn(pimpl_.get(), &impl::register_event, event, handler);
}
  • 整個 VendorSpecificEventManager 很簡單,主要就是 對外提供 RegisterEventHandler 方法。管理廠商相關事件的回調。

VendorSpecificEventManager::RegisterEventHandler 函數主要用在 LeScanningManager 和 LeScanningManager 模塊。 等介紹 這倆模塊時,我們在展開介紹。

5.將module 實體加入到 started_modules_

  1. 將module 實體加入到 started_modules_
    • started_modules_[module] = instance;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79695.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79695.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79695.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

小剛說C語言刷題—1080質因子

1.題目描述 任意輸入一正整數 N &#xff0c;求出它的所有質因子。如&#xff1a;10&#xff1d;25&#xff0c;20&#xff1d;225。 輸入 輸入只有一行&#xff0c;包括 11個整數 n (1≤n≤32768) 輸出 輸出若干行&#xff0c;按從小到大的順序給出這個數的所有質因子&am…

C語言中的宏

1.防止頭文件重復包含 1.#pragma once #pragma once 是一個編譯器指令&#xff0c;用于防止頭文件被重復包含。它的核心作用是通過簡單語法替代傳統的頭文件保護宏&#xff08;#ifndef/#define/#endif&#xff09;&#xff0c;提升代碼簡潔性和可維護性。 作用詳解 防止重復…

MapReduce 模型

?引言? MapReduce 是分布式計算領域的里程碑式模型&#xff0c;由 Google 在 2004 年論文中首次提出&#xff0c;旨在簡化海量數據處理的復雜性。其核心思想是通過函數式編程的 ?Map? &#xff08;映射&#xff09;和 ?Reduce? &#xff08;歸約&#xff09;階段&#x…

Linux文件編程——標準庫函數fopen、fread、fwrite等函數

1. fopen — 打開文件 函數原型&#xff1a; FILE *fopen(const char *filename, const char *mode);參數&#xff1a; filename&#xff1a;要打開的文件名&#xff0c;可以是相對路徑或絕對路徑。 mode&#xff1a;文件打開模式&#xff0c;表示文件的操作方式&#xff08…

從 Git 到 GitHub - 使用 Git 進行版本控制 - Git 常用命令

希望本貼能從零開始帶您一起學習如何使用 Git 進行版本控制&#xff0c;并結合遠程倉庫 GitHub。這會是一個循序漸進的指南&#xff0c;我們開始吧&#xff01; 學習 Git 和 GitHub 的路線圖&#xff1a; 理解核心概念&#xff1a;什么是版本控制&#xff1f;Git 是什么&…

2025.05.11拼多多機考真題算法崗-第四題

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? 筆試突圍OJ 04. 記憶碎片重組 問題描述 盧小姐正在開發一款名為"記憶碎片"的游戲,玩家需要分析混亂的記憶數據,推測出形成這些記憶的原始序列。游戲中,記憶數據存儲在一個特殊的數…

Android Exoplayer多路不同時長音視頻混合播放

在上一篇Android Exoplayer 實現多個音視頻文件混合播放以及音軌切換中我們提到一個問題&#xff0c;如果視頻和音頻時長不一致&#xff0c;特別是想混合多個音頻和多個視頻時就會出問題&#xff0c;無法播放。報錯如下&#xff1a; E/ExoPlayerImplInternal(11191): Playback…

Datawhale PyPOTS時間序列5月第1次筆記

課程原地址&#xff1a; https://github.com/WenjieDu/PyPOTS&#xff08;Package地址&#xff09; https://github.com/WenjieDu/BrewPOTS/tree/datawhale/202505_datawhale&#xff08;Tutorial地址&#xff09; 2.1 PyPOTS簡介 PyPOTS 是一個專為處理部分觀測時間序列&a…

網安學途—流量分析 attack.pcap

attack.pacp 使用Wireshark查看并分析虛擬機windows 7桌面下的attack.pcapng數據包文件&#xff0c;通過分析數據包attack.pcapng找出黑客的IP地址&#xff0c;并將黑客的IP地址作為FLAG &#xff08;形式&#xff1a;[IP地址]&#xff09;提交&#xff1a; 過濾器篩選&#x…

【大模型】DeepResearcher:通用智能體通過強化學習探索優化

DeepResearcher&#xff1a;通過強化學習在真實環境中擴展深度研究 一、引言二、技術原理&#xff08;一&#xff09;強化學習與深度研究代理&#xff08;二&#xff09;認知行為的出現&#xff08;三&#xff09;模型架構 三、實戰運行方式&#xff08;一&#xff09;環境搭建…

go語言實現IP歸屬地查詢

效果: 實現代碼main.go package mainimport ("encoding/json""fmt""io/ioutil""net/http""os" )type AreaData struct {Continent string json:"continent"Country string json:"country"ZipCode …

基于STM32、HAL庫的SGTL5000XNLA3R2音頻接口芯片驅動程序設計

一、簡介: SGTL5000XNLA3R2 是 Cirrus Logic 推出的高性能、低功耗音頻編解碼器,專為便攜式和電池供電設備設計。它集成了立體聲 ADC、DAC、麥克風前置放大器、耳機放大器和數字信號處理功能,支持 I2S/PCM 音頻接口和 I2C 控制接口,非常適合與 STM32 微控制器配合使用。 二…

window 顯示驅動開發-報告圖形內存(一)

計算圖形內存 在 VidMm 能夠向客戶端報告準確的帳戶之前&#xff0c;它必須首先計算圖形內存的總量。 VidMm 使用以下內存類型和公式來計算圖形內存&#xff1a; 系統總內存 此值是操作系統可訪問的系統內存總量。 BIOS 分配的內存不會出現在此數字中。 例如&#xff0c;一臺…

[FA1C4] 博客鏈接

Blog Link 博客已經從 CSDN 轉移 高情商&#xff1a;博客是給人看的 低情商&#xff1a;CSDN 已經爛了根本不能看 鏈接: https://fa1c4.github.io/

python通過curl訪問deepseek的API調用案例

廢話少說&#xff0c;開干&#xff01; API申請和充值 下面是deepeek的API網站 https://platform.deepseek.com/ 進去先注冊&#xff0c;是不是手機賬號密碼都不重要&#xff0c;都一樣&#xff0c;完事充值打米&#xff0c;主要是打米后左側API Keys里面創建一個API Keys&am…

【計算機視覺】OpenCV項目實戰:基于face_recognition庫的實時人臉識別系統深度解析

基于face_recognition庫的實時人臉識別系統深度解析 1. 項目概述2. 技術原理與算法設計2.1 人臉檢測模塊2.2 特征編碼2.3 相似度計算 3. 實戰部署指南3.1 環境配置3.2 數據準備3.3 實時識別流程 4. 常見問題與解決方案4.1 dlib安裝失敗4.2 人臉檢測性能差4.3 誤識別率高 5. 關鍵…

第6章: SEO與交互指標

第6章: SEO與交互指標 在當今的SEO環境中&#xff0c;Google越來越重視用戶交互指標&#xff0c;如頁面停留時長、交互性能等。本章將深入探討如何優化網頁速度和用戶交互體驗&#xff0c;以提升SEO效果和用戶滿意度。 1. Google的新時代SEO指標 隨著互聯網技術的發展&#xff…

Starrocks的主鍵表涉及到的MOR Delete+Insert更新策略

背景 寫這個文章的作用主要是做一些總結和梳理&#xff0c;特別是正對大數據場景下的實時寫入更新策略 COW 和 MOR 以及 DeleteInsert 的技術策略的演進&#xff0c; 這也適用于其他大數據的計算存儲系統。該文章主要參考了Primary Key table. 分析總結 Starrocks 的主鍵表主…

C 語言_常見排序算法全解析

排序算法是計算機科學中的基礎內容,本文將介紹 C 語言中幾種常見的排序算法,包括實現代碼、時間復雜度分析、適用場景和詳細解析。 一、冒泡排序(Bubble Sort) 基本思想:重復遍歷數組,比較相鄰元素,將較大元素交換到右側。 代碼實現: void bubbleSort(int arr[], i…

JIT+Opcache如何配置才能達到性能最優

首先打開php.ini文件&#xff0c;進行配置 1、OPcache配置 ; 啟用OPcache opcache.enable1; CLI環境下啟用OPcache&#xff08;按需配置&#xff09; opcache.enable_cli0; 預加載腳本&#xff08;PHP 7.4&#xff0c;加速常用類&#xff09; ; opcache.preload/path/to/prel…