| name | android-binder-native |
| description | Use when implementing or reviewing native C++ Binder services in AOSP using libbinder directly (BnInterface/BpInterface, Parcel, onTransact). Covers the IInterface pattern with DECLARE/IMPLEMENT_META_INTERFACE macros, server-side BnFoo stub, client-side BpFoo proxy, Parcel serialization, ServiceManager registration, ProcessState thread pool setup, and IBinder death notifications. Applies to AOSP system services, platform components, and vendor native services.
|
| argument-hint | <service-name> [write|review|debug] |
Android Native Binder Service (libbinder C++)
Practices for writing correct native C++ Binder services in AOSP using
libbinder directly. This covers IVI, HUD, and RSE platform components on
Android Automotive OS (AAOS).
Source of truth:
When to Use This Skill vs. AIDL
| Approach | When to Use |
|---|
| Native libbinder (this skill) | Maintaining existing AOSP system services; platform components that need direct Parcel control; learning how Binder works |
AIDL cpp backend (see android-aidl) | New AOSP system services — generates BnFoo/BpFoo automatically |
AIDL NDK backend (see android-hal) | Vendor HAL services, NDK-accessible services |
In modern AOSP development the AIDL compiler generates the BnFoo/BpFoo boilerplate from a .aidl file. Understanding the manual pattern is necessary for reading existing code and for cases where AIDL tooling is not used.
Note: libbinder is a platform system library. It is not available to third-party apps via the NDK. Use this pattern only in AOSP platform code (system partition, vendor partition binaries built with Soong).
Required Headers
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
Step 1 — Define the Interface (IFoo.h)
#pragma once
#include <binder/IInterface.h>
#include <utils/String16.h>
namespace android {
class IFoo : public IInterface {
public:
DECLARE_META_INTERFACE(Foo);
enum {
GET_VALUE = IBinder::FIRST_CALL_TRANSACTION,
SET_VALUE,
GET_NAME,
};
virtual int32_t getValue() = 0;
virtual status_t setValue(int32_t value) = 0;
virtual String16 getName() = 0;
};
class BnFoo : public BnInterface<IFoo> {
public:
status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0) override;
};
}
Step 2 — Define the Proxy (BpFoo) and Implement the Interface (IFoo.cpp)
#include "IFoo.h"
#include <binder/Parcel.h>
namespace android {
IMPLEMENT_META_INTERFACE(Foo, "com.example.IFoo");
class BpFoo : public BpInterface<IFoo> {
public:
explicit BpFoo(const sp<IBinder>& impl) : BpInterface<IFoo>(impl) {}
int32_t getValue() override {
Parcel data, reply;
data.writeInterfaceToken(IFoo::getInterfaceDescriptor());
remote()->transact(GET_VALUE, data, &reply);
return reply.readInt32();
}
status_t setValue(int32_t value) override {
Parcel data, reply;
data.writeInterfaceToken(IFoo::getInterfaceDescriptor());
data.writeInt32(value);
status_t status = remote()->transact(SET_VALUE, data, &reply);
return status;
}
String16 getName() override {
Parcel data, reply;
data.writeInterfaceToken(IFoo::getInterfaceDescriptor());
remote()->transact(GET_NAME, data, &reply);
String16 name;
reply.readString16(&name);
return name;
}
};
status_t BnFoo::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
CHECK_INTERFACE(IFoo, data, reply);
switch (code) {
case GET_VALUE:
reply->writeInt32(getValue());
return OK;
case SET_VALUE: {
int32_t value = data.readInt32();
return setValue(value);
}
case GET_NAME:
reply->writeString16(getName());
return OK;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}
Key rules:
writeInterfaceToken in the proxy and CHECK_INTERFACE in onTransact form a security check — they verify callers are not accidentally sending the wrong interface's Parcel.
- Always delegate unknown
code values to BBinder::onTransact() (base class handles INTERFACE_TRANSACTION and DUMP_TRANSACTION).
onTransact runs on a Binder thread pool thread — protect shared state with locks.
Step 3 — Implement the Service
#pragma once
#include "IFoo.h"
namespace android {
class FooService : public BnFoo {
public:
FooService() : value_(0) {}
int32_t getValue() override;
status_t setValue(int32_t value) override;
String16 getName() override;
private:
mutable Mutex mutex_;
int32_t value_;
};
}
#include "FooService.h"
namespace android {
int32_t FooService::getValue() {
AutoMutex lock(mutex_);
return value_;
}
status_t FooService::setValue(int32_t value) {
AutoMutex lock(mutex_);
value_ = value;
return OK;
}
String16 FooService::getName() {
return String16("FooService");
}
}
Step 4 — Register the Service (Server main)
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "FooService.h"
using namespace android;
int main(int , char* []) {
sp<ProcessState> proc = ProcessState::self();
proc->setThreadPoolMaxThreadCount(4);
sp<IServiceManager> sm = defaultServiceManager();
sm->addService(String16("com.example.foo"), new FooService());
proc->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
Step 5 — Connect from a Client
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "IFoo.h"
using namespace android;
int main() {
sp<IBinder> binder = defaultServiceManager()->getService(String16("com.example.foo"));
if (binder == nullptr) {
ALOGE("Service not found");
return 1;
}
sp<IFoo> foo = interface_cast<IFoo>(binder);
foo->setValue(42);
int32_t val = foo->getValue();
ALOGI("getValue = %d", val);
return 0;
}
For a non-blocking lookup:
sp<IBinder> binder = defaultServiceManager()->checkService(String16("com.example.foo"));
Parcel — Common Read/Write Methods
| Operation | Write (proxy) | Read (stub) |
|---|
bool | data.writeBool(b) | data.readBool(&b) |
int32_t | data.writeInt32(n) | data.readInt32(&n) or data.readInt32() |
int64_t | data.writeInt64(n) | data.readInt64(&n) |
float | data.writeFloat(f) | data.readFloat(&f) |
String16 | data.writeString16(s) | data.readString16(&s) |
sp<IBinder> | data.writeStrongBinder(b) | data.readStrongBinder() |
| byte array | data.write(buf, len) | data.read(buf, len) |
Order matters: the proxy and the stub must read/write in the exact same order.
Service Death Notification
class FooDeathRecipient : public IBinder::DeathRecipient {
public:
void binderDied(const wp<IBinder>& ) override {
ALOGW("FooService died — reconnecting");
}
};
sp<FooDeathRecipient> deathRecipient = new FooDeathRecipient();
binder->linkToDeath(deathRecipient);
binder->unlinkToDeath(deathRecipient);
AOSP Build (Android.bp)
cc_binary {
name: "com.example.foo-service",
srcs: [
"service_main.cpp",
"FooService.cpp",
"IFoo.cpp",
],
shared_libs: [
"libbinder",
"libutils",
"liblog",
],
// For a system service (system partition):
// system_ext_specific: true,
// For a vendor service:
// vendor: true,
}
cc_binary {
name: "com.example.foo-client",
srcs: ["client_example.cpp", "IFoo.cpp"],
shared_libs: ["libbinder", "libutils", "liblog"],
}
Prerequisites
- Android Studio (Flamingo or newer) or AOSP build environment set up.
- Android SDK Platform-Tools installed (
adb on PATH).
- Target device or emulator running Android 11+ (API 30+).
- For AOSP modules:
repo tool, AOSP source synced, lunch target configured.
Step-by-Step Workflows
The step-by-step implementation workflow is defined in the numbered Step sections below
(Step 1 through Step 5). Follow them in order: define the IFoo interface → implement
BpFoo proxy → implement BnFoo stub → register with ServiceManager → use from client.
Troubleshooting
ServiceManager::getService() returns null — the server hasn't registered yet; retry with backoff or use waitForService().
- Parcel
BAD_TYPE crash — read arguments from Parcel in exactly the same order they were written.
FAILED BINDER TRANSACTION — transaction data exceeds the 1 MB Binder buffer limit; chunk large data or use file descriptors.
DeadObjectException / DEAD_OBJECT status — service process crashed; use linkToDeath() to register a death handler.
Pre-Commit Checklist
References