|  | # CHRE Framework Porting Guide | 
|  |  | 
|  | [TOC] | 
|  |  | 
|  | CHRE achieves portability and extensibility across platforms by defining | 
|  | interfaces that the platform needs to implement. These interfaces provide | 
|  | dependencies for the common CHRE code that are necessarily platform-specific. | 
|  | Additionally, platform code calls into common code to ferry events from | 
|  | underlying subsystems to nanoapps. | 
|  |  | 
|  | This section gives an overview of the steps one should take to add support for a | 
|  | new platform in the CHRE reference implementation. | 
|  |  | 
|  | ## Directory Structure | 
|  |  | 
|  | CHRE platform code can be broadly categorized as follows. | 
|  |  | 
|  | ### Platform Interfaces | 
|  |  | 
|  | Files under `platform/include` serve as the interface between common code in | 
|  | `core/` and other platform-specific code in `platform/<platform_name>`.  These | 
|  | files are considered common and should not be modified for the sake of | 
|  | supporting an individual platform. | 
|  |  | 
|  | ### Shared Platform Code | 
|  |  | 
|  | Located in `platform/shared/`, the code here is part of the platform layer’s | 
|  | responsibilities, but is not necessarily specific to only one platform. In other | 
|  | words, this code is likely to be re-used by multiple platforms, but it is not | 
|  | strictly necessary for a given platform to use it. | 
|  |  | 
|  | ### Platform-specific Code | 
|  |  | 
|  | Files under `platform/<platform_name>` are specific to the underlying software | 
|  | of a given platform, for example the APIs which are used to access functionality | 
|  | like sensors, the operating system, etc. To permit code reuse, the CHRE platform | 
|  | layer for a given device may be composed of files from multiple | 
|  | `<platform_name>` folders, for example if the same sensor framework is supported | 
|  | across multiple OSes, there may be one folder that provides the components that | 
|  | are specific to just the OS. | 
|  |  | 
|  | Platform-specific code can be further subdivided into: | 
|  |  | 
|  | * **Source files**: normally included at | 
|  | `platform/<platform_name>/<file_name>.cc`, but may appear in a subdirectory | 
|  |  | 
|  | * **Headers which are includable by common code**: these are placed at | 
|  | `platform/<platform_name>/include/chre/target_platform/<file_name>.h`, and are | 
|  | included by *Platform Interfaces* found in `platform/include` and provide | 
|  | inline or base class definitions, such as `mutex_base_impl.h` and | 
|  | `platform_sensor_base.h` respectively, or required macros | 
|  |  | 
|  | * **Fully platform-specific headers**: these typically appear at | 
|  | `platform/<platform_name>/include/chre/platform/<platform_name/<file_name>.h` | 
|  | and may only be included by other platform-specific code | 
|  |  | 
|  | ## Open Sourcing | 
|  |  | 
|  | Partners who add support for a new platform are recommended to upstream their | 
|  | code to | 
|  | [AOSP](https://source.android.com/setup/contribute#contribute-to-the-code). | 
|  | This helps ensure that details of your platform are considered by the team that | 
|  | maintains the core framework, so any changes that break compilation are | 
|  | addressed in a timely fashion, and enables you to receive useful code review | 
|  | feedback to improve the quality of your CHRE implementation. Please reach out | 
|  | via your TAM to help organize this effort. | 
|  |  | 
|  | If some parts of a platform’s CHRE implementation must be kept closed source, | 
|  | then it is recommended to be kept in a separate Git project (under vendor/ in | 
|  | the Android tree). This vendor-private code can be integrated with the main CHRE | 
|  | build system through the `CHRE_VARIANT_MK_INCLUDES` variable. See the build | 
|  | system documentation for more details. | 
|  |  | 
|  | ## Recommended Steps for Porting CHRE | 
|  |  | 
|  | When starting to add support for a new platform in the CHRE framework, it’s | 
|  | recommended to break the task into manageable chunks, to progressively add more | 
|  | functionality until the full desired feature set is achieved. An existing | 
|  | platform implementation can be referenced to create empty stubs, and then | 
|  | proceed to add implementations piece by piece, testing along the way. | 
|  |  | 
|  | CHRE provides various test nanoapps in `apps/` that exercise a particular | 
|  | feature that the platform provides. These are selectively compiled into the | 
|  | firmware statically via a `static_nanoapps.cc` source file. | 
|  |  | 
|  | With this in mind, it is recommended to follow this general approach: | 
|  |  | 
|  | 1. Create a new platform with only empty stubs, with optional features (like | 
|  | `CHRE_GNSS_SUPPORT_ENABLED`) disabled at build-time | 
|  |  | 
|  | 2. Work on updating the build system to add a new build target and achieve | 
|  | successful compilation and linking (see the build system documentation for | 
|  | details) | 
|  |  | 
|  | 3. Implement base primitives from `platform/include`, including support for | 
|  | mutexes, condition variables, atomics, time, timers, memory allocation, and | 
|  | logging | 
|  |  | 
|  | 4. Add initialization code to start the CHRE thread | 
|  |  | 
|  | 5. Add static nanoapp initialization support (usually this is just a copy/paste | 
|  | from another platform) | 
|  |  | 
|  | 6. Confirm that the ‘hello world’ nanoapp produces the expected log message (if | 
|  | it does, huzzah!) | 
|  |  | 
|  | 7. Complete any remaining primitives, like assert | 
|  |  | 
|  | 8. Implement host link and the daemon/HAL on the host (AP) side, and validate it | 
|  | with a combination of the message world nanoapp and the host-side test code | 
|  | found at `host/common/test/chre_test_client.cc` | 
|  |  | 
|  | At this stage, the core functionality has been enabled, and further steps should | 
|  | include enabling dynamic loading (described in its own section below), and the | 
|  | desired optional feature areas, like sensors (potentially via their respective | 
|  | PALs, described in the next section). | 
|  |  | 
|  | ## Implementing the Context Hub HAL | 
|  |  | 
|  | The Context Hub HAL (found in the Android tree under | 
|  | `hardware/interfaces/contexthub`) defines the interface between Android and the | 
|  | underlying CHRE implementation, but as CHRE is implemented on a different | 
|  | processor from the HAL, the HAL is mostly responsible for relaying messages to | 
|  | CHRE. This project includes an implementation of the Context Hub HAL under | 
|  | `host/hal_generic` which pairs with the CHRE framework reference implementation. | 
|  | It converts between HAL API calls and serialized flatbuffers messages, using the | 
|  | host messaging protocol defined under `platform/shared` (platform | 
|  | implementations are able to choose a different protocol if desired, but would | 
|  | require a new HAL implementation), and passes the messages to and from the CHRE | 
|  | daemon over a socket. The CHRE daemon is in turn responsible for communicating | 
|  | directly with CHRE, including common functionality like relaying messages to and | 
|  | from nanoapps, as well as device-specific functionality as needed. Some examples | 
|  | of CHRE functionality that are typically implemented with support from the CHRE | 
|  | daemon include: | 
|  |  | 
|  | * Loading preloaded nanoapps at startup | 
|  | * Passing log messages from CHRE into Android logcat | 
|  | * Determining the offset between `chreGetTime()` and Android’s | 
|  | `SystemClock.elapsedRealtimeNanos()` for use with | 
|  | `chreGetEstimatedHostTimeOffset()` | 
|  | * Coordination with the SoundTrigger HAL for audio functionality | 
|  | * Exposing CHRE functionality to other vendor-specific components (e.g. via | 
|  | `chre::SocketClient`) | 
|  |  | 
|  | When adding support for a new platform, a new HAL implementation and/or daemon | 
|  | implementation on the host side may be required. Refer to code in the `host/` | 
|  | directory for examples. | 
|  |  | 
|  | ## Implementing Optional Feature Areas (e.g. PALs) | 
|  |  | 
|  | CHRE provides groups of functionality called *feature areas* which are | 
|  | considered optional from the perspective of the CHRE API, but may be required to | 
|  | support a desired nanoapp. CHRE feature areas include sensors, GNSS, audio, and | 
|  | others. There are two ways by which this functionality can be exposed to the | 
|  | common CHRE framework code: via the `Platform<Module>` C++ classes, or the C PAL | 
|  | (Platform Abstraction Layer) APIs. It may not be necessary to implement all of | 
|  | the available feature areas, and they can instead be disabled if they won’t be | 
|  | implemented. | 
|  |  | 
|  | The Platform C++ Classes and PAL APIs have extensive documentation in their | 
|  | header files, including details on requirements. Please refer to the headers for | 
|  | precise implementation details. | 
|  |  | 
|  | ### Platform C++ Classes vs. PAL APIs | 
|  |  | 
|  | Each feature area includes one or more `Platform<Module>` classes which the | 
|  | common framework code directly interacts with. These classes may be directly | 
|  | implemented to provide the given functionality, or the shim to the PAL APIs | 
|  | included in the `shared` platform directory may be used. PALs provide a C API | 
|  | which is suitable for use as a binary interface, for example between two dynamic | 
|  | modules/libraries, and it also allows for the main CHRE to platform-specific | 
|  | translation to be implemented in C, which may be preferable in some cases. | 
|  |  | 
|  | Note that the PAL APIs are binary-stable, in that it’s possible for the CHRE | 
|  | framework to work with a module that implements a different minor version of the | 
|  | PAL API, full backwards compatibility (newer CHRE framework to older PAL) is not | 
|  | guaranteed, and may not be possible due to behavioral changes in the CHRE API. | 
|  | While it is possible for a PAL implementation to simultaneously support multiple | 
|  | versions of the PAL API, it is generally recommended to ensure the PAL API | 
|  | version matches between the framework and PAL module, unless the source control | 
|  | benefits of a common PAL binary are desired. | 
|  |  | 
|  | This level of compatibility is not provided for the C++ `Platform<Module>` | 
|  | classes, as the CHRE framework may introduce changes that break compilation. If | 
|  | a platform implementation is included in AOSP, then it is possible for the | 
|  | potential impact to be evaluated and addressed early. | 
|  |  | 
|  | ### Disabling Feature Areas | 
|  |  | 
|  | If a feature area is not supported, setting the make variable | 
|  | `CHRE_<name>_SUPPORT_ENABLED` to false in the variant makefile will avoid | 
|  | inclusion of common code for that feature area. Note that it must still be | 
|  | possible for the associated CHRE APIs to be called by nanoapps without crashing | 
|  | - these functions must return an appropriate response indicating the lack of | 
|  | support (refer to `platform/shared/chre_api_<name>.cc` for examples). | 
|  |  | 
|  | ### Implementing Platform C++ Classes | 
|  |  | 
|  | As described in the CHRE Framework Overview section, CHRE abstracts common code | 
|  | from platform-specific code at compile time by inheriting through | 
|  | `Platform<Module>` and `Platform<Module>Base` classes. Platform-specific code | 
|  | may retrieve a reference to other objects in CHRE via | 
|  | `EventLoopManagerSingleton::get()`, which returns a pointer to the | 
|  | `EventLoopManager` object which contains all core system state. Refer to the | 
|  | `Platform<Module>` header file found in `platform/include`, and implementation | 
|  | examples from other platforms for further details. | 
|  |  | 
|  | ### Implementing PALs | 
|  |  | 
|  | PAL implementations must only use the callback and system APIs provided in | 
|  | `open()` to call into the CHRE framework, as the other functions in the CHRE | 
|  | framework do not have a stable API. | 
|  |  | 
|  | If a PAL implementation is provided as a dynamic module in binary form, it can | 
|  | be linked into the CHRE framework at build time by adding it to | 
|  | `TARGET_SO_LATE_LIBS` in the build variant’s makefile - see the build system | 
|  | documentation for more details. | 
|  |  | 
|  | ### PAL Verification | 
|  |  | 
|  | There are several ways to test the PAL implementation beyond manual testing. | 
|  | Some of them are listed below in increasing order of the amount of checks run by | 
|  | the tests. | 
|  |  | 
|  | 1.  Use the FeatureWorld apps provided under the `apps` directory to exercise | 
|  | the various PAL APIs and verify the CHRE API requirements are being met | 
|  |  | 
|  | 2. Assuming the platform PAL implementations utilize CHPP and can communicate | 
|  | from the host machine to the target chipset, execute `run_pal_impl_tests.sh` to | 
|  | run basic consistency checks on the PAL | 
|  |  | 
|  | 3.  Execute tests (see Testing section for details) | 
|  |  | 
|  | ## Dynamic Loading Support | 
|  |  | 
|  | CHRE requires support for runtime loading and unloading of nanoapp binaries. | 
|  | There are several advantages to this approach: | 
|  |  | 
|  | * Decouples nanoapp binaries from the underlying system - can maintain and | 
|  | deploy a single nanoapp binary across multiple devices, even if they support | 
|  | different versions of Android or the CHRE API | 
|  |  | 
|  | * Makes it possible to update nanoapps without requiring a system reboot, | 
|  | particularly on platforms where CHRE runs as part of a statically compiled | 
|  | firmware | 
|  |  | 
|  | * Enables advanced capabilities, like staged rollouts and targeted A/B testing | 
|  |  | 
|  | While dynamic loading is a responsibility of the platform implementation and may | 
|  | already be a part of the underlying OS/system capabilities, the CHRE team is | 
|  | working on a reference implementation for a future release. Please reach out via | 
|  | your TAM if you are interested in integrating this reference code prior to its | 
|  | public release. |