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