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_10 feature
  • Android 11 (API 30): android_11 feature
  • Android 12 (API 31) / 12L (API 32): android_12 feature
  • Android 13 (API 33): android_13 feature
  • Android 14 (API 34): android_14 feature
  • Android 15 (API 35): android_14 and android_15 — see below
  • Android 16 (API 36): android_16 feature
  • Android 17 (API 37): served by the android_16 feature

Note: Android 12L (API 32) uses the same Binder protocol as Android 12, so both are covered by the android_12 feature flag, and Android 17 (API 37) uses the same protocol as Android 16, so android_16 or android_16_plus covers it. No separate android_12l or android_17 feature is needed.

Android 15 has two service-manager protocols: android-15.0.0_r6 inserted getService2 at index 1 of IServiceManager and shifted every transaction code after it by one (addService 2 → 3, registerClientCallback 11 → 12, tryUnregisterService 12 → 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 by android_14; r6 and later, QPR builds included, by android_15. Enable both — android_14_plus and 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). The android_10 dispatch supports try_get_service, check_service, add_service, and list_services. APIs introduced later — is_declared, register_for_notifications, unregister_for_notifications, and get_service_debug_info — return false or StatusCode::UnknownTransaction so 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 17
  • android_11_plus: Supports Android 11 through 17
  • android_12_plus: Supports Android 12 through 17
  • android_13_plus: Supports Android 13 through 17
  • android_14_plus: Supports Android 14 through 17
  • android_15_plus: Supports Android 15 (r6 and later only) through 17
  • android_16_plus: Supports Android 16 and 17

Protocol Compatibility

rsbinder maintains binary compatibility with Android's Binder protocol:

  • Transaction Format: Uses identical binder_transaction_data structures
  • 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:

DeviceService ManagerDescription
/dev/binderservicemanagerFramework services (default)
/dev/hwbinderhwservicemanagerHAL services (HIDL)
/dev/vndbindervndservicemanagerVendor services

Warning: hwbinder uses a different protocol (libhwbinder) than standard binder (libbinder). rsbinder has not been tested with hwbinder, 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 open of the device or a refused transaction, not as an rsbinder error.
  • Shared memory is allocated with memfd_create; a peer's legacy /dev/ashmem fd is accepted on the way in. See Shared Memory.
  • @VintfStability is honored, including the stability check a ParcelableHolder carries 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.