AOSP Framework & Internals
2 min read

Native AIDL (C++)

Learn about Native AIDL (C++).

Introduction

While AIDL is deeply integrated into Java for the Android Application Framework, the core system services (such as SurfaceFlinger, AudioFlinger, and CameraService) are written in C++. AIDL can also generate C++ bindings, allowing Java apps to communicate seamlessly with native daemons, and native daemons to talk to each other over Binder.

Generating C++ Stubs from AIDL

The aidl compiler supports generating native code. In modern Android development, the cc_library or aidl_interface build rules handle this automatically. When an AIDL file is compiled for C++, it generates headers and implementation files that define the interface, along with proxy and stub classes.

// Android.bp
cc_binary {
    name: "my_native_service",
    srcs: [
        "IMyNativeService.aidl",
        "MyNativeService.cpp",
        "main.cpp",
    ],
    shared_libs: [
        "libbinder",
        "libutils",
    ],
}

BnXxx (Native Stub) and BpXxx (Native Proxy)

The generated C++ code follows a specific naming convention:

  • I<InterfaceName>: The abstract base class representing the interface.
  • Bn<InterfaceName> (Binder Native): The stub class that your service implements. It unpacks the Parcel and calls your implementation.
  • Bp<InterfaceName> (Binder Proxy): The proxy class used by the client. It packs arguments into a Parcel and calls remote()->transact().
// Implementing the native stub
#include <IMyNativeService.h>

class MyNativeService : public android::BnMyNativeService {
public:
    android::binder::Status doSomething(int32_t val) override {
        ALOGI("Received %d", val);
        return android::binder::Status::ok();
    }
};

Using AIDL in Native Services

To expose a native service to the system, you instantiate your Bn implementation and register it with ServiceManager.

// main.cpp
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "MyNativeService.h"

int main(int argc, char** argv) {
    // Initialize the binder driver for this process
    android::sp<android::ProcessState> ps = android::ProcessState::self();
    ps->startThreadPool();

    // Register the service
    android::sp<MyNativeService> service = new MyNativeService();
    android::defaultServiceManager()->addService(android::String16("my_native_service"), service);

    // Join the thread pool to handle incoming requests
    android::IPCThreadState::self()->joinThreadPool();
    return 0;
}

On the native client side, IServiceManager::getService is used to retrieve an sp<IBinder>, which is then cast to the interface using interface_cast.

android::sp<android::IBinder> binder = android::defaultServiceManager()->getService(android::String16("my_native_service"));
android::sp<IMyNativeService> proxy = android::interface_cast<IMyNativeService>(binder);
proxy->doSomething(42);