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

【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;

相关文章:

【android bluetooth 框架分析 02】【Module详解 7】【VendorSpecificEventManager 模块介绍】

1. 背景 我们在 gd_shim_module 介绍章节中&#xff0c;看到 我们将 VendorSpecificEventManager 模块加入到了 modules 中。 // system/main/shim/stack.cc modules.add<hci::VendorSpecificEventManager>();在 ModuleRegistry::Start 函数中我们对 加入的所有 module…...

水滴Android面经及参考答案

static 关键字有什么作用&#xff0c;它修饰的方法可以使用非静态的成员变量吗&#xff1f; static关键字在 Java 中有多种作用。首先&#xff0c;它可以用来修饰变量&#xff0c;被static修饰的变量称为静态变量。静态变量属于类&#xff0c;而不属于类的某个具体实例&#xf…...

工程师必读! 3 个最常被忽略的 TDR 测试关键细节与原理

TDR真的是一个用来看阻抗跟Delay的好工具&#xff0c;通过一个Port的测试就可以看到通道各个位置的阻抗变化。 可是使用上其实没这么单纯&#xff0c;有很多细节需要非常地小心&#xff0c;才可以真正地看到您想看的信息&#xff01; 就让我们整理3个极为重要的TDR使用小细节&…...

C++中的各式类型转换

隐式转换&#xff1a; 基本类型的隐式转换&#xff1a; 当函数参数类型非精确匹配&#xff0c;但是可以转换的时候发生 如&#xff1a; void func1(double x){cout << x << endl; }void func2(char c){cout << c << endl; }int main(){func1(2);//…...

2025年阿里云ACP人工智能高级工程师认证模拟试题(附答案解析)

这篇文章的内容是阿里云ACP人工智能高级工程师认证考试的模拟试题。 所有模拟试题由AI自动生成&#xff0c;主要为了练习和巩固知识&#xff0c;并非所谓的 “题库”&#xff0c;考试中如果出现同样试题那真是纯属巧合。 1、在PAl-Studio实验运行完毕后&#xff0c;可以右键单…...

如何使用scp命令拉取其他虚拟机中的文件

使用 SCP 命令拉取远程虚拟机文件 scp&#xff08;Secure Copy&#xff09;是基于 SSH 协议的安全文件传输工具&#xff0c;可以在本地与远程主机之间复制文件。以下是使用scp从其他虚拟机拉取文件的详细指南&#xff1a; 一、基本语法 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 规则&#xff08;Rule&#xff09;3.2 工作内存&#xff08;Working Memory&#xff09;3.3 知识库&#xff08;Knowledge Base, KieBase&#xff09;3.4 会话&…...

最大子段和(递推)

题目描述 给出一个长度为 n 的序列 a&#xff0c;选出其中连续且非空的一段使得这段和最大。 输入格式 第一行是一个整数&#xff0c;表示序列的长度 n。 第二行有 n 个整数&#xff0c;第 i 个整数表示序列的第 i 个数字 ai​。 输出格式 输出一行一个整数表示答案。 输…...

【计算机视觉】基于深度学习的实时情绪检测系统:emotion-detection项目深度解析

基于深度学习的实时情绪检测系统&#xff1a;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 是否启用&#xff0c;检查内核是否编译了Goodix GT9XX系列触摸屏的驱动支持 Windows CMD.exe输入&#xff1a; adb shell “zcat /proc/config.gz | grep CONFIG_TOUCHSCREEN_GT9XX” 如果返回CONFIG_TOUCHSCREEN_GT9XXy&#xff0c;表示驱动已编…...

【图像处理基石】什么是油画感?

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

AD PCB布线的常用命令

PCB布线顺序&#xff1a;先信号&#xff0c;再电源&#xff0c;再GNG 1.多根走线的应用 将IC上的引脚分类 更改一类引脚以及引线的颜色&#xff0c;画出走线&#xff08;将脚引出&#xff09; 选中这些走线&#xff0c;点击‘交互式总线布线’&#xff0c;便可以多根拉线 shi…...

Python操作Elasticsearch实战指南:从安装到性能调优的全链路解析

一、引言:为什么选择Python+Elasticsearch? Elasticsearch作为分布式搜索引擎,在日志分析、全文检索等场景中表现卓越。Python凭借其简洁语法和丰富生态,成为操作ES的首选语言。本文将带您从环境搭建到性能调优,系统掌握Python操作ES的核心技能。 二、环境准备:三步完成…...

【3-2】HDLC

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

MySQL 学习(八)如何打开binlog日志

目录 一、默认状态二、如何检查 binlog 状态三、如何开启 binlog3.1 临时开启&#xff08;重启后失效&#xff09;3.2 永久开启&#xff08;需修改配置文件&#xff09;3.3 验证是否开启成功3.4 查看 binlog 内容 四、高级配置建议五、注意事项六、开启后的日常维护 知识回顾&a…...

《数据库原理》部分习题解析

《数据库原理》部分习题解析 1. 课本pg196.第1题。 &#xff08;1&#xff09;函数依赖 若对关系模式 R(U) 的任何可能的关系 r&#xff0c;对于任意两个元组 t₁ 和 t₂&#xff0c;若 t₁[X] t₂[X]&#xff0c;则必须有 t₁[Y] t₂[Y]&#xff0c;则称属性集 Y 函数依赖…...

OpenCV进阶操作:光流估计

文章目录 前言一、光流估计1、光流估计是什么&#xff1f;2、光流估计的前提&#xff1f;1&#xff09;亮度恒定2&#xff09;小运动3&#xff09;空间一致 3、OpenCV中的经典光流算法1&#xff09;Lucas-Kanade方法&#xff08;稀疏光流&#xff09;2&#xff09; Farneback方…...

uniapp+vue3开发项目之引入vuex状态管理工具

前言&#xff1a; 我们在vue2的时候常用的状态管理工具就是vuex&#xff0c;vue3开发以后&#xff0c;又多了一个pinia的选项&#xff0c;相对更轻便&#xff0c;但是vuex也用的非常多的&#xff0c;这里简单说下在uni-app中vuex的使用。 实现步骤&#xff1a; 1、安装&#x…...

SparkSQL 连接 MySQL 并添加新数据:实战指南

SparkSQL 连接 MySQL 并添加新数据&#xff1a;实战指南 在大数据处理中&#xff0c;SparkSQL 作为 Apache Spark 的重要组件&#xff0c;能够方便地与外部数据源进行交互。MySQL 作为广泛使用的关系型数据库&#xff0c;与 SparkSQL 的结合可以充分发挥两者的优势。本文将详细…...

面试题:请解释Java中的设计模式,并举例说明单例模式(Singleton Pattern)的实现方式

Java中的设计模式 设计模式是在软件开发过程中针对特定场景而使用的通用解决方案。设计模式可以帮助开发者编写出更加清晰、灵活和可维护的代码。设计模式分为三大类&#xff1a; 创建型模式&#xff1a;用于对象的创建过程&#xff0c;如单例模式、工厂模式、建造者模式等。…...

4. 文字效果/2D-3D转换 - 3D翻转卡片

4. 文字效果/2D-3D转换 - 3D翻转卡片 案例&#xff1a;3D产品展示卡片 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><style type"text/css">.scene {width: 300px;height…...

嵌入式学习笔记 - 关于单片机的位数

通常我们经常说一个单片机是8位的&#xff0c;16位的&#xff0c;32位的&#xff0c;那么怎么判断一款单片机的位数是多少位呢&#xff0c;判断的依据是什么呢&#xff0c; 一 单片机的位数 单片机的位数是指单片机数据总线的宽度&#xff0c;也就是一次能处理的数据的位数&a…...

【AI News | 20250513】每日AI进展

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

mybatisplus 集成逻辑删除

一开始&#xff0c;没去查资料&#xff0c;后面要被AI气死了&#xff0c;先看它的的话 一开始&#xff0c;看ai的描述&#xff0c;我还以为&#xff0c;不需要改数据库&#xff0c;mybatis-puls自动拦截集成就可以实现逻辑删除&#xff0c;c&#xff0c;最后还是要给数据库加一…...

typedef unsigned short uint16_t; typedef unsigned int uint32_t;

你提到的这两行是 C/C 中的类型别名定义&#xff1a; typedef unsigned short uint16_t; typedef unsigned int uint32_t;它们的目的是让代码更具可读性和可移植性&#xff0c;尤其在处理精确位数的整数时非常有用。 ✅ 含义解释 typedef unsigned short uint16_t;…...

SimScape物理建模实例2--带控制的单质量弹簧阻尼系统

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

PyGame游戏开发(含源码+演示视频+开结题报告+设计文档)

前言&#xff1a; 大二小学期python课上基于pygame做的一个游戏小demo&#xff0c;当时老师花了一天讲解了下python基础语法后&#xff08;也是整个大学四年唯一学习python的时间&#xff09;&#xff0c;便让我们自学网课一周然后交项目&#xff0c;所以做的非常仓促&#xff…...

拒绝flash插件打劫!如何在vscode上玩4399小游戏

现在电脑上玩4399都需要flash插件了 这也导致了很多人无法玩到小时候的游戏 今天介绍一款插件 功能强大 即安即玩 首先打开vscode 点开小方框&#xff08;拓展&#xff09;搜索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概述优点缺点适用场景使用体验 框架对比总结如何选择&#xff1f;结语 静态博客框架通过将内容&…...