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.

200 lines
9.8 KiB

*** aside
See also: [Nanoapp Developer Guide](/doc/nanoapp_developer_guide.md) |
[Interacting with Nanoapps](/doc/nanoapp_clients.md)
***
# Nanoapp Overview
[TOC]
Nanoapps are applications written in C or C++ which run in CHRE, to leverage
low-power hardware. Typically, nanoapps integrate with a component on the
Android side, such as a privileged APK, in order to provide complete end-to-end
functionality of the target feature. This Android-side component is referred to
as the nanoapps “client”. Since nanoapps are not limited to the same power
constraints that Android apps are, they can process inputs, like sensor data,
much more frequently while the devices screen is off.
Nanoapps are abstracted from the underlying platform details by the CHRE API,
which is standardized across all CHRE implementations. This means that a nanoapp
is *code compatible* across devices - its source code does not need to be
changed to run on different hardware, but it *may* need to be recompiled. The
CHRE API also provides binary compatibility guarantees across minor versions, so
a nanoapp does not need to be recompiled to run on a device that exposes a newer
or older version of the CHRE API. These properties help provide for the maximum
reuse of code across devices.
Due to system security and resource constraints of the platforms that CHRE
targets, only device OEMs and their trusted partners are able to create
nanoapps. In other words, the system only runs nanoapps that possess a digital
signature that is trusted in advance by the device manufacturer, and APKs must
hold a special privileged/same-signature permission (`ACCESS_CONTEXT_HUB`) to be
able to interact with nanoapps and the Context Hub in general. However, this
does not mean that third-party APKs cannot benefit from CHRE - nanoapps can be
used to power APIs available for use by any Android app.
## Methods for Loading a Nanoapp
While nanoapps are nominally dynamically loadable modules, they can be loaded
into a device through a few methods, each of which has pros and cons elaborated
below.
### Static Nanoapps
Static nanoapps are, as the name suggests, statically compiled into the CHRE
framework binary. Static nanoapps are automatically initialized after the CHRE
framework completes its initialization during the boot process.
Static nanoapps typically arent used in production, because this monolithic
approach has downsides in terms of version control, updatability, etc., but it
can be useful during CHRE development and bring-up of new devices, especially
before dynamic loading functionality is enabled. For example, the FeatureWorld
nanoapps (described later) are typically built as static nanoapps.
Static nanoapps are typically unconditionally compiled as part of the framework
build (via `apps/apps.mk`), but then stripped out by the linker if unreferenced
(using the `--gc-sections` option, or equivalent). Static nanoapps are
referenced only if their initialization function appears in the
`kStaticNanoappList` array, which by default is empty, but can be overridden by
the device variant makefile, as in `variant/simulator/` for example.
Some boilerplate is needed to enable nanoapp to be built as a static nanoapp -
see the code wrapped in `#ifdef CHRE_NANOAPP_INTERNAL` in
`apps/hello_world/hello_world.cc`.
### Preloaded Nanoapps
Preloaded nanoapps are built as a separate binary from the CHRE framework, but
included in the vendor partition of an overall device image (hence they are
“preloaded” onto the device). The binaries associated with a preloaded nanoapp
(usually a `.so` and a `.napp_header` file) are checked in to the Android tree
as a “prebuilt” binary, and integrated into the Android build system so as to
appear in the resulting device image, for example using `$(BUILD_PREBUILT)` in
Android.mk, or `prebuilt_dsp` or `prebuilt_firmware` in Android.bp.
While the mechanism for loading prebuilt nanoapps is platform-specific, the CHRE
framework generally follows these steps at boot time:
1. When CHRE starts up, the CHRE daemon process running on the AP reads the
configuration file `/vendor/etc/chre/preloaded_nanoapps.json`, which contains
the list of nanoapps that should be automatically loaded.
2. For each nanoapp in the JSON file, the CHRE daemon reads the `.napp_header`
from storage, and sends a message to CHRE requesting it to load the nanoapp.
3. The platform layer of the CHRE framework handles the requests by loading,
authenticating, linking, and starting the nanoapp.
4. CHRE initialization proceeds (it is important for all preloaded nanoapps to
be included at the first moment list query command can be processed, to
avoid race conditions leading to clients believing that a preloaded nanoapp
is missing).
This path is most commonly used to deploy nanoapps to production, as the entire
device software can be validated together without external dependencies, while
also preserving the ability to update nanoapps independent from other components
in the system.
### Fully Dynamic Nanoapps
At the binary level, a preloaded nanoapp and fully dynamic nanoapp are
identical. The key difference is where they are stored and how they are
initially loaded into CHRE, and potentially how metadata is handled. In most
cases, preloaded nanoapps will use a separate `.napp_header` file with metadata
and `.so` file for the actual binary, a fully dynamic nanoapp has the header
prepended to the binary, and carries the `.napp` file type suffix. In other
words, the command `cat my_nanoapp.napp_header my_nanoapp.so > my_nanoapp.napp`
can be used to create a fully dynamic nanoapp file from these components.
Instead of being stored on the device filesystem, fully dynamic nanoapps can be
loaded at any time after initialization using the
`ContextHubManager.loadNanoApp()` Java API. This allows nanoapps to be
updated/delivered by an APK, outside of a full Android system update (OTA).
This mechanism is used to dynamically load and unload test nanoapps, but can
also be used for production nanoapps.
## Other Nanoapp Types
Some platforms support loading nanoapps into multiple tiers of memory, for
example low-power tightly coupled memory (TCM, usually SRAM), versus a
higher-power but higher-capacity memory bank (such as DRAM). This distinction is
normally made at the build target variant level.
CHRE also supports the concept of a *system nanoapp*, which is a nanoapp whose
purpose is to accomplish some low-level, device-specific functionality that is
purely beneath the HAL level. System nanoapps are therefore hidden from the
nanoapp list at the HAL. This property is controlled by setting the
`NANOAPP_IS_SYSTEM_NANOAPP` variable in the nanoapp Makefile.
## Example AOSP Nanoapps
Some basic nanoapps can be found in the `apps/` folder, which are used for test
purposes, as well as to demonstrate how to use the CHRE APIs.
### FeatureWorld Nanoapps
The *FeatureWorld* nanoapps each exercise a part of the CHRE API, and print
results/output to `chreLog`. An overview of a few of the key FeatureWorld
nanoapps is given below:
* `hello_world`: While not technically a FeatureWorld nanoapp, its generally
the first nanoapp to be tried, and it simply outputs a log message when it
starts and ends, and upon any event received.
* `message_world`: Exercises host messaging functionality. Typically used in
conjunction with `host/common/test/chre_test_client.cc` (see
`sendMessageToNanoapp()` in that file).
* `sensor_world`: Enables sensors and prints the samples it receives. This
nanoapp is typically customized prior to executing, for example to control
which sensors it will enable. It also supports a “break it” mode which
stresses the system by enabling/disabling sensors frequently.
* `host_awake_world`: Used to help validate functionality used for
opportunistically sending messages to the AP when it is awake.
### Stress Test Nanoapps
These nanoapps help stress test the CHRE framework. They include:
* `audio_stress_test`: Repeatedly enables and disables an audio source,
verifying that it continues to provide data as expected.
* `sensor_world`: Contains a “break it” mode which repeatedly enables, disables,
and reconfigures sensors.
* `spammer`: Sends a constant stream of messages and events to stress test the
queueing system.
* `unload_tester`: Used in conjunction with the spammer nanoapp to verify that
unloading a nanoapp with pending events/messages completes successfully. Note
that this nanoapp references internal framework functions (e.g.
`EventLoopManager::deferCallback()`) to accomplish its functionality, which is
generally only permissible for testing purposes.
### Power Test
The `power_test` nanoapp is intended to be used in conjunction with special
hardware that directly measures the power usage of the system and/or its
components. This nanoapp is intended to be used with its host-side client,
`chre_power_test_client`, to create some activity at the CHRE API level which
can then be measured. For example, running `./chre_power_test_client wifi enable
5000000000` will configure the `power_test` nanoapp to request a WiFi scan every
5 seconds - the power monitoring equipment can then be used to determine the
power cost of performing a WiFi scan from CHRE. Typically this is done after
unloading all other nanoapps in the system (which can be done via
`./chre_power_test_client unloadall`), and disabling all other functionality, to
get a clean power trace of purely the functionality exercised by the
`power_test` nanoapp.
Refer to `chre_power_test_client.cc` for more details, including a full listing
of all supported commands.
### Nanoapps Used with Java-based Test Suites
Nanoapps under `apps/test` are associated with a test suite, for example Context
Hub Qualification Test Suite (CHQTS), which is used to test that a given device
upholds the requirements of the CHRE API. Much of the host-side Java code
associated with these nanoapps can be found in the `java/` folder.