254 lines
12 KiB
Markdown
254 lines
12 KiB
Markdown
# 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.
|