【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 都要执行那下面几步:
-
创建module 实体
- Module* instance = module->ctor_();
-
将 当前 module 实体和 gd_stack_thread 线程绑定
- set_registry_and_handler(instance, thread);
-
启动当前模块所依赖的所有子模块。
- instance->ListDependencies(&instance->dependencies_);
- Start(&instance->dependencies_, thread);
-
最后调用自己的 Start() 函数
- instance->Start();
-
将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 实体
- 创建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 线程绑定
- 将 当前 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.启动当前模块所依赖的所有子模块
- 启动当前模块所依赖的所有子模块。
- 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() 函数
- 最后调用自己的 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_
- 将module 实体加入到 started_modules_
- started_modules_[module] = instance;
相关文章:
【android bluetooth 框架分析 02】【Module详解 7】【VendorSpecificEventManager 模块介绍】
1. 背景 我们在 gd_shim_module 介绍章节中,看到 我们将 VendorSpecificEventManager 模块加入到了 modules 中。 // system/main/shim/stack.cc modules.add<hci::VendorSpecificEventManager>();在 ModuleRegistry::Start 函数中我们对 加入的所有 module…...

水滴Android面经及参考答案
static 关键字有什么作用,它修饰的方法可以使用非静态的成员变量吗? static关键字在 Java 中有多种作用。首先,它可以用来修饰变量,被static修饰的变量称为静态变量。静态变量属于类,而不属于类的某个具体实例…...

工程师必读! 3 个最常被忽略的 TDR 测试关键细节与原理
TDR真的是一个用来看阻抗跟Delay的好工具,通过一个Port的测试就可以看到通道各个位置的阻抗变化。 可是使用上其实没这么单纯,有很多细节需要非常地小心,才可以真正地看到您想看的信息! 就让我们整理3个极为重要的TDR使用小细节&…...

C++中的各式类型转换
隐式转换: 基本类型的隐式转换: 当函数参数类型非精确匹配,但是可以转换的时候发生 如: void func1(double x){cout << x << endl; }void func2(char c){cout << c << endl; }int main(){func1(2);//…...
2025年阿里云ACP人工智能高级工程师认证模拟试题(附答案解析)
这篇文章的内容是阿里云ACP人工智能高级工程师认证考试的模拟试题。 所有模拟试题由AI自动生成,主要为了练习和巩固知识,并非所谓的 “题库”,考试中如果出现同样试题那真是纯属巧合。 1、在PAl-Studio实验运行完毕后,可以右键单…...
如何使用scp命令拉取其他虚拟机中的文件
使用 SCP 命令拉取远程虚拟机文件 scp(Secure Copy)是基于 SSH 协议的安全文件传输工具,可以在本地与远程主机之间复制文件。以下是使用scp从其他虚拟机拉取文件的详细指南: 一、基本语法 bash # 从远程主机复制到本地 scp [选…...

Nacos源码—9.Nacos升级gRPC分析七
大纲 10.gRPC客户端初始化分析 11.gRPC客户端的心跳机制(健康检查) 12.gRPC服务端如何处理客户端的建立连接请求 13.gRPC服务端如何映射各种请求与对应的Handler处理类 14.gRPC简单介绍 10.gRPC客户端初始化分析 (1)gRPC客户端代理初始化的源码 (2)gRPC客户端启动的源码…...
从入门到精通:Drools全攻略
目录 一、Drools 初相识二、快速上手 Drools2.1 环境搭建2.2 第一个 Drools 程序 三、深入理解 Drools 核心概念3.1 规则(Rule)3.2 工作内存(Working Memory)3.3 知识库(Knowledge Base, KieBase)3.4 会话&…...
最大子段和(递推)
题目描述 给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。 输入格式 第一行是一个整数,表示序列的长度 n。 第二行有 n 个整数,第 i 个整数表示序列的第 i 个数字 ai。 输出格式 输出一行一个整数表示答案。 输…...

【计算机视觉】基于深度学习的实时情绪检测系统:emotion-detection项目深度解析
基于深度学习的实时情绪检测系统:emotion-detection项目深度解析 1. 项目概述2. 技术原理与模型架构2.1 核心算法1) 数据预处理流程2) 改进型MobileNetV2 2.2 系统架构 3. 实战部署指南3.1 环境配置3.2 数据集准备3.3 模型训练3.4 实时推理 4. 常见问题与解决方案4.…...
Windows CMD通过adb检查触摸屏Linux驱动是否被编译
检查 CONFIG_TOUCHSCREEN_GT9XX 是否启用,检查内核是否编译了Goodix GT9XX系列触摸屏的驱动支持 Windows CMD.exe输入: adb shell “zcat /proc/config.gz | grep CONFIG_TOUCHSCREEN_GT9XX” 如果返回CONFIG_TOUCHSCREEN_GT9XXy,表示驱动已编…...

【图像处理基石】什么是油画感?
在图像处理中,“油画感”通常指图像呈现出类似油画的块状纹理、笔触痕迹或色彩过渡不自然的现象,表现为细节模糊、边缘不锐利、颜色断层或人工纹理明显。这种问题常见于照片处理、视频帧截图或压缩后的图像,本质是画质受损的一种表现。以下是…...

AD PCB布线的常用命令
PCB布线顺序:先信号,再电源,再GNG 1.多根走线的应用 将IC上的引脚分类 更改一类引脚以及引线的颜色,画出走线(将脚引出) 选中这些走线,点击‘交互式总线布线’,便可以多根拉线 shi…...
Python操作Elasticsearch实战指南:从安装到性能调优的全链路解析
一、引言:为什么选择Python+Elasticsearch? Elasticsearch作为分布式搜索引擎,在日志分析、全文检索等场景中表现卓越。Python凭借其简洁语法和丰富生态,成为操作ES的首选语言。本文将带您从环境搭建到性能调优,系统掌握Python操作ES的核心技能。 二、环境准备:三步完成…...

【3-2】HDLC
前言 前面我们提到了 PSTN(Public Switched Telephone Network) ,今天介绍一种很少见的数据链路层的协议,HDLC! 文章目录 前言1. 定义2. 帧边界3. 零比特填充4. 控制字段4.1. 信息帧(I帧)4.2. …...

MySQL 学习(八)如何打开binlog日志
目录 一、默认状态二、如何检查 binlog 状态三、如何开启 binlog3.1 临时开启(重启后失效)3.2 永久开启(需修改配置文件)3.3 验证是否开启成功3.4 查看 binlog 内容 四、高级配置建议五、注意事项六、开启后的日常维护 知识回顾&a…...
《数据库原理》部分习题解析
《数据库原理》部分习题解析 1. 课本pg196.第1题。 (1)函数依赖 若对关系模式 R(U) 的任何可能的关系 r,对于任意两个元组 t₁ 和 t₂,若 t₁[X] t₂[X],则必须有 t₁[Y] t₂[Y],则称属性集 Y 函数依赖…...

OpenCV进阶操作:光流估计
文章目录 前言一、光流估计1、光流估计是什么?2、光流估计的前提?1)亮度恒定2)小运动3)空间一致 3、OpenCV中的经典光流算法1)Lucas-Kanade方法(稀疏光流)2) Farneback方…...
uniapp+vue3开发项目之引入vuex状态管理工具
前言: 我们在vue2的时候常用的状态管理工具就是vuex,vue3开发以后,又多了一个pinia的选项,相对更轻便,但是vuex也用的非常多的,这里简单说下在uni-app中vuex的使用。 实现步骤: 1、安装&#x…...
SparkSQL 连接 MySQL 并添加新数据:实战指南
SparkSQL 连接 MySQL 并添加新数据:实战指南 在大数据处理中,SparkSQL 作为 Apache Spark 的重要组件,能够方便地与外部数据源进行交互。MySQL 作为广泛使用的关系型数据库,与 SparkSQL 的结合可以充分发挥两者的优势。本文将详细…...
面试题:请解释Java中的设计模式,并举例说明单例模式(Singleton Pattern)的实现方式
Java中的设计模式 设计模式是在软件开发过程中针对特定场景而使用的通用解决方案。设计模式可以帮助开发者编写出更加清晰、灵活和可维护的代码。设计模式分为三大类: 创建型模式:用于对象的创建过程,如单例模式、工厂模式、建造者模式等。…...

4. 文字效果/2D-3D转换 - 3D翻转卡片
4. 文字效果/2D-3D转换 - 3D翻转卡片 案例:3D产品展示卡片 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><style type"text/css">.scene {width: 300px;height…...
嵌入式学习笔记 - 关于单片机的位数
通常我们经常说一个单片机是8位的,16位的,32位的,那么怎么判断一款单片机的位数是多少位呢,判断的依据是什么呢, 一 单片机的位数 单片机的位数是指单片机数据总线的宽度,也就是一次能处理的数据的位数&a…...

【AI News | 20250513】每日AI进展
AI Repos 1、iap-diffusion-labs 从零开始带我们构建完整的扩散模型。通过三个精心设计的实验练习,循序渐进地引导我们实现流匹配和扩散模型,从基础 SDE 到条件图像生成,每一步都有详尽指导和完整代码,让复杂理论简单易懂。主要内…...

mybatisplus 集成逻辑删除
一开始,没去查资料,后面要被AI气死了,先看它的的话 一开始,看ai的描述,我还以为,不需要改数据库,mybatis-puls自动拦截集成就可以实现逻辑删除,c,最后还是要给数据库加一…...
typedef unsigned short uint16_t; typedef unsigned int uint32_t;
你提到的这两行是 C/C 中的类型别名定义: typedef unsigned short uint16_t; typedef unsigned int uint32_t;它们的目的是让代码更具可读性和可移植性,尤其在处理精确位数的整数时非常有用。 ✅ 含义解释 typedef unsigned short uint16_t;…...

SimScape物理建模实例2--带控制的单质量弹簧阻尼系统
模型下载: 基于simscape,单质量系统带位置控制资源-CSDN文库 在实例1中,我们搭建了不带控制的单质量弹簧阻尼系统,该系统没有外界力量介入,只有弹簧的初始弹力,带着弹簧使劲弹来弹去。 SimScape物理建模实…...

PyGame游戏开发(含源码+演示视频+开结题报告+设计文档)
前言: 大二小学期python课上基于pygame做的一个游戏小demo,当时老师花了一天讲解了下python基础语法后(也是整个大学四年唯一学习python的时间),便让我们自学网课一周然后交项目,所以做的非常仓促ÿ…...

拒绝flash插件打劫!如何在vscode上玩4399小游戏
现在电脑上玩4399都需要flash插件了 这也导致了很多人无法玩到小时候的游戏 今天介绍一款插件 功能强大 即安即玩 首先打开vscode 点开小方框(拓展)搜索4399 认准4399 on vscode点击安装 安装完毕后 按下 Ctrl Shift P , 输入 4399 on VSCode 或…...
五大静态博客框架对比:Hugo、Hexo、VuePress、MkDocs、Jekyll
目录 1. Hugo概述优点缺点适用场景使用体验 2. Hexo概述优点缺点适用场景使用体验 3. VuePress概述优点缺点适用场景使用体验 4. MkDocs概述优点缺点适用场景使用体验 5. Jekyll概述优点缺点适用场景使用体验 框架对比总结如何选择?结语 静态博客框架通过将内容&…...