1# CHRE Framework Porting Guide 2 3[TOC] 4 5CHRE achieves portability and extensibility across platforms by defining 6interfaces that the platform needs to implement. These interfaces provide 7dependencies for the common CHRE code that are necessarily platform-specific. 8Additionally, platform code calls into common code to ferry events from 9underlying subsystems to nanoapps. 10 11This section gives an overview of the steps one should take to add support for a 12new platform in the CHRE reference implementation. 13 14## Directory Structure 15 16CHRE platform code can be broadly categorized as follows. 17 18### Platform Interfaces 19 20Files under `platform/include` serve as the interface between common code in 21`core/` and other platform-specific code in `platform/<platform_name>`. These 22files are considered common and should not be modified for the sake of 23supporting an individual platform. 24 25### Shared Platform Code 26 27Located in `platform/shared/`, the code here is part of the platform layer’s 28responsibilities, but is not necessarily specific to only one platform. In other 29words, this code is likely to be re-used by multiple platforms, but it is not 30strictly necessary for a given platform to use it. 31 32### Platform-specific Code 33 34Files under `platform/<platform_name>` are specific to the underlying software 35of a given platform, for example the APIs which are used to access functionality 36like sensors, the operating system, etc. To permit code reuse, the CHRE platform 37layer for a given device may be composed of files from multiple 38`<platform_name>` folders, for example if the same sensor framework is supported 39across multiple OSes, there may be one folder that provides the components that 40are specific to just the OS. 41 42Platform-specific code can be further subdivided into: 43 44* **Source files**: normally included at 45 `platform/<platform_name>/<file_name>.cc`, but may appear in a subdirectory 46 47* **Headers which are includable by common code**: these are placed at 48 `platform/<platform_name>/include/chre/target_platform/<file_name>.h`, and are 49 included by *Platform Interfaces* found in `platform/include` and provide 50 inline or base class definitions, such as `mutex_base_impl.h` and 51 `platform_sensor_base.h` respectively, or required macros 52 53* **Fully platform-specific headers**: these typically appear at 54 `platform/<platform_name>/include/chre/platform/<platform_name>/<file_name>.h` 55 and may only be included by other platform-specific code 56 57## Open Sourcing 58 59Partners who add support for a new platform are recommended to upstream their 60code to 61[AOSP](https://source.android.com/setup/contribute#contribute-to-the-code). 62This helps ensure that details of your platform are considered by the team that 63maintains the core framework, so any changes that break compilation are 64addressed in a timely fashion, and enables you to receive useful code review 65feedback to improve the quality of your CHRE implementation. Please reach out 66via your TAM to help organize this effort. 67 68If some parts of a platform’s CHRE implementation must be kept closed source, 69then it is recommended to be kept in a separate Git project (under vendor/ in 70the Android tree). This vendor-private code can be integrated with the main CHRE 71build system through the `CHRE_VARIANT_MK_INCLUDES` variable. See the build 72system documentation for more details. 73 74## Recommended Steps for Porting CHRE 75 76When starting to add support for a new platform in the CHRE framework, it’s 77recommended to break the task into manageable chunks, to progressively add more 78functionality until the full desired feature set is achieved. An existing 79platform implementation can be referenced to create empty stubs, and then 80proceed to add implementations piece by piece, testing along the way. 81 82CHRE provides various test nanoapps in `apps/` that exercise a particular 83feature that the platform provides. These are selectively compiled into the 84firmware statically via a `static_nanoapps.cc` source file. 85 86With this in mind, it is recommended to follow this general approach: 87 881. Create a new platform with only empty stubs, with optional features (like 89 `CHRE_GNSS_SUPPORT_ENABLED`) disabled at build-time 90 912. Work on updating the build system to add a new build target and achieve 92 successful compilation and linking (see the build system documentation for 93 details) 94 953. Implement base primitives from `platform/include`, including support for 96 mutexes, condition variables, atomics, time, timers, memory allocation, and 97 logging 98 994. Add initialization code to start the CHRE thread 100 1015. Add static nanoapp initialization support (usually this is just a copy/paste 102 from another platform) 103 1046. Confirm that the ‘hello world’ nanoapp produces the expected log message (if 105 it does, huzzah!) 106 1077. Complete any remaining primitives, like assert 108 1098. Implement host link and the daemon/HAL on the host (AP) side, and validate it 110 with a combination of the message world nanoapp and the host-side test code 111 found at `host/common/test/chre_test_client.cc` 112 113At this stage, the core functionality has been enabled, and further steps should 114include enabling dynamic loading (described in its own section below), and the 115desired optional feature areas, like sensors (potentially via their respective 116PALs, described in the next section). 117 118## Implementing the Context Hub HAL 119 120The Context Hub HAL (found in the Android tree under 121`hardware/interfaces/contexthub`) defines the interface between Android and the 122underlying CHRE implementation, but as CHRE is implemented on a different 123processor from the HAL, the HAL is mostly responsible for relaying messages to 124CHRE. This project includes an implementation of the Context Hub HAL under 125`host/hal_generic` which pairs with the CHRE framework reference implementation. 126It converts between HAL API calls and serialized flatbuffers messages, using the 127host messaging protocol defined under `platform/shared` (platform 128implementations are able to choose a different protocol if desired, but would 129require a new HAL implementation), and passes the messages to and from the CHRE 130daemon over a socket. The CHRE daemon is in turn responsible for communicating 131directly with CHRE, including common functionality like relaying messages to and 132from nanoapps, as well as device-specific functionality as needed. Some examples 133of CHRE functionality that are typically implemented with support from the CHRE 134daemon include: 135 136* Loading preloaded nanoapps at startup 137* Passing log messages from CHRE into Android logcat 138* Determining the offset between `chreGetTime()` and Android’s 139 `SystemClock.elapsedRealtimeNanos()` for use with 140 `chreGetEstimatedHostTimeOffset()` 141* Coordination with the SoundTrigger HAL for audio functionality 142* Exposing CHRE functionality to other vendor-specific components (e.g. via 143 `chre::SocketClient`) 144 145When adding support for a new platform, a new HAL implementation and/or daemon 146implementation on the host side may be required. Refer to code in the `host/` 147directory for examples. 148 149## Implementing Optional Feature Areas (e.g. PALs) 150 151CHRE provides groups of functionality called *feature areas* which are 152considered optional from the perspective of the CHRE API, but may be required to 153support a desired nanoapp. CHRE feature areas include sensors, GNSS, audio, and 154others. There are two ways by which this functionality can be exposed to the 155common CHRE framework code: via the `Platform<Module>` C++ classes, or the C PAL 156(Platform Abstraction Layer) APIs. It may not be necessary to implement all of 157the available feature areas, and they can instead be disabled if they won’t be 158implemented. 159 160The Platform C++ Classes and PAL APIs have extensive documentation in their 161header files, including details on requirements. Please refer to the headers for 162precise implementation details. 163 164### Platform C++ Classes vs. PAL APIs 165 166Each feature area includes one or more `Platform<Module>` classes which the 167common framework code directly interacts with. These classes may be directly 168implemented to provide the given functionality, or the shim to the PAL APIs 169included in the `shared` platform directory may be used. PALs provide a C API 170which is suitable for use as a binary interface, for example between two dynamic 171modules/libraries, and it also allows for the main CHRE to platform-specific 172translation to be implemented in C, which may be preferable in some cases. 173 174Note that the PAL APIs are binary-stable, in that it’s possible for the CHRE 175framework to work with a module that implements a different minor version of the 176PAL API, full backwards compatibility (newer CHRE framework to older PAL) is not 177guaranteed, and may not be possible due to behavioral changes in the CHRE API. 178While it is possible for a PAL implementation to simultaneously support multiple 179versions of the PAL API, it is generally recommended to ensure the PAL API 180version matches between the framework and PAL module, unless the source control 181benefits of a common PAL binary are desired. 182 183This level of compatibility is not provided for the C++ `Platform<Module>` 184classes, as the CHRE framework may introduce changes that break compilation. If 185a platform implementation is included in AOSP, then it is possible for the 186potential impact to be evaluated and addressed early. 187 188### Disabling Feature Areas 189 190If a feature area is not supported, setting the make variable 191`CHRE_<name>_SUPPORT_ENABLED` to false in the variant makefile will avoid 192inclusion of common code for that feature area. Note that it must still be 193possible for the associated CHRE APIs to be called by nanoapps without crashing 194- these functions must return an appropriate response indicating the lack of 195 support (refer to `platform/shared/chre_api_<name>.cc` for examples). 196 197### Implementing Platform C++ Classes 198 199As described in the CHRE Framework Overview section, CHRE abstracts common code 200from platform-specific code at compile time by inheriting through 201`Platform<Module>` and `Platform<Module>Base` classes. Platform-specific code 202may retrieve a reference to other objects in CHRE via 203`EventLoopManagerSingleton::get()`, which returns a pointer to the 204`EventLoopManager` object which contains all core system state. Refer to the 205`Platform<Module>` header file found in `platform/include`, and implementation 206examples from other platforms for further details. 207 208### Implementing PALs 209 210PAL implementations must only use the callback and system APIs provided in 211`open()` to call into the CHRE framework, as the other functions in the CHRE 212framework do not have a stable API. 213 214If a PAL implementation is provided as a dynamic module in binary form, it can 215be linked into the CHRE framework at build time by adding it to 216`TARGET_SO_LATE_LIBS` in the build variant’s makefile - see the build system 217documentation for more details. 218 219#### Recommended Implementation flow 220 221While there may be minor differences, most CHRE PAL [API][CHRE_PAL_DIR_URL] 222implementations follow the following pattern: 223 2241. **Implement the Module API for CHRE** 225 226CHRE provides a standardized structure containing various interfaces for 227calling into the vendor's closed source code in _pal/<feature>.h_. These 228functions must be implemented by the platform, and provided to CHRE when a call 229to _chrePal<feature>GetApi_ function is called. Functions to be implemented are 230of two broad categories: 231 232* _Access functions_ 233 234 CHRE provides feature specific callbacks (see 2. below) to the PAL by 235 invoking the _open()_ function in the Module API provided above. The 236 structures returned by this function call must be stored somewhere by the 237 PAL, and used as necessary to call into the CHRE core. Typically, one or 238 more of these callbacks need to be invoked in response to a request from 239 CHRE using the Module API provided above. 240 241 The _close()_ function, when invoked by CHRE, indicates that CHRE is 242 shutting down. It is now the PAL's responsibility to perform cleanup, 243 cancel active requests, and not invoke any CHRE callbacks from this point 244 on. 245 246* _Request functions_ 247 248 These are interfaces in the PAL API that are module specific, and used by 249 CHRE to call into the vendor PAL code. 250 2512. ** Use CHRE's callbacks ** 252 253CHRE provides a set of module specific callbacks by invoking the _open()_ access 254function provided by the Module API. It then starts performing control or data 255requests as needed, by invoking the request functions in the Module API. The PAL 256is expected to process these requests, and invoke the appropriate CHRE provided 257callback in response. Note that some callbacks might require memory ownership 258to be held until explicitly released. For example, upon an audio request from 259CHRE via a call to the `requestAudioDataEvent` audio PAL API, the platform 260might invoke the `audioDataEventCallback` when the audio data is ready and 261packaged approapriately into a `chreAudioDataEvent` structure. The platform 262must ensure that the memory associated with this data structure remains in 263context until CHRE explicitly releases it via a call to `releaseAudioDataEvent`. 264 265Please refer to the appropriate PAL documentation to ensure that such 266dependencies are understood early in the development phase. 267 268#### Reference implementations 269 270Please refer to the various reference implementations that are 271[available][CHRE_LINUX_DIR_URL] for CHRE PALS for the Linux platform. Note that 272this implementation is meant to highlight the usage of the PAL APIs and 273callbacks, and might not necessarily port directly over into a resource 274constrained embedded context. 275 276### PAL Verification 277 278There are several ways to test the PAL implementation beyond manual testing. 279Some of them are listed below in increasing order of the amount of checks run by 280the tests. 281 2821. Use the FeatureWorld apps provided under the `apps` directory to exercise 283the various PAL APIs and verify the CHRE API requirements are being met 284 2852. Assuming the platform PAL implementations utilize CHPP and can communicate 286from the host machine to the target chipset, execute `run_pal_impl_tests.sh` to 287run basic consistency checks on the PAL 288 2893. Execute tests (see Testing section for details) 290 291## Dynamic Loading Support 292 293CHRE requires support for runtime loading and unloading of nanoapp binaries. 294There are several advantages to this approach: 295 296* Decouples nanoapp binaries from the underlying system - can maintain and 297 deploy a single nanoapp binary across multiple devices, even if they support 298 different versions of Android or the CHRE API 299 300* Makes it possible to update nanoapps without requiring a system reboot, 301 particularly on platforms where CHRE runs as part of a statically compiled 302 firmware 303 304* Enables advanced capabilities, like staged rollouts and targeted A/B testing 305 306While dynamic loading is a responsibility of the platform implementation and may 307already be a part of the underlying OS/system capabilities, the CHRE team is 308working on a reference implementation for a future release. Please reach out via 309your TAM if you are interested in integrating this reference code prior to its 310public release. 311 312[CHRE_PAL_DIR_URL]: https://cs.android.com/android/platform/superproject/+/master:system/chre/pal/include/chre/pal/ 313[CHRE_LINUX_DIR_URL]: https://cs.android.com/android/platform/superproject/+/master:system/chre/platform/linux/ 314 315## Adding Context Hub support 316 317Once you have implemented the necessary pieces described previously, you are 318now ready to add the Context Hub support on the device! Here are the necessary 319steps to do this: 320 3211. Add the HAL implementation on the device 322 323Add the build target of the Context Hub HAL implementation to your device .mk 324file. For example, if the default generic Context Hub HAL is being used, you 325can add the following: 326 327``` 328PRODUCT_PACKAGES += \ 329 android.hardware.contexthub-service.generic 330``` 331 332 333Currently, the generic Context Hub HAL relies on the CHRE daemon to communicate 334with CHRE. If you are using one of our existing platforms, you can add one of 335the following CHRE daemon build targets to your PRODUCT_PACKAGES as you did the 336generic HAL above. 337 338Qualcomm target: `chre`\ 339Exynos target: `chre_daemon_exynos`\ 340MediaTek target: `TBD` 341 342Otherwise, you can look at those target definitions to define a new one for 343your specific platform. 344 3452. Add the relevant SElinux policies for the device 346 347Resolve any missing SElinux violations by using the relevant tools such as 348audit2allow, and updating the SElinux policies for your device. You may follow 349the directions in [the official Android page](https://source.android.com/docs/security/features/selinux/validate) 350for additional guidance. 351 3523. Add the Context Hub feature flag for the device 353 354Add the following in your device.mk file: 355 356``` 357PRODUCT_COPY_FILES += \ 358 frameworks/native/data/etc/android.hardware.context_hub.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.context_hub.xml 359``` 360 361The above change will enable the Context Hub Service on the device, and expects 362that the Context Hub HAL comes up. If (1) and (2) are not performed, the device 363may fail to boot to the Android home screen. 364