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 theParceland calls your implementation.Bp<InterfaceName>(Binder Proxy): The proxy class used by the client. It packs arguments into aParceland callsremote()->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);