| Brian Duddie | 7f23a87 | 2020-07-01 14:27:31 -0700 | [diff] [blame] | 1 | # CHRE Framework Porting Guide |
| 2 | |
| 3 | [TOC] |
| 4 | |
| 5 | CHRE achieves portability and extensibility across platforms by defining |
| 6 | interfaces that the platform needs to implement. These interfaces provide |
| 7 | dependencies for the common CHRE code that are necessarily platform-specific. |
| 8 | Additionally, platform code calls into common code to ferry events from |
| 9 | underlying subsystems to nanoapps. |
| 10 | |
| 11 | This section gives an overview of the steps one should take to add support for a |
| 12 | new platform in the CHRE reference implementation. |
| 13 | |
| 14 | ## Directory Structure |
| 15 | |
| 16 | CHRE platform code can be broadly categorized as follows. |
| 17 | |
| 18 | ### Platform Interfaces |
| 19 | |
| 20 | Files under `platform/include` serve as the interface between common code in |
| 21 | `core/` and other platform-specific code in `platform/<platform_name>`. These |
| 22 | files are considered common and should not be modified for the sake of |
| 23 | supporting an individual platform. |
| 24 | |
| 25 | ### Shared Platform Code |
| 26 | |
| 27 | Located in `platform/shared/`, the code here is part of the platform layer’s |
| 28 | responsibilities, but is not necessarily specific to only one platform. In other |
| 29 | words, this code is likely to be re-used by multiple platforms, but it is not |
| 30 | strictly necessary for a given platform to use it. |
| 31 | |
| 32 | ### Platform-specific Code |
| 33 | |
| 34 | Files under `platform/<platform_name>` are specific to the underlying software |
| 35 | of a given platform, for example the APIs which are used to access functionality |
| 36 | like sensors, the operating system, etc. To permit code reuse, the CHRE platform |
| 37 | layer for a given device may be composed of files from multiple |
| 38 | `<platform_name>` folders, for example if the same sensor framework is supported |
| 39 | across multiple OSes, there may be one folder that provides the components that |
| 40 | are specific to just the OS. |
| 41 | |
| 42 | Platform-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 |
| Alan Rosenthal | 8278a96 | 2023-10-02 20:42:35 +0000 | [diff] [blame] | 54 | `platform/<platform_name>/include/chre/platform/<platform_name>/<file_name>.h` |
| Brian Duddie | 7f23a87 | 2020-07-01 14:27:31 -0700 | [diff] [blame] | 55 | and may only be included by other platform-specific code |
| 56 | |
| 57 | ## Open Sourcing |
| 58 | |
| 59 | Partners who add support for a new platform are recommended to upstream their |
| 60 | code to |
| 61 | [AOSP](https://source.android.com/setup/contribute#contribute-to-the-code). |
| 62 | This helps ensure that details of your platform are considered by the team that |
| 63 | maintains the core framework, so any changes that break compilation are |
| 64 | addressed in a timely fashion, and enables you to receive useful code review |
| 65 | feedback to improve the quality of your CHRE implementation. Please reach out |
| 66 | via your TAM to help organize this effort. |
| 67 | |
| 68 | If some parts of a platform’s CHRE implementation must be kept closed source, |
| 69 | then it is recommended to be kept in a separate Git project (under vendor/ in |
| 70 | the Android tree). This vendor-private code can be integrated with the main CHRE |
| 71 | build system through the `CHRE_VARIANT_MK_INCLUDES` variable. See the build |
| 72 | system documentation for more details. |
| 73 | |
| 74 | ## Recommended Steps for Porting CHRE |
| 75 | |
| 76 | When starting to add support for a new platform in the CHRE framework, it’s |
| 77 | recommended to break the task into manageable chunks, to progressively add more |
| 78 | functionality until the full desired feature set is achieved. An existing |
| 79 | platform implementation can be referenced to create empty stubs, and then |
| 80 | proceed to add implementations piece by piece, testing along the way. |
| 81 | |
| 82 | CHRE provides various test nanoapps in `apps/` that exercise a particular |
| 83 | feature that the platform provides. These are selectively compiled into the |
| 84 | firmware statically via a `static_nanoapps.cc` source file. |
| 85 | |
| 86 | With this in mind, it is recommended to follow this general approach: |
| 87 | |
| 88 | 1. Create a new platform with only empty stubs, with optional features (like |
| 89 | `CHRE_GNSS_SUPPORT_ENABLED`) disabled at build-time |
| 90 | |
| 91 | 2. 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 | |
| 95 | 3. Implement base primitives from `platform/include`, including support for |
| 96 | mutexes, condition variables, atomics, time, timers, memory allocation, and |
| 97 | logging |
| 98 | |
| 99 | 4. Add initialization code to start the CHRE thread |
| 100 | |
| 101 | 5. Add static nanoapp initialization support (usually this is just a copy/paste |
| 102 | from another platform) |
| 103 | |
| 104 | 6. Confirm that the ‘hello world’ nanoapp produces the expected log message (if |
| 105 | it does, huzzah!) |
| 106 | |
| 107 | 7. Complete any remaining primitives, like assert |
| 108 | |
| 109 | 8. 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 | |
| 113 | At this stage, the core functionality has been enabled, and further steps should |
| 114 | include enabling dynamic loading (described in its own section below), and the |
| 115 | desired optional feature areas, like sensors (potentially via their respective |
| 116 | PALs, described in the next section). |
| 117 | |
| 118 | ## Implementing the Context Hub HAL |
| 119 | |
| 120 | The Context Hub HAL (found in the Android tree under |
| 121 | `hardware/interfaces/contexthub`) defines the interface between Android and the |
| 122 | underlying CHRE implementation, but as CHRE is implemented on a different |
| 123 | processor from the HAL, the HAL is mostly responsible for relaying messages to |
| 124 | CHRE. This project includes an implementation of the Context Hub HAL under |
| 125 | `host/hal_generic` which pairs with the CHRE framework reference implementation. |
| 126 | It converts between HAL API calls and serialized flatbuffers messages, using the |
| 127 | host messaging protocol defined under `platform/shared` (platform |
| 128 | implementations are able to choose a different protocol if desired, but would |
| 129 | require a new HAL implementation), and passes the messages to and from the CHRE |
| 130 | daemon over a socket. The CHRE daemon is in turn responsible for communicating |
| 131 | directly with CHRE, including common functionality like relaying messages to and |
| 132 | from nanoapps, as well as device-specific functionality as needed. Some examples |
| 133 | of CHRE functionality that are typically implemented with support from the CHRE |
| 134 | daemon 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 | |
| 145 | When adding support for a new platform, a new HAL implementation and/or daemon |
| 146 | implementation on the host side may be required. Refer to code in the `host/` |
| 147 | directory for examples. |
| 148 | |
| 149 | ## Implementing Optional Feature Areas (e.g. PALs) |
| 150 | |
| 151 | CHRE provides groups of functionality called *feature areas* which are |
| 152 | considered optional from the perspective of the CHRE API, but may be required to |
| 153 | support a desired nanoapp. CHRE feature areas include sensors, GNSS, audio, and |
| 154 | others. There are two ways by which this functionality can be exposed to the |
| 155 | common 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 |
| 157 | the available feature areas, and they can instead be disabled if they won’t be |
| 158 | implemented. |
| 159 | |
| 160 | The Platform C++ Classes and PAL APIs have extensive documentation in their |
| 161 | header files, including details on requirements. Please refer to the headers for |
| 162 | precise implementation details. |
| 163 | |
| 164 | ### Platform C++ Classes vs. PAL APIs |
| 165 | |
| 166 | Each feature area includes one or more `Platform<Module>` classes which the |
| 167 | common framework code directly interacts with. These classes may be directly |
| 168 | implemented to provide the given functionality, or the shim to the PAL APIs |
| 169 | included in the `shared` platform directory may be used. PALs provide a C API |
| 170 | which is suitable for use as a binary interface, for example between two dynamic |
| 171 | modules/libraries, and it also allows for the main CHRE to platform-specific |
| 172 | translation to be implemented in C, which may be preferable in some cases. |
| 173 | |
| 174 | Note that the PAL APIs are binary-stable, in that it’s possible for the CHRE |
| 175 | framework to work with a module that implements a different minor version of the |
| 176 | PAL API, full backwards compatibility (newer CHRE framework to older PAL) is not |
| 177 | guaranteed, and may not be possible due to behavioral changes in the CHRE API. |
| 178 | While it is possible for a PAL implementation to simultaneously support multiple |
| 179 | versions of the PAL API, it is generally recommended to ensure the PAL API |
| 180 | version matches between the framework and PAL module, unless the source control |
| 181 | benefits of a common PAL binary are desired. |
| 182 | |
| 183 | This level of compatibility is not provided for the C++ `Platform<Module>` |
| 184 | classes, as the CHRE framework may introduce changes that break compilation. If |
| 185 | a platform implementation is included in AOSP, then it is possible for the |
| 186 | potential impact to be evaluated and addressed early. |
| 187 | |
| 188 | ### Disabling Feature Areas |
| 189 | |
| 190 | If a feature area is not supported, setting the make variable |
| 191 | `CHRE_<name>_SUPPORT_ENABLED` to false in the variant makefile will avoid |
| 192 | inclusion of common code for that feature area. Note that it must still be |
| 193 | possible 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 | |
| 199 | As described in the CHRE Framework Overview section, CHRE abstracts common code |
| 200 | from platform-specific code at compile time by inheriting through |
| 201 | `Platform<Module>` and `Platform<Module>Base` classes. Platform-specific code |
| 202 | may 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 |
| 206 | examples from other platforms for further details. |
| 207 | |
| 208 | ### Implementing PALs |
| 209 | |
| 210 | PAL 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 |
| 212 | framework do not have a stable API. |
| 213 | |
| 214 | If a PAL implementation is provided as a dynamic module in binary form, it can |
| 215 | be 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 |
| 217 | documentation for more details. |
| 218 | |
| Karthik Bharadwaj | e4f6401 | 2022-10-31 18:29:14 +0000 | [diff] [blame] | 219 | #### Recommended Implementation flow |
| 220 | |
| 221 | While there may be minor differences, most CHRE PAL [API][CHRE_PAL_DIR_URL] |
| 222 | implementations follow the following pattern: |
| 223 | |
| 224 | 1. **Implement the Module API for CHRE** |
| 225 | |
| 226 | CHRE provides a standardized structure containing various interfaces for |
| 227 | calling into the vendor's closed source code in _pal/<feature>.h_. These |
| 228 | functions must be implemented by the platform, and provided to CHRE when a call |
| 229 | to _chrePal<feature>GetApi_ function is called. Functions to be implemented are |
| 230 | of 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 |
| Victor Berchet | 32e6420 | 2022-11-22 11:10:19 -0800 | [diff] [blame] | 238 | more of these callbacks need to be invoked in response to a request from |
| Karthik Bharadwaj | e4f6401 | 2022-10-31 18:29:14 +0000 | [diff] [blame] | 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 | |
| 251 | 2. ** Use CHRE's callbacks ** |
| 252 | |
| 253 | CHRE provides a set of module specific callbacks by invoking the _open()_ access |
| 254 | function provided by the Module API. It then starts performing control or data |
| 255 | requests as needed, by invoking the request functions in the Module API. The PAL |
| 256 | is expected to process these requests, and invoke the appropriate CHRE provided |
| 257 | callback in response. Note that some callbacks might require memory ownership |
| 258 | to be held until explicitly released. For example, upon an audio request from |
| 259 | CHRE via a call to the `requestAudioDataEvent` audio PAL API, the platform |
| 260 | might invoke the `audioDataEventCallback` when the audio data is ready and |
| 261 | packaged approapriately into a `chreAudioDataEvent` structure. The platform |
| 262 | must ensure that the memory associated with this data structure remains in |
| 263 | context until CHRE explicitly releases it via a call to `releaseAudioDataEvent`. |
| 264 | |
| 265 | Please refer to the appropriate PAL documentation to ensure that such |
| 266 | dependencies are understood early in the development phase. |
| 267 | |
| 268 | #### Reference implementations |
| 269 | |
| 270 | Please refer to the various reference implementations that are |
| 271 | [available][CHRE_LINUX_DIR_URL] for CHRE PALS for the Linux platform. Note that |
| 272 | this implementation is meant to highlight the usage of the PAL APIs and |
| 273 | callbacks, and might not necessarily port directly over into a resource |
| 274 | constrained embedded context. |
| 275 | |
| Brian Duddie | 7f23a87 | 2020-07-01 14:27:31 -0700 | [diff] [blame] | 276 | ### PAL Verification |
| 277 | |
| 278 | There are several ways to test the PAL implementation beyond manual testing. |
| 279 | Some of them are listed below in increasing order of the amount of checks run by |
| 280 | the tests. |
| 281 | |
| 282 | 1. Use the FeatureWorld apps provided under the `apps` directory to exercise |
| 283 | the various PAL APIs and verify the CHRE API requirements are being met |
| 284 | |
| 285 | 2. Assuming the platform PAL implementations utilize CHPP and can communicate |
| 286 | from the host machine to the target chipset, execute `run_pal_impl_tests.sh` to |
| karthik bharadwaj | 2320790 | 2020-07-23 10:29:18 -0700 | [diff] [blame] | 287 | run basic consistency checks on the PAL |
| Brian Duddie | 7f23a87 | 2020-07-01 14:27:31 -0700 | [diff] [blame] | 288 | |
| 289 | 3. Execute tests (see Testing section for details) |
| 290 | |
| 291 | ## Dynamic Loading Support |
| 292 | |
| 293 | CHRE requires support for runtime loading and unloading of nanoapp binaries. |
| 294 | There 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 | |
| 306 | While dynamic loading is a responsibility of the platform implementation and may |
| 307 | already be a part of the underlying OS/system capabilities, the CHRE team is |
| 308 | working on a reference implementation for a future release. Please reach out via |
| 309 | your TAM if you are interested in integrating this reference code prior to its |
| 310 | public release. |
| Karthik Bharadwaj | e4f6401 | 2022-10-31 18:29:14 +0000 | [diff] [blame] | 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 | |
| Arthur Ishiguro | 5cae813 | 2022-10-31 18:46:23 +0000 | [diff] [blame] | 315 | ## Adding Context Hub support |
| 316 | |
| 317 | Once you have implemented the necessary pieces described previously, you are |
| 318 | now ready to add the Context Hub support on the device! Here are the necessary |
| 319 | steps to do this: |
| 320 | |
| 321 | 1. Add the HAL implementation on the device |
| 322 | |
| 323 | Add the build target of the Context Hub HAL implementation to your device .mk |
| 324 | file. For example, if the default generic Context Hub HAL is being used, you |
| 325 | can add the following: |
| 326 | |
| 327 | ``` |
| 328 | PRODUCT_PACKAGES += \ |
| 329 | android.hardware.contexthub-service.generic |
| 330 | ``` |
| 331 | |
| 332 | |
| 333 | Currently, the generic Context Hub HAL relies on the CHRE daemon to communicate |
| 334 | with CHRE. If you are using one of our existing platforms, you can add one of |
| 335 | the following CHRE daemon build targets to your PRODUCT_PACKAGES as you did the |
| 336 | generic HAL above. |
| 337 | |
| Michael Bestas | 527e88b | 2025-03-10 22:34:00 +0200 | [diff] [blame] | 338 | Qualcomm target: `chre_daemon_msm`\ |
| Arthur Ishiguro | 5cae813 | 2022-10-31 18:46:23 +0000 | [diff] [blame] | 339 | Exynos target: `chre_daemon_exynos`\ |
| 340 | MediaTek target: `TBD` |
| 341 | |
| 342 | Otherwise, you can look at those target definitions to define a new one for |
| 343 | your specific platform. |
| 344 | |
| 345 | 2. Add the relevant SElinux policies for the device |
| 346 | |
| 347 | Resolve any missing SElinux violations by using the relevant tools such as |
| 348 | audit2allow, and updating the SElinux policies for your device. You may follow |
| 349 | the directions in [the official Android page](https://source.android.com/docs/security/features/selinux/validate) |
| 350 | for additional guidance. |
| 351 | |
| 352 | 3. Add the Context Hub feature flag for the device |
| 353 | |
| 354 | Add the following in your device.mk file: |
| 355 | |
| 356 | ``` |
| 357 | PRODUCT_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 | |
| 361 | The above change will enable the Context Hub Service on the device, and expects |
| 362 | that the Context Hub HAL comes up. If (1) and (2) are not performed, the device |
| 363 | may fail to boot to the Android home screen. |