• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1*** aside
2See also:
3[Porting Guide](/doc/porting_guide.md) |
4[Build System](/doc/framework_build.md) |
5[Debugging](/doc/framework_debugging.md) |
6[Testing](/doc/framework_testing.md) |
7[Vendor Extensions](/doc/vendor_extensions.md)
8***
9
10# CHRE Framework Overview
11
12[TOC]
13
14The CHRE reference implementation (hereafter referred to just as "CHRE" or "the
15CHRE framework") is developed primarily in C++11 using a modular object-oriented
16approach that separates common code from platform-specific code. CHRE is an
17event-based system, so CHRE is built around an event loop which executes nanoapp
18code as well as CHRE system callbacks. Per the CHRE API, nanoapps can’t execute
19in more than one thread at a time, so CHRE is structured around a single thread
20that executes the event loop, although there may be other threads in the system
21that support CHRE. The EventLoopManager is a Singleton object which owns the
22main state of the CHRE framework, including EventLoop and \*Manager classes for
23the various subsystems supported by CHRE.
24
25To get a better understanding of code structure and how it weaves between common
26and platform-specific components, it is helpful to trace the flow through a few
27example scenarios. Note that this is not meant to be an exhaustive list of
28everything that happens in each case (for that, refer to the code itself), but
29rather an overview of key points to serve as an introduction.
30
31## Loading a nanoapp via the HAL
32
33There are multiple ways by which a nanoapp can be loaded (see the relevant
34section below for details), but this example traces the flow for dynamically
35loading a nanoapp that has been passed in via the Context Hub HAL's
36`loadNanoapp()` method.
37
381. The nanoapp binary reaches the HAL implementation, and it is loaded into the
39   processor where CHRE is running using a platform-specific method. While the
40   path this takes can vary, one common approach is to transmit the binary into
41   CHRE via the platform-specific HostLink implementation, then verify its
42   digital signature, and parse the binary file format (e.g. ELF) to load and
43   link the code.
44
452. Once the nanoapp code is loaded, the platform code calls
46   `EventLoopManager::deferCallback()` to switch context to the main CHRE thread
47   (if needed), so it can complete loading and starting the nanoapp.
48   `deferCallback()` effectively posts an event to the main event loop which
49   does not get delivered to any nanoapps. Instead, the purpose is to invoke the
50   supplied callback from the CHRE thread once the event is popped off the
51   queue.
52
533. The (platform-specific) callback finalizes the newly constructed `Nanoapp`
54   object as needed, and passes it to `EventLoop::startNanoapp()` - this marks a
55   transition from platform-specific to common code.
56
574. `EventLoop` takes ownership of the `Nanoapp` object (which is a composite of
58   common and platform-specific data and functions, as described in the Platform
59   Abstractions section), includes it in the collection of loaded nanoapps to
60   execute in the main event loop, updates `mCurrentNanoapp` to reference the
61   nanoapp it's about to execute, and calls into `PlatformNanoapp::start()`.
62
635. Since the mechanism of supporting dynamic linkage and position independent
64   code can vary by platform, transferring control from the framework to a
65   nanoapp is considered part of the platform layer. So
66   `PlatformNanoapp::start()` performs any necessary tasks for this, and calls
67   into the `nanoappStart()` function defined in the nanoapp binary.
68
69## Invoking a CHRE API from a nanoapp
70
71Let's assume the nanoapp we've loaded in the previous section calls the
72`chreSensorConfigure()` CHRE API function within `nanoappStart()`:
73
741. The nanoapp invokes `chreSensorConfigure()` with parameters to enable the
75   accelerometer.
76
772. The Nanoapp Support Library (NSL) and/or the platform's dynamic linking
78   module are responsible for handling the transition of control from the
79   nanoapp binary to the CHRE framework. This can vary by platform, but we'll
80   assume that control arrives in the `chreSensorConfigure()` implementation in
81   `platform/shared/chre_api_sensor.cc`.
82
833. `EventLoopManager::validateChreApiCall()` is invoked to confirm that this
84   function is being called from the context of a nanoapp being executed within
85   the event loop (since associating the API call with a specific nanoapp is a
86   requirement of this API and many others, and the majority of the CHRE
87   framework code is only safe to execute from within the main CHRE thread), and
88   fetch a pointer to the current `Nanoapp` (i.e. it retrieves `mCurrentNanoapp`
89   set previosly by `EventLoop`).
90
914. `SensorManager::setSensorRequest()` (via
92   `EventLoopManager::getSensorRequestManager()`) is called to process the
93   nanoapp’s request - we transition to common code here.
94
955. The request is validated and combined with other nanoapp requests for the
96   same sensor to determine the effective sensor configuration that should be
97   requested from the platform, and the nanoapp is registered to receive
98   broadcast accelerometer sensor events.
99
1006. `SensorRequestManager` calls into `PlatformSensorManager::configureSensor()`,
101   which performs the necessary operations to actually configure the
102   accelerometer to collect data.
103
1047. Assuming success, the return value propagates back up to the nanoapp, and it
105   continues executing.
106
107## Passing an event to a nanoapp
108
109Following the example from above, let's follow the case where an accelerometer
110sample has been generated and is delivered to the nanoapp for processing.
111
1121. Starting in platform-specific code, likely in a different thread, the
113   accelerometer sample is received from the underlying sensor framework - this
114   typically happens in a different thread than the main CHRE thread, and within
115   the fully platform-specific `PlatformSensorManagerBase` class.
116
1172. As needed, memory is allocated to store the sample while it is being
118   processed, and the data is converted into the CHRE format: `struct
119   chreSensorThreeAxisData`.
120
1213. `SensorRequestManager::handleSensorDataEvent()` is invoked (common code) to
122   distribute the data to nanoapps.
123
1244. `SensorRequestManager` calls into `EventLoop` to post an event containing the
125   sensor data to all nanoapps registered for the broadcast event type
126   associated with accelerometer data, and sets `sensorDataEventFree()` as the
127   callback invoked after the system is done processing the event.
128
1295. `EventLoop` adds this event to its event queue and signals the CHRE thread.
130
1316. Now, within the context of the CHRE thread, once the event loop pops this
132   event off of its queue in `EventLoop::run()`, the `nanoappHandleEvent()`
133   function is invoked (via `PlatformNanoapp`, as with `nanoappStart`) for each
134   nanoapp that should receive the event.
135
1367. Once the event has been processed by each nanoapp, the free callback
137   (`sensorDataEventFree()`), is called to release any memory or do other
138   necessary cleanup actions now that the event is complete.
139
140## Platform Abstractions
141
142CHRE follows the 'compile time polymorphism' paradigm, to allow for the benefits
143of `virtual` functions, while minimizing code size impact on systems with tight
144memory constraints.
145
146Each framework module as described in the previous section is represented by a
147C++ class in `core/`, which serves as the top-level reference to the module and
148defines and implements the common functionality. This common object is then
149composed with platform-specific functionality at compile-time. Using the
150`SensorRequestManager` class as an example, its role is to manage common
151functionality, such as multiplexing sensor requests from all clients into a
152single request made to the platform through the `PlatformSensorManager` class,
153which in turn is responsible for forwarding that request to the underlying
154sensor system.
155
156While `SensorRequestManager` is fully common code, `PlatformSensorManager` is
157defined in a common header file (under `platform/include/chre/platform`), but
158implemented in a platform-specific source file. In other words, it defines the
159interface between common code and platform-specific code.
160
161`PlatformSensorManager` inherits from `PlatformSensorManagerBase`, which is
162defined in a platform-specific header file, which allows for extending
163`PlatformSensorManager` with platform-specific functions and data. This pattern
164applies for all `Platform<Module>` classes, which must be implemented for all
165platforms that support the given module.
166
167Selection of which `PlatformSensorManager` and `PlatformSensorManagerBase`
168implementation is instantiated is controlled by the build system, by setting the
169appropriate include path and source files. This includes the path used to
170resolve include directives appearing in common code but referencing
171platform-specific headers, like `#include
172"chre/target_platform/platform_sensor_manager_base.h"`.
173
174To ensure compatibility across all platforms, common code is restricted in how
175it interacts with platform-specific code - it must always go through a common
176interface with platform-specific implementation, as described above. However,
177platform-specific code is less restricted, and can refer to common code, as well
178as other platform code directly.
179
180## Coding conventions
181
182This project follows the [Google-wide style guide for C++
183code](https://google.github.io/styleguide/cppguide.html), with the exception of
184Android naming conventions for methods and variables. This means 2 space
185indents, camelCase method names, an mPrefix on class members and so on.  Style
186rules that are not specified in the Android style guide are inherited from
187Google. Additionally, this project uses clang-format for automatic code
188formatting.
189
190This project uses C++11, but with two main caveats:
191
1921. General considerations for using C++ in an embedded environment apply. This
193   means avoiding language features that can impose runtime overhead, due to the
194   relative scarcity of memory and CPU resources, and power considerations.
195   Examples include RTTI, exceptions, overuse of dynamic memory allocation, etc.
196   Refer to existing literature on this topic including this [Technical Report
197   on C++ Performance](http://www.open-std.org/jtc1/sc22/wg21/docs/TR18015.pdf)
198   and so on.
199
2002. Full support of the C++ standard library is generally not expected to be
201   extensive or widespread in the embedded environments where this code will
202   run. This means things like <thread> and <mutex> should not be used, in
203   favor of simple platform abstractions that can be implemented directly with
204   less effort (potentially using those libraries if they are known to be
205   available).
206