1# Gabeldorsche Architecture
2
3[TOC]
4
5This document outlines some architectural considerations we've made when
6developing the Gabeldorsche (GD) Bluetooth stack.
7
8## Threading model
9
10First of all, the GD stack does not build on concepts of threads. Instead, it
11works with [`Handlers`](#handler). However, since GD ultimately runs on an OS,
12it still needs to interact with processes and threads before achieving the
13[`Handler`](#handler) abstraction.
14
15### Processes
16
17In general. three types of processes exist in the GD runtime environment:
18
19**Application processes**
20:   include third-party apps, other system components such as audio and telecom
21    services that interact with the _Bluetooth stack process_ APIs defined
22    through various RPC/IPC methods such as Binder, Socket IPC, gRPC, DBUS. and
23    so on, using languages such as AIDL or Protobuf. For Android applications,
24    although APIs are defined in AIDL, some boiler plate code is wrapped in Java
25    libraries exposed through code in
26    [`frameworks/base/core/java/android/bluetooth`](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/bluetooth/)
27    that is released to developers as
28    [Android SDK](https://developer.android.com/guide/topics/connectivity/bluetooth).
29
30**Hardware abstraction layer (HAL) processes**
31:   one or many processes from the vendor partition, and hence is hardware
32    depenedent. They interact with the _Bluetooth stack process_ via a set of
33    hardware abstraction APIs defined through RPC/IPC methods such as Binder,
34    Socket IPC, DBUS, and so on, using languages such as HIDL. On Android, this
35    would be HAL processes that implement HIDL APIs such as
36    [IBluetoothHci](https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/master/bluetooth/1.1/IBluetoothHci.hal)
37    and
38    [IBluetoothAudioProvider](https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/master/bluetooth/audio/2.0/IBluetoothAudioProvider.hal).
39
40**Bluetooth stack process**
41:   typically one single process that implements various Bluetooth protocols and
42    profiles above the Host Controller Interface (HCI) and below the Bluetooth
43    SDK APIs. On one hand, it servces the requests from _Application processes_;
44    on the other hand, it forwards these requests via interactions with _HAL
45    processes_. On Android, this process typically runs under AID_BLUETOOTH
46    (usually 1002) with process name "com.android.bluetooth". The process is
47    started in Java and loads native libraries through JNI. Other systems that
48    do not use Java virtual machine may have a pure native process. Multiple
49    threads may exist in this process for various reasons. The GD stack runs
50    entirely in this process.
51
52### Threads in Bluetooth stack process
53
54Currently, the goals of thread optimization in the Bluetooth stack are:
55
56*   Reduce the number of threads as much as possible to simplify synchronization
57*   Do blocking I/O operations in separate threads
58*   Try moving I/O operations into polling mode so that we can use event driven
59    methods to interact with it on main thread
60*   Move alarm and timer mechanisms to their calling threads to avoid a separate
61    alarm thread
62*   Isolate individual components so that each component can be started and
63    stopped individually without terminating the main thread
64*   Prefer data passing over data sharing among threads to reduce locking and
65    race conditions
66
67After above optimization, we are left with five main types of threads within the
68native code:
69
70**Main thread**
71:   The main workhorse in the Bluetooth stack. The thread's execution context is
72    further divided into [`Handlers`](#handler) that reside in individual
73    [`Modules`](#module). This thread can be divided further into smaller ones
74    if performance is constrained on the running platform. Deployer just needs
75    to bind handlers to different threads and that should not affect the overall
76    operation.
77
78**JNI thread**
79:   In the native thread, we treat the Java layer as a separate application as
80    its threading module is completely different. Therefore, we put a thread
81    between these two layers to buffer any blocking operation.
82
83**HCI thread (or other HW I/O thread)**
84:   This thread is responsible for deadling with hardware I/O and can be
85    potentially blocking. Hence it has its separate thread to avoid blocking the
86    main thread.
87
88**Audio worker thread**
89:   Responsible for audio encoding and decoding operations that require higher
90    precision execution timing. Such worker has its separate thread to avoid
91    being affected by the main thread.
92
93**Socket I/O thread**
94:   Communicate with various applications that uses the
95    [`BluetootSocket`](https://developer.android.com/reference/android/bluetooth/BluetoothSocket)
96    interface. It has its sepearate thread due to potential I/O delay.
97
98### Data flow diagram
99
100Function invocations between different components are abstracted as control
101packets (function closure) passed through queues. Data flow between components
102are data packets sent through queues, signaled using [`Reactor`](#reactor). They
103will merge to the input queue for each component. We define three types of
104queues:
105
106**Non-blocking queue**
107:   When users try to dequeue when it’s empty, or enqueue when it’s full, it
108    will return immediately. All queueing within a thread must be non-blocking,
109    because otherwise it will deadlock.
110
111**Blocking queue**
112:   When users try to dequeue when it’s empty, or enqueue when it’s full, it
113    will block, until other thread makes the queue to be writable/readable. It
114    can be used as a flow control mechanism to avoid too many packets from user
115    thread.
116
117**Leaky queue**
118:   Same as non-blocking queue, but it will flush when it’s full and user tries
119    to enqueue. This is useful for audio encoding.
120
121![Threading Model](./data_flow_diagram.png)
122
123## Building blocks
124
125### Module {#module}
126
127Code in GD is packed into C++ objects called
128[`Module`](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/module.h).
129A module standardized the following aspects of GD code:
130
131*   **Dependencies**: A module provides its own dependencies on other modules by
132    implementing `ListDependencies()`
133*   **Life Cycle**: A module must implement `Start()` and `Stop()` life cycle
134    methods
135*   **Threading Module**: The `Module` base class provides a `Handler` for code
136    execution context via `GetHandler()`
137*   **Metrics**: A `Module` can dump its state information for dumpsys through
138    `DumpState()`
139
140See its definition at: https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/module.h
141
142### Handler {#handler}
143
144Similar to
145[`android.os.Handler`](https://developer.android.com/reference/android/os/Handler),
146[`bluetooth::os::Handler`](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/os/handler.h)
147provides a sequential execution context while hiding the concept of thread from
148the executing code.
149
150By scoping execution context into smaller areas, `Handler` benefits development
151in the following ways:
152
153*   Less need for locking due to sequential execution context
154*   Smaller context leads to easier management of code flow
155*   Separation from thread gives system deployer more freedom to tweak the
156    underlying thread allocation. For example, for real time OS without full
157    thread implementation, a `Handler` can be used to provide a near-thread
158    execution context
159
160Of course, there are downsides of using `Handler`, which developers should be
161cautious about:
162
163WARNING: Although multiple `Handler` could bind to the same thread, `Handler`
164does not gurantee sequential execution of code across different `Handler` even
165when the are on the same thread.
166
167WARNING: Locking among `Handlers` that were bound to the same thread may result
168in deadlock
169
170WARNING: Data must be copied between `Handler` to avoid both deadlock and race
171condition
172
173See its definition at: https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/os/handler.h
174
175### Reactor {#reactor}
176
177[`bluetooth::os:Reactor`](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/os/reactor.h)
178implements the
179[Reactor Design Pattern](https://en.wikipedia.org/wiki/Reactor_pattern), in
180which concurrent _Events_ are demultiplexed by a _Synchronous Event
181Demultiplexer_ to a list of _Request Handlers_ registered through a
182_Dispatcher_.
183
184In a generic Linux operating system, such as Android, we implemented it using
185file descriptors such as
186[eventfd](http://man7.org/linux/man-pages/man2/eventfd.2.html) for `Handler`,
187[timerfd](http://man7.org/linux/man-pages/man2/timerfd_create.2.html) for
188`Alarm`, and [socketfd](http://man7.org/linux/man-pages/man2/socket.2.html) for
189data processing pipelines. In the context of file descriptors, events are
190catigorized into two types:
191
192*   **OnReadReady**: means that the demultiplexer has some events for the
193    handler and the handler can read at least one event from the underlying
194    event queue. This is often associated with `EPOLLIN`, `EPOLLHUP`,
195    `EPOLLRDHUP`, and `EPOLLERR`.
196*   **OnWriteReady**: means that the demultiplexer is ready to consume more
197    events from this handler, and the handler can write at least one event to
198    the underlying queue. this is often associated with `EPOLLOUT`.
199
200This pattern naturally creates a back pressure from one queue to another without
201any extra signaling mechanism. When used in networking stack like ours, it
202simplifies the signaling code flow.
203
204See its definition at:
205https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/os/reactor.h
206
207A pure data use case of `Reactor` is a `Reactive Queue`, see its definition at:
208https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/os/queue.h
209
210## Packet Definition Language (PDL)
211
212Packet parsing and serialization has been a big part of any networking stack. It
213is usually the first snippet of code that interface with a remote device. In the
214past, this has been achieved manually using macros like `STREAM_TO_UNIT8` or
215`UINT8_TO_STREAM`. This manual method is tedious and errorprone. To fix this, we
216created a Packet Definition Language that defines networking packet structure to
217the bits level. C++ headers and Python bindings will be automatically generated
218from its code generator and any fixes to the code generator will apply
219systematically to all packet code generated.
220
221Example PDL:
222
223```
224// Comments
225little_endian_packets // Whether this packet is big or small endian
226
227// Include header from other C++ header files
228custom_field SixBytes : 48 "packet/parser/test/" // expect six_bytes.h
229custom_field Variable "packet/parser/test/" // expect variable.h
230
231// A packet
232packet Parent {
233  _fixed_ = 0x12 : 8, // fixed field 0x12 that takes 8 bits
234  _size_(_payload_) : 8, // Size field that takes 8 bits
235  _payload_, // special payload field of variable size
236  footer : 8, // fiexed size footer of 8 bits
237}
238
239packet Child : Parent {
240  field_name : 16, // addition field append after Parent
241}
242
243// an enum of 4 bits
244enum FourBits : 4 {
245  ONE = 1,
246  TWO = 2,
247  THREE = 3,
248  FIVE = 5,
249  TEN = 10,
250  LAZY_ME = 15,
251}
252```
253
254See its documentation at:
255https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/packet/parser/README
256
257## Calling convention between modules
258
259### Asynchronous server-client model
260
261For most communication among modules, developers should assume an asynchronous
262server-client model in a generic model like:
263
264```c++
265// Define callback function type
266using CallbackFunction = std::function<void(ParamType)>;
267
268// Asynchronous method definition
269bool Foo(Parameter param, CallbackFunction callback);
270
271// A new callback is passed for each asynchronous call
272// Always prefer lambda over std::bind
273CallbackFunction callback = [this] {
274  // do something
275};
276Parameter param = {
277  // something
278};
279if (Foo(param, callback)) {
280   // The callback will be invoked
281   // Callback must be invoked in the future
282} else {
283   // Failed, no need to wait
284}
285```
286
287Many protocols and profiles fit into such model such as `AclManager` and
288`L2cap`.
289
290### Synchronous database model
291
292In some cases, an asynchronous server-client model is not feasible. In this
293case, developers can consider a synchronous database model. In such a model,
294operations can happen synchronously with help of mutex. When the method returns,
295the changes must be reflected to all dependencies. Any changes in the internal
296states must be applied atomically.
297
298```c++
299// Synchronous method definition
300void Foo(Parameter param, Output* output);
301int Bar(Parameter param);
302Parameter param = {
303  // something
304};
305Output output = {};
306Foo(param, &output);
307// output can be used immediately
308int bar_output = Bar(param);
309// bar_output can be used immediately
310```
311
312Many storage and informational modules fit into this model such as `Metrics` and
313`Storage`.
314