You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
7.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Extending CHRE with Vendor-specific Functionality
[TOC]
The CHRE framework is easily extensible with no modifications to the core
framework. Depending on the goals of the new API, one or more of the following
steps must be performed. At a high-level, to add a new vendor-specific API to
CHRE, one must:
1. Define new APIs in a header that can be referenced by both platform CHRE
framework code and vendor-specific nanoapps.
2. Expose the new APIs from the framework to nanoapps, and connect them to a new
module to provide the desired functionality
3. Integrate the new module with existing CHRE framework features, e.g. the
event subsystem, to provide complete functionality that fits within the
existing CHRE conventions
It's best to refer to existing standard CHRE API feature areas, such as
`chre/wifi.h` and `WifiRequestManager`, and follow a similar design where
possible.
## Defining the API
To prevent collision with future common CHRE API definitions, vendor extensions
must not use the plain chre prefix followed by a capitalized letter. Instead,
its recommended to prefix the APIs with the vendors name as lowercase. For
example, if your company name is XYZ Semiconductor and youre defining a new
widget API, its recommended to use a naming scheme like
`chrexyzWidget<FunctionName>()`, and included indirectly via `#include
<chre_xyz.h>` or directly via `<chre_xyz/widget.h>`. The equivalent C++
namespace would be `::chre::xyz`.
There are reserved ranges for vendor/implementation-specific event types
(starting from `CHRE_EVENT_INTERNAL_EXTENDED_FIRST_EVENT`), and other cases
where vendors may wish or need to define a custom value in an existing field. To
prevent collision with future versions of the CHRE API, vendor extensions must
only use values within vendor-reserved ranges. If you would like to add a new
value to an existing field for a vendor extension and a vendor-reserved range
does not already exist, please reach out to the CHRE team for guidance -
solutions may involve creating a new reserved range in the common CHRE API, or
providing advice on a different method of defining the API.
Vendors can only add on to the CHRE API - existing APIs must not be changed. Do
not modify core CHRE definitions, for example by adding on fields to common
structures, re-using event types, repurposing fields that are reserved for
future use, etc.
Its recommended that any vendor extensions consider compatibility when
designing it - see the Compatibility section for API design guidelines.
If this API is intended to be open-sourced, it should be added to
`platform/<platform_name>/extensions/include`. Otherwise, its suggested that
the API be placed outside of the CHRE tree, in a separate Git project under
`vendor/` in the Android tree, to avoid potential conflicts when upgrading to a
new version of CHRE.
### Build Customization
As part of the CHRE framework build system, the `CHRE_VARIANT_MK_INCLUDES`
environment variable can be used to inject an external `.mk` file into the
top-level build without any source code changes in the system/chre project.
Alternatively, if open sourcing, the `platform.mk` file should contain the
additions needed to support the new vendor API. Refer to the CHRE framework
build documentation for further details.
To expose the new functionality to nanoapps, its recommended to create a single
`.mk` file that adds the necessary `COMMON_CFLAGS` entries (and potentially
other build configuration). For example, create a `chrexyz.mk` file which
nanoapps should include in their Makefile prior to including
`$(CHRE_PREFIX)/build/nanoapp/app.mk`.
## Threading Model
Interactions with a nanoapp always happen from within the CHRE thread that runs
the EventLoop, so vendor extension code does not need to worry about race
conditions due to multiple nanoapps calling into APIs, and likewise nanoapps do
not need to worry about race conditions in its callbacks/handlers. However, it
is common for a platform module to receive data in a callback on another thread.
In that case, it is recommended to use `EventLoopManager::deferCallback()` to
pass the incoming data to the CHRE thread for processing, as opposed to using
mutexes or other synchronization primitives, to avoid multithreading-related
issues that can arise in rare conditions. Further, note that most of the core
CHRE functionality is only safe to call from within the CHRE thread (other than
posting an event, or methods that are explicitly marked as thread-safe).
## Initialization
Since the new API will not be part of the core framework, it wont be attached
to `EventLoopManager` or initialized as part of `chre::init()` or
`EventLoopManagerSingleton::get()->lateInit()`, since vendor-extension APIs are
by definition not part of the common code. Instead, a separate singleton object
should be created, for example `chre::xyz::VendorExtensionManager`, and
platform-specific initialization code should invoke any necessary initialization
**after** `chre::init` is called, but **before** loading any static nanoapps or
invoking `EventLoop::run()` to ensure that nanoapps dont begin interacting with
the API before its state is ready.
## Handling Nanoapp API Calls
Calls from a nanoapp into the CHRE framework first arrive in platform-specific
code (refer to the Framework Overview documentation for details). The first step
once an API call reaches the framework is usually to call
`EventLoopManager::validateChreApiCall(__func__)`. This fetches a pointer to the
`Nanoapp` object associated with the nanoapp that invoked the API, which will
fail if the API is called outside of the EventLoop thread context (see the
Threading Model above). From this point, the vendor extension singleton should
be used to invoke the appropriate functionality.
## Sending Events to Nanoapps
Vendor extension APIs that need to pass data to a nanoapp asynchronously should
use the event susbsystem, using the vendor-reserved event type range (starting
at `CHRE_EVENT_INTERNAL_EXTENDED_FIRST_EVENT` and extending to
`CHRE_EVENT_INTERNAL_LAST_EVENT`). Event types for a given vendor extension
should be globally unique and stable over time.
Synchronous API calls that can potentially block for periods greater than a few
milliseconds are discouraged, as these can prevent other nanoapps from
executing, and/or cause the pending event queue to grow excessively during
periods of high activity. Refer to the GNSS and WWAN APIs for design patterns
related to passing data to a nanoapp asynchronously, using custom event payloads
and/or `chreAsyncResult`.
Events can either be unicast to a nanoapp identified by its instance ID
(`Nanoapp::getInstanceId()`), or broadcast to all nanoapps registered for the
given event type - see `Nanoapp::registerForBroadcastEvent()` and
`Nanoapp::unregisterForBroadcastEvent()`.
Use `EventLoop::postEventOrDie()` or `EventLoop::postLowPriorityEventOrFree()`
(via `EventLoopManagerSingleton::get()->getEventLoop()`) to pass events to
nanoapps, depending on what error handling is desired in the case that the event
cannot be posted to the queue. Any memory referenced by `eventData` must not be
modified until `freeCallback` is invoked.