美文网首页
Android gd -- Gabeldorsche Blue

Android gd -- Gabeldorsche Blue

作者: 打出了枫采 | 来源:发表于2022-12-09 16:18 被阅读0次

Gabeldorsche Architecture

谷歌宣布新版本的 Gabeldorsche,即自版本 11 以来在 Android 中使用的蓝牙堆栈,用Rust重写的BT Stack (准确的说是一些BT底层核心)

From: https://android.googlesource.com/platform//system/bt/+/ce7fbfcc74e7908aa733131df374ac2421d75d57/gd/docs/architecture/architecture.md#gabeldorsche-architecture

内容

本文档概述了开发 Gabeldorsche (GD) 蓝牙堆栈时所做的一些架构注意事项。

threading-model

首先,GD 堆栈不建立在线程的概念之上。相反,它适用于Handlers. 但是,由于GD最终运行在OS上,在实现Handler抽象之前,它仍然需要与进程和线程进行交互。

processes

一般来说。GD运行时环境中存在三种类型的进程:

应用程序进程:包括第三方应用程序、其他系统组件(例如音频和电信服务)与通过各种 RPC/IPC 方法(例如 Binder、Socket IPC、gRPC、DBUS)定义的蓝牙堆栈进程API 交互。等等,使用 AIDL 或 Protobuf 等语言。对于 Android 应用程序,尽管 API 是在 AIDL 中定义的,但一些样板代码包含在通过代码公开的 Java 库中,这些代码frameworks/base/core/java/android/bluetooth作为Android SDK发布给开发人员。

硬件抽象层 (HAL) 进程:来自供应商分区的一个或多个进程,因此依赖于硬件。它们通过Binder、Socket IPC、DBUS等RPC/IPC方法定义的一组硬件抽象API,使用HIDL等语言与蓝牙栈进程进行交互。在 Android 上,这将是实现 HIDL API(例如IBluetoothHciIBluetoothAudioProvider )的 HAL 进程。

蓝牙堆栈进程:通常是在主机控制器接口 (HCI) 之上和蓝牙 SDK API 之下实现各种蓝牙协议和配置文件的单个进程。一方面,它为来自应用程序进程的请求提供服务;另一方面,它通过与HAL 进程的交互来转发这些请求。在 Android 上,此进程通常在 AID_BLUETOOTH(通常为 1002)下运行,进程名称为“com.android.bluetooth”。该过程在 Java 中启动,并通过 JNI 加载本机库。其他不使用Java虚拟机的系统可能有纯原生进程。由于各种原因,这个进程中可能存在多个线程。GD栈完全运行在这个进程中。

threads-in-bluetooth-stack-process蓝牙堆栈进程中的线程

目前,蓝牙堆栈中线程优化的目标是:

  • 尽可能减少线程数以简化同步
  • 在单独的线程中执行阻塞 I/O 操作
  • 尝试将 I/O 操作移动到轮询模式,以便我们可以使用事件驱动方法在主线程上与其交互
  • 将警报和计时器机制移动到它们的调用线程以避免单独的警报线程
  • 隔离单个组件,以便每个组件都可以单独启动和停止,而无需终止主线程
  • 首选数据传递而不是线程间的数据共享,以减少锁定和竞争条件

经过上述优化后,我们在本机代码中留下了五种主要类型的线程:

主线程:蓝牙堆栈中的主力。线程的执行上下文被进一步划分为Handlers驻留在 individual 中的那些Modules。如果运行平台上的性能受到限制,则可以将该线程进一步划分为更小的线程。部署者只需要将处理程序绑定到不同的线程,这不应该影响整体操作。

JNI 线程:在原生线程中,我们将 Java 层视为一个单独的应用程序,因为它的线程模块是完全不同的。因此,我们在这两层之间放置了一个线程来缓冲任何阻塞操作。

HCI 线程(或其他 HW I/O 线程):该线程负责硬件 I/O 的死机,并且可能会阻塞。因此它有自己的独立线程以避免阻塞主线程。

Audio worker thread:负责对执行时序精度要求更高的音频编解码操作。这样的worker有自己独立的线程,避免被主线程影响。

Socket I/O线程:与使用该BluetootSocket接口的各种应用程序进行通信。由于潜在的 I/O 延迟,它有单独的线程。

data-flow-diagram数据流程图

不同组件之间的函数调用被抽象为通过队列传递的控制包(函数闭包)。组件之间的数据流是通过队列发送的数据包,使用Reactor. 它们将合并到每个组件的输入队列中。我们定义了三种类型的队列:

非阻塞队列:当用户试图在空的时候出队,或者满的时候入队,它会立即返回。线程内的所有排队都必须是非阻塞的,否则会死锁。

阻塞队列:当用户尝试在队列为空时出队,或在队列已满时入队,它将阻塞,直到其他线程使队列可写/可读。它可以用作流量控制机制,以避免来自用户线程的数据包过多。

Leaky queue:与非阻塞队列相同,但当它已满并且用户尝试入队时它会刷新。这对音频编码很有用。

image.png

building-blocks建筑模块

module模块

GD 中的代码被打包到名为Module. 一个模块标准化了 GD 代码的以下方面:

  • 依赖关系:一个模块通过实现来提供自己对其他模块的依赖关系ListDependencies()
  • 生命周期:模块必须实现Start()Stop()生命周期方法
  • 线程模块Module基类Handler通过GetHandler()
  • 指标:AModule可以通过 dumpsys 转储其状态信息DumpState()

请参阅其定义:https://android.googlesource.com/platform/system/bt/+/master/gd/module.h

handler处理程序

类似于android.os.Handlerbluetooth::os::Handler提供顺序执行上下文,同时从执行代码中隐藏线程的概念。

通过将执行上下文划分为更小的区域,Handler可以通过以下方式使开发受益:

  • 由于顺序执行上下文,较少需要锁定
  • 较小的上下文导致更容易管理代码流
  • 与线程分离使系统部署者可以更自由地调整底层线程分配。例如,对于没有全线程实现的实时操作系统,aHandler可用于提供近线程执行上下文

当然,使用 也有缺点Handler,开发者应该谨慎对待:

警告:虽然多个Handler可以绑定到同一个线程,Handler但不保证代码在不同线程上的顺序执行Handler,即使它们在同一个线程上。

警告:Handlers绑定到同一线程的线程之间的锁定可能会导致死锁

警告:必须在两者之间复制数据Handler以避免死锁和竞争条件

请参阅其定义: https: //android.googlesource.com/platform/system/bt/+/master/gd/os/handler.h

reactor反应堆

bluetooth::os:Reactor实现Reactor 设计模式,其中并发事件同步事件多路分解器多路分解为通过Dispatcher注册的请求处理程序列表。

在通用的 Linux 操作系统(例如 Android)中,我们使用文件描述符(例如eventfd for Handlertimerfd forAlarmsocketfd for 数据处理管道)来实现它。在文件描述符的上下文中,事件分为两种类型:

  • OnReadReady:表示多路分解器有一些事件供处理程序使用,并且处理程序可以从底层事件队列中读取至少一个事件。这通常与EPOLLINEPOLLHUPEPOLLRDHUP和相关联EPOLLERR
  • OnWriteReady:表示多路分解器已准备好从该处理程序中消耗更多事件,并且该处理程序可以将至少一个事件写入底层队列。这通常与EPOLLOUT.

这种模式自然会产生从一个队列到另一个队列的背压,而无需任何额外的信号机制。当在像我们这样的网络堆栈中使用时,它简化了信令代码流。

请参阅其定义:https://android.googlesource.com/platform/system/bt/+/master/gd/os/reactor.h

的纯数据用例Reactor是 a Reactive Queue,请参阅其定义: https: //android.googlesource.com/platform/system/bt/+/master/gd/os/queue.h

Packet-Definition-Language-PDL

数据包解析和序列化一直是任何网络堆栈的重要组成部分。它通常是与远程设备交互的第一段代码。过去,这是使用STREAM_TO_UNIT8或 之类的宏手动实现的UINT8_TO_STREAM。这种手动方法既乏味又容易出错。为了解决这个问题,我们创建了一种数据包定义语言,将网络数据包结构定义为位级别。C++ 标头和 Python 绑定将从其代码生成器自动生成,对代码生成器的任何修复都将系统地应用于生成的所有数据包代码。

示例 PDL:

// Comments
little_endian_packets // Whether this packet is big or small endian

// Include header from other C++ header files
custom_field SixBytes : 48 "packet/parser/test/" // expect six_bytes.h
custom_field Variable "packet/parser/test/" // expect variable.h

// A packet
packet Parent {
  _fixed_ = 0x12 : 8, // fixed field 0x12 that takes 8 bits
  _size_(_payload_) : 8, // Size field that takes 8 bits
  _payload_, // special payload field of variable size
  footer : 8, // fiexed size footer of 8 bits
}

packet Child : Parent {
  field_name : 16, // addition field append after Parent
}

// an enum of 4 bits
enum FourBits : 4 {
  ONE = 1,
  TWO = 2,
  THREE = 3,
  FIVE = 5,
  TEN = 10,
  LAZY_ME = 15,
}

请参阅其文档:https://android.googlesource.com/platform/system/bt/+/master/gd/packet/parser/README

模块之间的调用约定

asynchronous-server_client-model异步服务器-客户端模型

对于模块之间的大多数通信,开发人员应该采用通用模型中的异步服务器-客户端模型,例如:

// Define callback function type
using CallbackFunction = std::function<void(ParamType)>;

// Asynchronous method definition
bool Foo(Parameter param, CallbackFunction callback);

// A new callback is passed for each asynchronous call
// Always prefer lambda over std::bind
CallbackFunction callback = [this] {
  // do something
};
Parameter param = {
  // something
};
if (Foo(param, callback)) {
   // The callback will be invoked
   // Callback must be invoked in the future
} else {
   // Failed, no need to wait
}

许多协议和配置文件都适合这样的模型,例如AclManagerL2cap

synchronous-database-model同步数据库模型

在某些情况下,异步服务器-客户端模型是不可行的。在这种情况下,开发人员可以考虑同步数据库模型。在这样的模型中,操作可以在互斥锁的帮助下同步发生。当方法返回时,更改必须反映到所有依赖项。内部状态的任何更改都必须以原子方式应用。

// Synchronous method definition
void Foo(Parameter param, Output* output);
int Bar(Parameter param);
Parameter param = {
  // something
};
Output output = {};
Foo(param, &output);
// output can be used immediately
int bar_output = Bar(param);
// bar_output can be used immediately

许多存储和信息模块都适合此模型,例如MetricsStorage

相关文章

  • ping

    package com.gd.windtrend.frontpos.service; import android...

  • 代码中改变shape的颜色

    android:background="@drawable/shape_daily_spike_bg_blue" ...

  • BT

    http://www.android-doc.com/guide/topics/connectivity/blue...

  • Android开发踩坑

    Android颜色值所支持的4个格式 Android中颜色值是通过红(Red)、绿(Green)、蓝 (Blue)...

  • Blue

    Blue sky Blue broad Blue blue Blue gloom

  • PHP学习笔记 - 进阶篇(9)

    图形图像操作 GD库简介 GD指的是Graphic Device,PHP的GD库是用来处理图形的扩展库,通过GD库...

  • 图形图像操作

    PHP图形操作之GD库简介 GD指的是Graphic Device,PHP的GD库是用来处理图形的扩展库,通过GD...

  • blue blue blue

    傍晚的时候回家,抬头看天的时候,发现天空是深蓝色的。 比普通的蓝色深一点儿。 电影里说东京的天空总有最大密度的蓝色...

  • Blue,Blue,Blue

    (大海为什么是蓝色的?因为有鱼吐泡泡,bule blue blue) 用一根火柴去烤香烟 花火染红干枯的草叶 贪它...

  • blue blue blue

    曾经被誉为世界一流的媒体,Bi Bi Say这一轮操作下来,只能让更多的人,一边心堵,也还是会露出蔑视的微笑吧。 ...

网友评论

      本文标题:Android gd -- Gabeldorsche Blue

      本文链接:https://www.haomeiwen.com/subject/cxwzfdtx.html