• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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