Stability tiers
rsbinder uses a three-tier model for public-API stability on the path to 1.0. Each tier states what kind of change can land between releases and what callers can rely on.
| Tier | Versioning | Wire compatibility | When it can change |
|---|---|---|---|
| Stable | Semver-strict | AOSP-faithful, byte-tested against real libbinder | Only on a major bump — and pre-1.0 the 0.x minor slot is the major slot (see the changelog preamble). Breaking changes are last-resort. |
| Provisional | Stabilizing toward 1.0 | AOSP-faithful in the validated cases (hermetic + real-libbinder STAGE3) | May break in a minor bump if 1.0 review surfaces an issue. Will be re-classified as Stable or Experimental at 1.0. |
| Experimental | Opt-in via Cargo feature | No guarantee until the corresponding real-libbinder interop gate passes | Anytime, including the wire format. Default builds do not reach this code. |
Stable
Surface that has shipped through multiple releases against real Android binder and is not expected to break.
- Kernel binder core —
Parcel,IBinder,Interface,Strong<I>,Weak<I>,Status,StatusCode,ParcelFileDescriptor,ProcessState::{init, init_default, start_thread_pool, join_thread_pool},Binder::new,BinderFeatures. - Transaction code constants —
FIRST_CALL_TRANSACTION,LAST_CALL_TRANSACTION,PING_TRANSACTION,INTERFACE_TRANSACTION,DUMP_TRANSACTION,FLAG_ONEWAY,FLAG_CLEAR_BUF. - Service manager (Android binder) —
hub::add_service,hub::check_service. (hub::get_service/hub::get_interfacewere deprecated in 0.10.0 and removed in 0.11.0, in favor ofwait_for_*/check_interface/try_*— which are Provisional (below). See Service Manager.) - AIDL compiler entry points —
rsbinder_aidl::Builder::{new, source, output, version, generate}. - rsb_device binary CLI (binderfs setup);
--group/--modeand the0600default node are new in 0.11.0.
Provisional
Implemented and validated, but the public-API shape is still under review for 1.0. Expect at most a single round of renames or signature tweaks; wire formats are already locked.
- Service-manager lookups (new in 0.10.0) —
hub::wait_for_service,wait_for_interface,check_interface,try_get_service,try_get_interface,register_client_callback,try_unregister_service, and theimpl Into<SIBinder>form ofadd_service. Wire behavior matches AOSPwaitForService/checkService; only the Rust signatures are still settling. - RPC transport —
RpcServer,RpcSession,setup_unix_server,setup_unix_client*,from_preconnected_fd,set_root,get_root,set_android13plus,set_max_threads(N)(bothN == 1andN >= 2multi-connection),set_max_connections,set_supported_fd_modes(&[FileDescriptorTransportMode::Unix]). Validated against real android-13 / 14 / 15 / 16libbinder(plans 2-1 … 2-12 / 2-13 / 2-14 STAGE3). - FD-over-RPC (v1+ AOSP-faithful, AC-11.3 gate passed).
- RPC death notification (session-disconnect, AOSP-faithful).
- IAccessor client / server (plans 2-13 D.8 + 2-14 D.9 STAGE3
passed against real
libbinder). rsb_hub—addServicedescriptor auto-detect,getService2,checkService2,Service::Accessorrouting. Linux-native bringup. New in 0.11.0: per-name access control, service declarations, on-demand start,dump, supervisor integration, and thersb_serviceCLI — the configuration file format is settling with them.- macOS first-class support (plan 2-9 Phase A+B).
- Entry API (new in 0.11.0) —
serve,connect,connect_async,Client,Server,ServerGuard,ServeOptions,ClientOptions,Endpoint. Replaced thersbinder::servicefacade. The URI grammar and the two option structs are what may still change. - Interface macros (new in 0.11.0,
macrosfeature) —#[rsbinder::interface],#[derive(Parcelable)],#[derive(BinderEnum)]. Feature-gated but not Experimental: the emitted code is byte-for-byte the.aidlcode, so the wire is whatever.aidlalready guarantees. Only the Rust-facing spelling is provisional; 0.12.0 narrowed it to what.aidlrenders and added#[deprecated]. See Interface Macros. - Shared memory (new in 0.11.0) —
SharedMemory,MemoryHeapBase,MappedHeap,MemoryDealer,HeapCache, and theIMemory/IMemoryHeapwire (handwritten AOSP wire, not AIDL). STAGE3-gated against reallibbinderin both directions. - Data serialization (new in 0.11.0) —
to_bytes/from_bytes, no feature required since 0.12.0. The bytes are the IPC bytes, so only the two signatures may still change. See Storing Values. - Cross-stack bridging (new in 0.11.0) —
impl Interface for Strong<I>(a proxy publishes as a local service, so a gateway is one line) andbridge::Rewrap. See Cross-Transport Services. lazy_service(new in 0.11.0) —LazyServiceRegistrarand the AOSPregisterService/ client-callback lifecycle, gated against Android's ownservicemanager.- Receive mapping size (new in 0.12.0) —
ProcessState::init_with_mmap_size,binder://?mmap=,ClientOptions::mmap_size/ServeOptions::mmap_size. The size is local to the receiving process and nothing about it crosses the wire. TransportCaps(new in 0.12.0) —Client::caps(),RpcSession::caps(),Endpoint::static_caps(),calling_caps(). Each bit is derived from a check another type still performs, so the set of bits is what may grow.- Cancellation (new in 0.12.0) — the
cancelmodule over AOSP'sandroid.os.ICancellationSignal, STAGE3-gated against reallibbinderin both directions. - Typed service-specific errors (new in 0.12.0) —
ServiceSpecificError,#[derive(ServiceSpecificError)],impl_service_specific_error!,Status::service_specific,Status::service_error,Status::message. The code on the wire is thei32AOSP writes; only the Rust mapping is new. - Large payloads and pipes (new in 0.12.0) —
Parcel::write_blob/read_blob(AOSP's blob wire, inline up to 16 KB and a memfd region above),ParcelFileDescriptor::pipe()and itsRead/Writeimpls. - Awaitable lookups and death (new in 0.12.0,
tokiofeature) —wait_for_interface_async,check_interface_async,death_signal/DeathSignal. Wire behavior is that of the synchronous calls they wrap. - Fast Message Queue (new in 0.12.0) — the
rsbinder-fmqcrate (MessageQueue,EventFlag,Descriptor,AttachPolicy; the synchronized flavor, primitive elements, Linux and Android) andrsbinder::fmq, which re-exports it on every platform beside the AOSP parcelablesMQDescriptor,GrantorDescriptor,SynchronizedReadWrite,UnsynchronizedWriteandNativeHandle, with the twoTryFromconversions betweenMQDescriptorandDescriptor.rsbinder-aidlresolves imports ofandroid.hardware.commonandandroid.hardware.common.fmqto those types and compiles generic parcelables such asMQDescriptor<T, Flavor>. The parcelables are AOSP's VINTF-stable wire, and the queue keepslibfmq's memory layout, counters and futex protocol, so only the Rust signatures may still change. For an NDK peer, which cannot linklibfmq, the reference implementation is two header-only C11 files:rsbinder-fmq/c/rsbinder_fmq.h(the queue) andcontrib/ndk/rsbinder_stream.h(the stream's records on it). Validated against AOSP's ownlibfmqon the host, both roles (rsbinder-fmq/tests/libfmq_host.rs), and across binder on an emulator with either side as the service (example-hello/cpp/run_fmq_interop.sh); the queue header against the crate on the host (rsbinder-fmq/tests/c_header.rs), the record header with both ends under AddressSanitizer (tests/tests/c_stream_header.rs), and both against rsbinder on an emulator (example-hello/cpp/run_stream_interop.sh). See Builtin AOSP Types and Generic Parcelables. - Streaming (new in 0.12.0) — the
streammodule:Sink,Receiver, and the three AIDL files inrsbinder/aidl/stream/: thersbinder.stream.StreamEndpoint<T>parcelable (Tthe item type; the ring's record layout and EventFlag bits on the kernel path) and the two interfacesIStreamSink/IStreamSource(the RPC path). The contract is rsbinder's own rather than AOSP's, written as ordinary AIDL so a C++ or NDK peer can be either end (a Java peer is out of scope: AOSP has no Java FMQ). Validated rsbinder-to-rsbinder over kernel binder (two processes, including a real Android driver) and over RPC, and over kernel binder against an NDK peer built on the C reference headers and against one whose ring is AOSP's ownlibfmq, both directions (example-hello/cpp/run_stream_interop.sh), and over RPC against the device's libbinderRpcSession, both directions (example-hello/cpp/run_stream_rpc_interop.sh). See Streaming. - Observability (new in 0.12.0) — the work source functions
(
set_calling_work_source_uidand the five beside it, the AOSPIPCThreadStateset),Remotable::transaction_namewithrsbinder_aidl::Builder::trace, theobservemodule (TransactionObserver,set_observer,LogObserver,StatsObserver), and thetracingfeature (TracingObserverand the client spans of proxies generated withtrace(true)). None of it changes the wire: the work source uses a header field kernel binder already has. The work source is STAGE3-gated against reallibbinder. See Observability. - Reconnecting (new in 0.12.0) —
Reconnectingand thereconnectmodule: one service named by aUri, looked up again after its process dies or its RPC session ends, with anon_connecthook rerun on each new connection. It adds nothing to the wire. On kernel binder it sends, beyond a plainconnect, a death link and, while the name is absent, a service-manager notification registration, both existing commands; over RPC it sends nothing a plainconnectdoes not. Validated over kernel binder and RPC, and against a reallibbinderRpcServerthat is killed and restarted on an emulator (example-hello/cpp/run_rpc_reconnect_interop.sh). See Reconnecting to a Service. - Freeze notifications (new in 0.12.0) —
IBinder::add_frozen_state_change_callback/remove_frozen_state_change_callback,FrozenStateChangeCallback,FrozenState, andProcessState::freeze_process/process_freeze_info: AOSPaddFrozenStateChangeCallback(libbinder android-15.0.0_r6+) over the driver's own commands, so the contract is the kernel UAPI rather than a libbinder wire. Validated on the Rust binder driver, on the C driver of an Android 17 emulator, and on an Android 15 driver withoutfeatures/freeze_notification, whereadd_frozen_state_change_callbackreturnsInvalidOperation(tests/tests/freeze_kernel.rs). RpcClientConfig(new in 0.12.0) — one android-13+ client configuration for every transport (unix,unix_abstract,vsock,tls,tcp_debug,new), withincoming_connectionsandoutgoing_connectionson all of them. It replacesRpcUnixClientConfigand the Unix-only multi-connection helpers, which are deprecated and go in the release after.- AIDL compiler, beyond the Stable entry points —
Builder::{dest_dir, hash}and the publicrendermodule, the seamrsbinder-macrosplugs into. Its input structs are#[non_exhaustive], so a template gaining a field stays a minor release.
Experimental (opt-in)
Off by default, gated by a Cargo feature. Wire format and API may change without a deprecation cycle.
| Feature | Surface | Status |
|---|---|---|
rpc-tcp-debug | TcpDebugTransport — plain TCP backend | Bring-up / interop only, never production. |
rpc-vsock | VsockTransport — host↔VM | Linux/Android only; loopback testing requires vsock_loopback.ko. |
rpc-tls | TLS over rustls, socket-orthogonal (tcp / unix / vsock) | Hermetic green; the StreamOwned decoupling (plan 2-15) has landed. Real-libbinder STAGE3 not yet attempted — stock emulator images ship no libbinder_tls. |
Non-goals
Surface that rsbinder will not support, even after 1.0. Listed here so contributors don't burn cycles implementing something that has already been ruled out — and so the AIDL compiler's deliberate rejection of these types reads as intentional rather than as a gap.
- AIDL
Map<K, V>— AOSP's own Rust / C++ / NDK backends rejectMap<K, V>at the language layer (aidl_language.cpp:1612-1615: "Currently, only Java backend supports Map."), and have done so since 2019. The wire format is built on JavaParcel's runtime type-tag system (VAL_STRING,VAL_INTEGER,VAL_MAP, …) which has no typed-Rust analogue. The rsbinder-aidl frontend therefore emitsunknown type 'Map'for anyMap<…>reference — matching AOSP. Useparcelable(typed struct),List<Entry>, orParcelableHolderinstead. Re-examine if AOSP removes the cross-backend block.
What this means in practice
- A 0.x → 0.(x+1) minor bump can change Provisional signatures.
Pre-1.0 the minor slot is the major slot, so a Stable item can
change there too — what the tier buys you is that it is last-resort and
always lands in that release's Migrating from … section of the
CHANGELOG,
named with its replacement. That section carries the changes that have a
replacement to name; one that only alters a value or a behavior may be
recorded under Fixed instead. Changed / Removed carry the rationale
for the entries that have one, but not every entry appears there.
rsbinder runs
cargo-semver-checksfor bothrsbinderandrsbinder-aidl(default features and RPC features) on pull requests targetingmaster; it reports signature changes, and cannot see a change that alters only a value or a behavior. Neither can your build — for those, read Migrating and Fixed both. - Experimental features never break the default build's wire format. Enabling one is an explicit acknowledgement that the corresponding interop gate has not passed.
- After 1.0, all Stable items follow Semver strictly. Provisional items get re-classified as Stable or moved into a feature gate.