# Generating C++ Binder Interfaces with `aidl-cpp` ## Background “aidl” refers to several related but distinct concepts: - the AIDL interface [definition language](http://developer.android.com/guide/components/aidl.html) - .aidl files (which contain AIDL) - the aidl generator which transforms AIDL into client/server IPC interfaces The _aidl generator_ is a command line tool that generates client and server stubs for Binder interfaces from a specification in a file with the .aidl extension. For Java interfaces, the executable is called `aidl` while for C++ the binary is called `aidl-cpp`. In this document, we’ll use AIDL to describe the language of .aidl files and _aidl generator_ to refer to the code generation tool that takes an .aidl file, parses the AIDL, and outputs code. Previously, the _aidl generator_ only generated Java interface/stub/proxy objects. C++ Binder interfaces were handcrafted with various degrees of compatibility with the Java equivalents. The Brillo project added support for generating C++ with the _aidl generator_. This generated C++ is cross-language compatible (e.g. Java clients are tested to interoperate with native services). ## Overview This document describes how C++ generation works with attention to: - build interface - cross-language type mapping - C++ parcelables - cross-language error reporting - cross-language null reference handling - cross-language integer constants ## Detailed Design ### Build Interface Write AIDL in .aidl files and add them to `LOCAL_SRC_FILES` in your Android.mk. If your build target is a binary (e.g. you include `$(BUILD_SHARED_LIBRARY)`), then the generated code will be C++, not Java. AIDL definitions should be hosted from the same repository as the implementation. Any system that needs the definition will also need the implementation (for both parcelables and interface). If there are multiple implementations (i.e. one in Java and one in C++), keep the definition with the native implementation. Android [now has systems](https://developers.google.com/brillo/?hl=en) that run the native components of the system without the Java. If you use an import statement in your AIDL, even from the same package, you need to add a path to `LOCAL_AIDL_INCLUDES`. This path should be relative to the root of the Android tree. For instance, a file IFoo.aidl defining com.example.IFoo might sit in a folder hierarchy something/something-else/com/example/IFoo.aidl. Then we would write: ``` LOCAL_AIDL_INCLUDES := something/something-else ``` Generated C++ ends up in nested namespaces corresponding to the interface’s package. The generated header also corresponds to the interface package. So com.example.IFoo becomes ::com::example::IFoo in header “com/example/IFoo.h”. Similar to how Java works, the suffix of the path to a .aidl file must match the package. So if IFoo.aidl declares itself to be in package com.example, the folder structure (as given to `LOCAL_SRC_FILES`) must look like: `some/prefix/com/example/IFoo.aidl`. To generate code from .aidl files from another build target (e.g. another binary or java), just add a relative path to the .aidl files to `LOCAL_SRC_FILES`. Remember that importing AIDL works the same, even for code in other directory hierarchies: add the include root path relative to the checkout root to `LOCAL_AIDL_INCLUDES`. ### Type Mapping The following table summarizes the equivalent C++ types for common Java types and whether those types may be used as in/out/inout parameters in AIDL interfaces. | Java Type | C++ Type | inout | Notes | |-----------------------|---------------------|-------|-------------------------------------------------------| | boolean | bool | in | "These 8 types are all considered primitives. | | byte | int8\_t | in | | | char | char16\_t | in | | | int | int32\_t | in | | | long | int64\_t | in | | | float | float | in | | | double | double | in | | | String | String16 | in | Supports null references. | | android.os.Parcelable | android::Parcelable | inout | | | T extends IBinder | sp | in | | | Arrays (T[]) | vector | inout | May contain only primitives, Strings and parcelables. | | List | vector | inout | | | PersistableBundle | PersistableBundle | inout | binder/PersistableBundle.h | | List | vector> | inout | | | FileDescriptor | ScopedFd | inout | nativehelper/ScopedFd.h | Note that java.util.Map and java.utils.List are not good candidates for cross language communication because they may contain arbitrary types on the Java side. For instance, Map is cast to Map and then the object values dynamically inspected and serialized as type/value pairs. Support exists for sending arbitrary Java serializables, Android Bundles, etc. ### C++ Parcelables In Java, a parcelable should extend android.os.Parcelable and provide a static final CREATOR field that acts as a factory for new instances/arrays of instances of the parcelable. In addition, in order to be used as an out parameter, a parcelable class must define a readFromParcel method. In C++, parcelables must implement android::Parcelable from binder/Parcelable.h in libbinder. Parcelables must define a constructor that takes no arguments. In order to be used in arrays, a parcelable must implement a copy or move constructor (called implicitly in vector). The C++ generator needs to know what header defines the C++ parcelable. It learns this from the `cpp_header` directive shown below. The generator takes this string and uses it as the literal include statement in generated code. The idea here is that you generate your code once, link it into a library along with parcelable implementations, and export appropriate header paths. This header include must make sense in the context of the Android.mk that compiles this generated code. ``` // ExampleParcelable.aidl package com.example.android; // Native types must be aliased at their declaration in the appropriate .aidl // file. This allows multiple interfaces to use a parcelable and its C++ // equivalent without duplicating the mapping between the C++ and Java types. // Generator will assume bar/foo.h declares class // com::example::android::ExampleParcelable parcelable ExampleParcelable cpp_header "bar/foo.h"; ``` ### Null Reference Handling The aidl generator for both C++ and Java languages has been expanded to understand nullable annotations. Given an interface definition like: ``` interface IExample { void ReadStrings(String neverNull, in @nullable String maybeNull); }; ``` the generated C++ header code looks like: ``` class IExample { android::binder::Status ReadStrings( const android::String16& in_neverNull, const std::unique_ptr& in_maybeNull); }; ``` Note that by default, the generated C++ passes a const reference to the value of a parameter and rejects null references with a NullPointerException sent back the caller. Parameters marked with @nullable are passed by pointer, allowing native services to explicitly control whether they allow method overloading via null parameters. Java stubs and proxies currently do nothing with the @nullable annotation. ### Exception Reporting C++ methods generated by the aidl generator return `android::binder::Status` objects, rather than `android::status_t`. This Status object allows generated C++ code to send and receive exceptions (an exception type and a String16 error message) since we do not use real exceptions in C++. More background on Status objects can be found here. For legacy support and migration ease, the Status object includes a mechanism to report a `android::status_t`. However, that return code is interpreted by a different code path and does not include a helpful String message. For situations where your native service needs to throw an error code specific to the service, use `Status::fromServiceSpecificError()`. This kind of exception comes with a helpful message and an integer error code. Make your error codes consistent across services by using interface constants (see below). ### Integer Constants AIDL has been enhanced to support defining integer constants as part of an interface: ``` interface IMyInterface { const int CONST_A = 1; const int CONST_B = 2; const int CONST_C = 3; ... } ``` These map to appropriate 32 bit integer class constants in Java and C++ (e.g. `IMyInterface.CONST_A` and `IMyInterface::CONST_A` respectively).