• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Generating C++ Binder Interfaces with `aidl-cpp`
2
3## Background
4
5“aidl” refers to several related but distinct concepts:
6
7 - the AIDL interface [definition language](http://developer.android.com/guide/components/aidl.html)
8 - .aidl files (which contain AIDL)
9 - the aidl generator which transforms AIDL into client/server IPC interfaces
10
11The _aidl generator_ is a command line tool that generates client and server
12stubs for Binder interfaces from a specification in a file with the .aidl
13extension.  For Java interfaces, the executable is called `aidl` while for C++
14the binary is called `aidl-cpp`.  In this document, we’ll use AIDL to describe
15the language of .aidl files and _aidl generator_ to refer to the code generation
16tool that takes an .aidl file, parses the AIDL, and outputs code.
17
18Previously, the _aidl generator_ only generated Java interface/stub/proxy
19objects.  C++ Binder interfaces were handcrafted with various degrees of
20compatibility with the Java equivalents.  The Brillo project added support for
21generating C++ with the _aidl generator_.  This generated C++ is cross-language
22compatible (e.g. Java clients are tested to interoperate with native services).
23
24## Overview
25
26This document describes how C++ generation works with attention to:
27
28 - build interface
29 - cross-language type mapping
30 - implementing a generated interface
31 - C++ parcelables
32 - cross-language error reporting
33 - cross-language null reference handling
34
35## Detailed Design
36
37### Build Interface
38
39Write AIDL in .aidl files and add them to `LOCAL_SRC_FILES` in your Android.mk.
40If your build target is a binary (e.g. you include `$(BUILD_SHARED_LIBRARY)`),
41then the generated code will be C++, not Java.
42
43AIDL definitions should be hosted from the same repository as the
44implementation.  Any system that needs the definition will also need the
45implementation (for both parcelables and interface).  If there are multiple
46implementations (i.e. one in Java and one in C++), keep the definition with the
47native implementation.  Android
48[now has systems](https://developers.google.com/brillo/?hl=en) that run the
49native components of the system without the Java.
50
51If you use an import statement in your AIDL, even from the same package, you
52need to add a path to `LOCAL_AIDL_INCLUDES`.  This path should be relative to
53the root of the Android tree.  For instance, a file IFoo.aidl defining
54com.example.IFoo might sit in a folder hierarchy
55something/something-else/com/example/IFoo.aidl.  Then we would write:
56
57```
58LOCAL_AIDL_INCLUDES := something/something-else
59```
60
61Generated C++ ends up in nested namespaces corresponding to the interface’s
62package.  The generated header also corresponds to the interface package.  So
63com.example.IFoo becomes ::com::example::IFoo in header “com/example/IFoo.h”.
64
65Similar to how Java works, the suffix of the path to a .aidl file must match
66the package.  So if IFoo.aidl declares itself to be in package com.example, the
67folder structure (as given to `LOCAL_SRC_FILES`) must look like:
68`some/prefix/com/example/IFoo.aidl`.
69
70To generate code from .aidl files from another build target (e.g. another
71binary or java), just add a relative path to the .aidl files to
72`LOCAL_SRC_FILES`.  Remember that importing AIDL works the same, even for code
73in other directory hierarchies: add the include root path relative to the
74checkout root to `LOCAL_AIDL_INCLUDES`.
75
76### Type Mapping
77
78The following table summarizes the equivalent C++ types for common Java types
79and whether those types may be used as in/out/inout parameters in AIDL
80interfaces.
81
82| Java Type             | C++ Type            | inout | Notes                                                 |
83|-----------------------|---------------------|-------|-------------------------------------------------------|
84| boolean               | bool                | in    | "These 8 types are all considered primitives.         |
85| byte                  | int8\_t             | in    |                                                       |
86| char                  | char16\_t           | in    |                                                       |
87| int                   | int32\_t            | in    |                                                       |
88| long                  | int64\_t            | in    |                                                       |
89| float                 | float               | in    |                                                       |
90| double                | double              | in    |                                                       |
91| String                | String16            | in    | Supports null references.                             |
92| @utf8InCpp String     | std::string         | in    | @utf8InCpp causes UTF16 to UTF8 conversion in C++.    |
93| android.os.Parcelable | android::Parcelable | inout |                                                       |
94| java.util.Map         | android::binder::Map| inout | `std::map<std::string,android::binder::Value>`        |
95| T extends IBinder     | sp<T>               | in    |                                                       |
96| Arrays (T[])          | vector<T>           | inout | May contain only primitives, Strings and parcelables. |
97| List<String>          | vector<String16>    | inout |                                                       |
98| PersistableBundle     | PersistableBundle   | inout | binder/PersistableBundle.h                            |
99| List<IBinder>         | vector<sp<IBinder>> | inout |                                                       |
100| FileDescriptor        | unique_fd           | inout | android-base/unique_fd.h from libbase                 |
101
102Note that annotations may be placed at the interface level, as well as on a
103type by type basis.  Interface level annotations will be applied
104opportunistically and be overridden by per type annotations.  For instance, an
105interface marked @nullable will still not allow null int parameters.
106
107### Implementing a generated interface
108
109Given an interface declaration like:
110
111```
112package foo;
113
114import bar.IAnotherInterface;
115
116interface IFoo {
117  IAnotherInterface DoSomething(int count, out List<String> output);
118}
119```
120
121`aidl-cpp` will generate a C++ interface:
122
123```
124namespace foo {
125
126// Some headers have been omitted for clarity.
127#include <android/String16.h>
128#include <cstdint>
129#include <vector>
130#include <bar/IAnotherInterface.h>
131
132// Some class members have been omitted for clarity.
133class IFoo : public android::IInterface {
134 public:
135  virtual android::binder::Status DoSomething(
136      int32_t count,
137      std::vector<android::String16>* output,
138      android::sp<bar::IAnotherInterface>* returned_value) = 0;
139};
140```
141
142Note that `aidl-cpp` will import headers for types used in the interface.  For
143imported types (e.g. parcelables and interfaces), it will import a header
144corresponding to the package/class name of the import.  For instance,
145`import bar.IAnotherInterface` causes aidl-cpp to generate
146`#include <bar/IAnotherInterface.h>`.
147
148When writing a service that implements this interface, write:
149
150```
151#include "foo/BnFoo.h"
152
153namespace unrelated_namespace {
154
155class MyFoo : public foo::BnFoo {
156 public:
157  android::binder::Status DoSomething(
158      int32_t count,
159      std::vector<android::String16>* output,
160      android::sp<bar::IAnotherInterface>* returned_value) override {
161    for (int32_t i = 0; i < count; ++i) {
162      output->push_back(String16("..."));
163    }
164    *returned_value = new InstanceOfAnotherInterface;
165    return Status::ok();
166  }
167};  // class MyFoo
168
169}  // namespace unrelated_namespace
170```
171
172Note that the output values, `output` and `returned_value` are passed by
173pointer, and that this pointer is always valid.
174
175#### Dependencies
176
177The generated C++ code will use symbols from libbinder as well as libutils.
178AIDL files using the FileDescriptor type will also explicitly require
179libnativehelper, although this is likely a transitive dependency of the other
180two, and should be included automatically within the Android build tree
181regardless.
182
183### C++ Parcelables
184
185In Java, a parcelable should extend android.os.Parcelable and provide a static
186final CREATOR field that acts as a factory for new instances/arrays of
187instances of the parcelable.  In addition, in order to be used as an out
188parameter, a parcelable class must define a readFromParcel method.
189
190In C++, parcelables must implement android::Parcelable from binder/Parcelable.h
191in libbinder.  Parcelables must define a constructor that takes no arguments.
192In order to be used in arrays, a parcelable must implement a copy or move
193constructor (called implicitly in vector).
194
195The C++ generator needs to know what header defines the C++ parcelable.  It
196learns this from the `cpp_header` directive shown below.  The generator takes
197this string and uses it as the literal include statement in generated code.
198The idea here is that you generate your code once, link it into a library along
199with parcelable implementations, and export appropriate header paths.  This
200header include must make sense in the context of the Android.mk that compiles
201this generated code.
202
203```
204// ExampleParcelable.aidl
205package com.example.android;
206
207// Native types must be aliased at their declaration in the appropriate .aidl
208// file.  This allows multiple interfaces to use a parcelable and its C++
209// equivalent without duplicating the mapping between the C++ and Java types.
210// Generator will assume bar/foo.h declares class
211// com::example::android::ExampleParcelable
212parcelable ExampleParcelable cpp_header "bar/foo.h";
213```
214
215### Null Reference Handling
216
217The aidl generator for both C++ and Java languages has been expanded to
218understand nullable annotations.
219
220Given an interface definition like:
221
222```
223interface IExample {
224  void ReadStrings(String neverNull, in @nullable String maybeNull);
225};
226```
227
228the generated C++ header code looks like:
229
230```
231class IExample {
232  android::binder::Status ReadStrings(
233      const android::String16& in_neverNull,
234      const std::unique_ptr<android::String16>& in_maybeNull);
235};
236```
237
238Note that by default, the generated C++ passes a const reference to the value
239of a parameter and rejects null references with a NullPointerException sent
240back the caller.  Parameters marked with @nullable are passed by pointer,
241allowing native services to explicitly control whether they allow method
242overloading via null parameters.  Java stubs and proxies currently do nothing
243with the @nullable annotation.
244
245Consider an AIDL type `in @nullable List<String> bar`.  This type
246indicates that the remote caller may pass in a list of strings, and that both
247the list and any string in the list may be null.  This type will map to a C++
248type `unique_ptr<vector<unique_ptr<String16>>>* bar`.  In this case:
249
250  - `bar` is never null
251  - `*bar` might be null
252  - `(*bar)->empty()` could be true
253  - `(**bar)[0]` could be null (and so on)
254
255### Exception Reporting
256
257C++ methods generated by the aidl generator return `android::binder::Status`
258objects, rather than `android::status_t`.  This Status object allows generated
259C++ code to send and receive exceptions (an exception type and a String16 error
260message) since we do not use real exceptions in C++.  More background on Status
261objects can be found here.
262
263For legacy support and migration ease, the Status object includes a mechanism
264to report a `android::status_t`.  However, that return code is interpreted by a
265different code path and does not include a helpful String message.
266
267For situations where your native service needs to throw an error code specific
268to the service, use `Status::fromServiceSpecificError()`.  This kind of
269exception comes with a helpful message and an integer error code.  Make your
270error codes consistent across services by using interface constants (see
271below).
272