1# Nanoapp Developer Guide 2 3[TOC] 4 5Since CHRE is an open platform, anyone can write nanoapps. However, deploying to 6a device requires cooperation of the device manufacturer, because CHRE is a 7security-sensitive trusted environment, similar to other low-level firmware, and 8it typically has tight resource constraints. This section assumes you have a 9basic understanding of what a nanoapp is (if not, see the Nanoapp Overview 10section), and provides some simple instructions to help you get started with 11developing your own nanoapp. 12 13## Getting Started 14 15When starting a new nanoapp, it’s helpful to start with the skeleton of an 16existing nanoapp. The simplest example can be found at `apps/hello_world`. Start 17by copying this folder to the location where you will develop the nanoapp - it 18can be outside of the `system/chre` project, for example in a vendor-specific 19Git repository in the `vendor/` folder of the Android tree. 20 21If you don’t plan to use this nanoapp as a *static nanoapp* (see the Nanoapp 22Overview for details), remove the `hello_world.mk` file and delete the code 23blocks wrapped in `#ifdef CHRE_NANOAPP_INTERNAL`. Rename the remaining files to 24match your nanoapp. 25 26### Picking a Nanoapp ID 27 28Nanoapps are uniquely identified by a 64-bit number. The most significant 5 29bytes of this number are the vendor identifier, and the remaining bytes identify 30the nanoapp within the vendor’s namespace. The vendor identifier is usually 31devised from an ASCII representation of the vendor’s name, for example Google 32uses 0x476F6F676C (“Googl”). The remaining portion of the ID is typically just 33an incrementing value for each nanoapp. 34 35Refer to `system/chre/chre_api/include/chre_api/chre/common.h` and 36`util/include/chre/util/nanoapp/app_id.h` for some examples and utilities. 37 38Be sure to pick a unique nanoapp ID when creating a new nanoapp. 39 40### Picking a Language 41 42CHRE guarantees support for nanoapps written in C99 or C++11, though not all 43standard library functions are supported (see below for details). For a 44device-specific nanoapp, additional programming languages/versions *may* be 45supported, but this can impact portability. 46 47### Building the Nanoapp Binary 48 49While it’s possible to build a nanoapp with a different build system, just as it 50is for the CHRE framework, it’s recommended to use the common build system 51included in this project, as it makes it easy to support a variety of target 52platforms. The rest of this section assumes you are using the CHRE build system 53to create a non-static nanoapp. 54 55Update the `Makefile` in your nanoapp’s directory to: 56 57* Define nanoapp metadata, including: 58 * `NANOAPP_NAME`: sets the output filename of the binary 59 * `NANOAPP_ID`: 64-bit identifier, in hexadecimal format 60 * `NANOAPP_VERSION`: 32-bit version, in hexadecimal format (see versioning 61 section below) 62 * `NANOAPP_NAME_STRING`, `NANOAPP_VENDOR_STRING`: human-readable strings for 63 the name of the nanoapp and vendor, respectively 64 * `NANOAPP_IS_SYSTEM_NANOAPP`: 0 or 1 (see Nanoapp Overview) 65* Populate `COMMON_SRCS` with the C or C++ source files to compile 66* Populate `COMMON_CFLAGS` with compiler flags, like additional include paths 67* Include any additional `.mk` files for vendor extensions, etc. before `app.mk` 68 69Refer to `build/nanoapp/app.mk` for full details. 70 71The nanoapp can then be built using a command like ``OPT_LEVEL=s make 72<build_target> -j`nproc` `` (see the CHRE Framework Build System section for 73details on build targets), which will produce build artifacts at 74`out/<build_target>/<nanoapp_name>.*`. 75 76### Loading onto a Device 77 78Exact steps to load a nanoapp binary can vary by device, but for developing a 79preloaded nanoapp, this typically involves the following steps: 80 81* Perform any needed post-processing of the nanoapp binary to permit it to be 82 loaded (such as signing with a development or production key) 83* Write the binary to the device’s storage (for example, using `adb push`) 84* Update `preloaded_nanoapps.json` or other configuration as needed, so that 85 CHRE knows to load the new nanoapp 86* Restart CHRE to reload all nanoapps, including the new one 87 88## Nanoapp Versioning 89 90While not strictly enforced, nanoapps are recommended to follow the convention 91of the CHRE framework and use [Semantic Versioning](http://semver.org). In the 92case of a nanoapp, the key versioned “API” is considered the interface between 93the client and nanoapp. Nanoapp versions are represented as a 32-bit integer, 94where the most significant byte represents the major version, followed by one 95byte for the minor version, and two bytes for the patch version. 96 97## Using the CHRE API 98 99The CHRE API is the key interface between each nanoapp and the underlying 100system. Refer to the extensive API documentation in the header files at 101`chre_api/include`, as well as usage of the APIs by sample nanoapps. The CHRE 102API is normally included via `#include <chre.h>`. 103 104## Utility Libraries 105 106Some source and header files under `util` are specifically designed to aid in 107nanoapp development, and others were initially created for use in the framework 108but can be leveraged by nanoapps as well. In general, any source and header file 109there that does **not** include a header from `chre/platform` (part of the 110internal CHRE framework implementation details) may be used by a nanoapp, and 111files within a subdirectory called `nanoapp` are specifically targeted for use 112by nanoapps. 113 114This includes `util/include/chre/util/nanoapp/log.h` (meant to be included via 115`#include “chre/util/nanoapp/log.h”`), which provides macros like `LOGD` which 116can be conditionally compiled, include a configurable prefix to help identify 117the sender, and suppress double promotion warnings. 118 119The utilities library also includes a number of container classes, which are 120meant to mimic the C++ standard library, but with a lightweight, CHRE-compatible 121implementation. This includes: 122 123* `chre::DynamicVector`: an `std::vector` analogue 124* `chre::FixedSizeVector`: accessed like `std::vector`, but only uses statically 125 allocated memory 126* `chre::ArrayQueue`: can be used as a circular buffer 127* `chre::UniquePtr`: an `std::unique_ptr` analogue 128* `chre::Optional`: an analogue to `std::optional` from C++17 129* `chre::Singleton`: a container for a statically allocated object with explicit 130 initialization and deinitialization (e.g. enables construction of a global 131 object to be deferred until `nanoappStart()`) 132 133## Interacting with the Host 134 135Nanoapps can interact with one or more clients on the host (applications 136processor) through a flexible binary message-passing interface. For simple 137interactions in cases where the lowest memory footprint is desired, using only 138the built-in message type field with no additional payload, or passing 139hand-rolled packed C-style structures (e.g. using Java’s ByteBuffer on the 140client side) can work, though this approach can be error-prone. Using a 141well-defined serialization format, such as Protocol Buffers (see the Using 142NanoPB section below) or FlatBuffers, is usually a better choice. 143 144There are a few common tips to keep in mind when interacting with the host: 145 1461. Nanoapp binaries are usually updated independently from client code - watch 147out for compatibility issues arising from changes to the messaging protocol, and 148use a serialization format like Protocol Buffers if possible. 149 1502. Nanoapp messages to the host always wake it up if it’s asleep. If this is not 151required, nanoapps are encouraged to batch their messages and opportunistically 152send when the host wakes up for another reason (see 153`chreConfigureHostSleepStateEvents()`). 154 1553. After calling `chreSendMessageToHostEndpoint()`, ownership of the memory 156associated with the message payload is assigned to the framework. Do not modify 157it until the free callback is invoked. 158 1594. Nanoapp messaging should be unicast, unless broadcast messaging is strictly 160necessary. Design the messaging protocol such that the client initiates 161communication, and save the host endpoint ID in the nanoapp to use when sending 162replies. 163 164## Interacting with Other Nanoapps 165 166While most nanoapps are only concerned with providing functionality for a single 167client on the host, it is possible for a nanoapp to provide services to other 168nanoapps within CHRE. Similar to how nanoapps communicate with the host by 169passing *messages*, nanoapps can communicate with one another by passing 170*events* with arbitrary binary payload. Event IDs starting in the range 171`CHRE_EVENT_FIRST_USER_VALUE` are reserved for this purpose. 172 173Typically a nanoapp creates a *nanoapp client library* which other nanoapps can 174include, which presents a simple, expressive API, and handles the implementation 175details of passing events to the target nanoapp, and interpreting incoming 176messages. 177 178Refer to the functions defined in `chre/event.h` for more details. 179 180## Using TensorFlow Lite for Microcontrollers 181 182Many nanoapps use machine learning techniques to accomplish their functionality. 183The CHRE build system has built-in support for integrating [TensorFlow Lite for 184Microcontrollers](https://www.tensorflow.org/lite/microcontrollers) (TFLM) into 185a nanoapp. Sync the TFLM sources, set `TFLM_PATH`, and define `USE_TFLM=true` in 186your Makefile - see `apps/tflm_demo/README` for details and an example nanoapp. 187 188## Using Nanopb 189 190The CHRE build system has integrated support for using 191[Nanopb](https://jpa.kapsi.fi/nanopb/) to provide support for [Protocol 192Buffers](https://developers.google.com/protocol-buffers) in a nanoapp. To 193integrate this into your nanoapp’s Makefile, first install and configure 194dependencies: 195 196* Sync the Nanopb source tree (e.g. from a release on GitHub), and define the 197 `NANOPB_PREFIX` environment variable to its path 198* Download and install the protobuf compiler `protoc` and make it available in 199 your `$PATH`, or set the `PROTOC` environment variable 200 201Then in your nanoapp’s Makefile, populate `NANOPB_SRCS` with the desired 202`.proto` file(s). That’s it! Though some additional options/parameters are 203available - see `build/nanopb.mk` for details. 204 205## Nanoapp Development Best Practices 206 207Even though CHRE aims to provide an environment for low-power and low-latency 208contextual signal processing, these two are often conflicting goals. In 209addition, CHRE is usually implemented in a resource-constrained environment with 210limited memory available. 211 212As it requires collaboration from all nanoapps to optimize their resource usage 213for CHRE to live up to its promises, some best practices are provided here as 214guidance for nanoapp development. 215 216### Memory Efficiency 217 218#### Avoid dynamic heap allocations where possible 219 220As CHRE is designed in a resource-constrained environment, there is no guarantee 221runtime memory allocation will succeed. In addition, dynamic heap allocations 222make it difficult to estimate the memory usage in advance. Developers are 223therefore encouraged to use static allocations where possible. 224 225#### Be careful of stack usage 226 227Unlike Linux’s default stack of 8MB that scales dynamically, CHRE only has a 228fixed stack of limited size (8KB is typical). Ensure you keep any allocations to 229an absolute minimum and any large allocations should go out of scope prior to 230navigating deeper into a stack. 231 232#### Prefer in-place algorithms 233 234Prefer in-place algorithms over out-of-place ones where efficiency allows to 235minimize additional memory requirements. 236 237### Power Efficiency 238 239#### Be opportunistic when possible 240 241Examples include: 242 243* If the host is asleep and doesn’t need to act on a nanoapp message 244 immediately, buffer until it wakes up for another reason. 245* Make a WiFi on-demand scan request only if the WiFi scan monitor doesn’t 246 provide a scan result in time. 247 248#### Batch data at the source where possible 249 250By batching data at the source, it reduces the data delivery frequency and helps 251keep CHRE asleep and improve power efficiency. Clients should make data requests 252with the longest batch interval that still meets the latency requirement. 253Examples include: 254 255* Make a sensor data request with the longest ``latency`` possible. 256* Make an audio data request with the longest ``deliveryInterval`` possible. 257 258### Standard Library Usage 259 260CHRE implementations are only required to support a subset of the standard C and 261C++ libraries, as well as language features requiring run-time support. This 262list is carefully considered to ensure memory usage and implementation 263complexity are minimized. Following these principles, some features are 264explicitly excluded due to their memory and/or extensive OS-level dependencies, 265and others because they are supplanted by more suitable CHRE-specific APIs. 266While not meant to be an exhaustive list and some platforms may differ, the 267following standard library features are not meant to be used by nanoapps: 268 269* C++ exceptions and run-time type information (RTTI) 270* Standard library multi-threading support, including C++11 headers `<thread>`, 271 `<mutex>`, `<atomic>`, `<future>`, etc. 272* C and C++ Standard Input/Output libraries 273* C++ Standard Template Library (STL) 274* C++ Standard Regular Expressions library 275* Dynamic memory allocation (`malloc`, `calloc`, `realloc`, `free`), and 276 libraries that inherently use dynamic allocation, such as `std::unique_ptr` 277* Localization and Unicode character support 278* Date and time libraries 279* Functions that modify normal program flow, including `<setjmp.h>`, 280 `<signal.h>`, `abort`, `std::terminate`, etc. 281* Accessing the host environment, including `system`, `getenv`, etc. 282* POSIX or other libraries not included in the C99 or C++11 language standards 283 284In many cases, equivalent functionality is available from CHRE API functions 285and/or utility libraries. For example, `chreLog` may be used for debug logging, 286where a more traditional program might use `printf`. 287 288## Debugging 289 290Similar to the framework debugging methods, each has its nanoapp counterpart to 291support nanoapp debugging through the framework. Please see the Framework 292Debugging section for reference/context. 293 294### Logging 295 296CHRE API `chreLog()` logs information into the system as part of the CHRE logs. 297Normally this appears in logcat, but some platforms may route it to a different 298logging system (a future version of the CHRE API is expected to make logcat 299logging mandatory). 300 301Nanoapps are encouraged to `#include "chre/util/nanoapp/log.h"` and use the 302`LOGx()` macros defined therein, which requires these additional steps: 303 304* Define `LOG_TAG` to a short, human-readable identifier for your nanoapp, as 305 this gets prepended to logs 306* Define `NANOAPP_MINIMUM_LOG_LEVEL` to a `CHRE_LOG_LEVEL_\*` value in your 307 Makefile for compile time log level filtering - it’s recommended to use 308 `CHRE_LOG_LEVEL_DEBUG` for development, and `CHRE_LOG_LEVEL_INFO` for release 309 310See also the Framework Debugging section for more general guidance on logging in 311CHRE. 312 313### Debug Dump 314 315When running on CHRE v1.4+, nanoapps can also append information to the CHRE 316framework debug dump. Nanoapps interested in using this capability should call 317`chreConfigureDebugDumpEvent(true)` in `nanoappStart()`, then when 318`CHRE_EVENT_DEBUG_DUMP` is received in `nanoappHandleEvent()`, use 319`chreDebugDumpLog()` to write human-readable output to the debug dump, which 320appears in bug reports under the Context Hub HAL debug section. In the reference 321CHRE framework implementation, nanoapp debug dumps have the nanoapp name and ID 322automatically prepended, for example: 323 324``` 325Nanoapp debug dumps: 326 327 DebugDumpWorld 0x0123456789000011: 328 Debug event count: 2 329 Total dwell time: 92 us 330``` 331 332Refer to the associated CHRE API documentation and Framework Debugging section 333for more information. 334 335### CHRE_ASSERT 336 337To help catch programming errors or other unexpected conditions, nanoapps can 338use the `CHRE_ASSERT` macro provided by `#include "chre/util/nanoapp/assert.h"`. 339Keep in mind that if one nanoapp encounters an assertion failure, it most likely 340will cause a reset of the processor where CHRE is running, impacting other 341functionality (though this can vary by platform). Therefore, assertions are only 342recommended to be used during development. Define the `CHRE_ASSERTIONS_ENABLED` 343variable in your Makefile to `false` to disable assertions at compile time. 344