Android Development
Android already has a complete Binder IPC environment, so rsbinder and rsbinder-aidl use the existing device nodes and service manager directly. Nothing here needs rsb_device or rsb_hub, which exist for Linux.
For building in the Android environment, you need to install the Android NDK and set up a Rust build environment that utilizes the NDK.
See: Android Build Environment Setup
Android Version Compatibility
rsbinder supports multiple Android versions with explicit feature flags for compatibility management. The Binder IPC interface has evolved across Android versions, and rsbinder handles these differences transparently.
Supported Android Versions
- Android 10 (API 29):
android_10feature - Android 11 (API 30):
android_11feature - Android 12 (API 31) / 12L (API 32):
android_12feature - Android 13 (API 33):
android_13feature - Android 14 (API 34):
android_14feature - Android 15 (API 35):
android_14andandroid_15— see below - Android 16 (API 36):
android_16feature - Android 17 (API 37): served by the
android_16feature
Note: Android 12L (API 32) uses the same Binder protocol as Android 12, so both are covered by the
android_12feature flag, and Android 17 (API 37) uses the same protocol as Android 16, soandroid_16orandroid_16_pluscovers it. No separateandroid_12lorandroid_17feature is needed.
Android 15 has two service-manager protocols:
android-15.0.0_r6insertedgetService2at index 1 ofIServiceManagerand shifted every transaction code after it by one (addService2 → 3,registerClientCallback11 → 12,tryUnregisterService12 → 13). The SDK version stayed 35, so the build alone does not say which numbering a device speaks. The initial release (r1–r5) is served byandroid_14;r6and later, QPR builds included, byandroid_15. Enable both —android_14_plusand everything wider does — and rsbinder probes the running service manager once at startup to pick the right one. With only one of the two enabled, a device that speaks the other is refused with an error naming the missing feature, rather than addressed with the wrong transaction codes.
Android 10 caveat: Android 10 uses the legacy C
IServiceManager(the AIDL-based interface only landed in Android 11). Theandroid_10dispatch supportstry_get_service,check_service,add_service, andlist_services. APIs introduced later —is_declared,register_for_notifications,unregister_for_notifications, andget_service_debug_info— returnfalseorStatusCode::UnknownTransactionso callers can detect the gap rather than silently misbehave.
Feature Flag Configuration
In your Cargo.toml, specify the Android versions you want to support:
[dependencies]
rsbinder = { version = "0.12", features = ["android_14_plus"] }
Available feature combinations:
android_10_plus: Supports Android 10 through 17android_11_plus: Supports Android 11 through 17android_12_plus: Supports Android 12 through 17android_13_plus: Supports Android 13 through 17android_14_plus: Supports Android 14 through 17android_15_plus: Supports Android 15 (r6and later only) through 17android_16_plus: Supports Android 16 and 17
Protocol Compatibility
rsbinder maintains binary compatibility with Android's Binder protocol:
- Transaction Format: Uses identical
binder_transaction_datastructures - Object Types: Supports all Android Binder object types (BINDER, HANDLE, FD)
- Command Protocols: Implements the same ioctl commands (BC_/BR_ protocol)
- Memory Management: Compatible parcel serialization and shared memory handling
- AIDL Compatibility: Generates code compatible with Android's AIDL interfaces
Because the wire format is identical, the language a service is implemented
in is invisible to its callers: a client generated by rsbinder-aidl can call
an existing Android service written in C++ or Java exactly as it would call an
rsbinder one — no JNI or C shim required. Vendor the service's .aidl from
AOSP, build it with rsbinder-aidl, and look the service up with
hub::try_get_interface::<dyn IFoo>("service.name"). rsbinder relies on this itself:
its hub module drives Android's own C++ servicemanager exactly this way. The
same generated stubs also drive the RPC transport, which is
wire-compatible with real libbinder RPC peers in both directions — though AOSP
exposes only a few services that way (VM / accessor-mediated) rather than over
kernel binder.
Version Detection (Optional)
rsbinder uses rsproperties internally to read Android system properties. You can use the same crate for version detection:
#![allow(unused)] fn main() { // Read Android SDK version (returns default value if not available) let sdk_version: u32 = rsproperties::get_or("ro.build.version.sdk", 0); println!("Android SDK version: {}", sdk_version); // Read release version string let version: String = rsproperties::get_or("ro.build.version.release", String::new()); println!("Running on Android {}", version); }
Add rsproperties to your dependencies:
[dependencies]
rsproperties = "0.6"
Using Android's Existing Binder Devices
On Android, the binder device files are already created and managed by the system. Use ProcessState::init() to connect to the appropriate device:
#![allow(unused)] fn main() { // Connect to the default system binder (/dev/binder) ProcessState::init("/dev/binder", rsbinder::DEFAULT_MAX_BINDER_THREADS)?; }
The second argument is the binder thread-pool ceiling, passed to the kernel
as written. DEFAULT_MAX_BINDER_THREADS (15) is what init_default() uses;
pass 0 only when the process must never have the kernel spawn a binder
thread for it — a single-threaded service manager, or a client that only
makes synchronous outbound calls.
Android provides several binder devices for different purposes:
| Device | Service Manager | Description |
|---|---|---|
/dev/binder | servicemanager | Framework services (default) |
/dev/hwbinder | hwservicemanager | HAL services (HIDL) |
/dev/vndbinder | vndservicemanager | Vendor services |
Warning:
hwbinderuses a different protocol (libhwbinder) than standard binder (libbinder). rsbinder has not been tested withhwbinder, so compatibility is not guaranteed.
You do not need to run rsb_hub on Android — the system already provides service managers for each binder device.
Android-Specific Considerations
- SELinux applies as it does to any other process: a denial surfaces as a
failed
openof the device or a refused transaction, not as an rsbinder error. - Shared memory is allocated with
memfd_create; a peer's legacy/dev/ashmemfd is accepted on the way in. See Shared Memory. @VintfStabilityis honored, including the stability check aParcelableHoldercarries on the wire.
JNI Integration
rsbinder is designed for pure Rust-based programs. Integrating Rust Binder services with Java through JNI is not recommended and was not considered in the design. Since JNI only provides a C interface, multiple data conversions occur (Java → C → Rust), which is inefficient. Instead, develop independent Binder services in Rust and communicate with them from Java clients through the standard Binder IPC mechanism.