“Treble separates system and vendor” states an intention, not the mechanism. Separation works only when independently built components agree on which interface exists, how its values are encoded, which version is required, and what happens when a feature is absent. This chapter follows those agreements across an update.
Before you start#
Read Inside a HAL service, HALs and Treble, Soong, and Bytes and trust. Source examples use AOSP android-14.0.0_r1. Compatibility examples are invented unless explicitly identified as source. No system/vendor mixing or flashing is required.
Learning goals#
Distinguish wire compatibility, semantic compatibility, stable native linkage, VINTF matching, and physical correctness. Explain frozen AIDL snapshots, version/hash queries, capabilities, defaults, and fallbacks. Work through an old-service/new-client matrix without concluding that any Android system image can run with any vendor image.
The dependency problem Treble addresses#
Without a controlled boundary, a vendor implementation can depend on an internal framework C++ layout or symbol that changes in the next platform release. Updating the framework would then require rebuilding vendor code even when the hardware has not changed. Treble limits and versions such dependencies so supported framework/vendor combinations can evolve with less lockstep work. It does not eliminate kernel, firmware, bootloader, SELinux, partition, or product requirements.
A wire contract says how calls and data cross a process boundary. A native ABI says how compiled code links and calls within a process. Stable AIDL addresses a Binder interface's cross-process contract. Stable native libraries and linker restrictions address a different dependency problem. A HAL's use of Binder does not make every library it links stable.
Stable AIDL freezes an agreed schema#
The Android 14 vibrator aidl_interface declares stability: "vintf" and versions 1 and 2. Its aidl_api/android.hardware.vibrator/ directory retains API snapshots. Generated version-specific libraries let dependencies name the agreed interface version instead of accidentally compiling against a moving file.
The stable AIDL documentation describes updating/freezing APIs and compatibility checks. Snapshot checking asks whether the declared change follows allowed evolution rules. It cannot inspect the motor, prove vendor code uses the new fields correctly, or decide that a unit change from milliseconds to seconds is harmless.
Interface version identifies an evolution level. Interface hash identifies the frozen API definition. The generated getInterfaceVersion() and getInterfaceHash() operations support identification; the hash is not a cryptographic attestation that the service executable is trusted or uncompromised. An attacker-controlled implementation can claim things. Boot trust and runtime authorization are separate mechanisms.
Evolve values without rewriting their meaning#
Suppose a fictional V1 interface has a request with durationMs. V2 adds an optional strength field with a defined default and a new method. This is a teaching example, not the vibrator HAL's actual change history.
- A new server must continue understanding the old method and the old field's meaning.
- A new client speaking to an old server must not assume a new method exists.
- A newly added structured-parcelable field needs a meaningful default for old senders; old receivers do not acquire its semantics just because they can skip unknown data.
- New enum values need defensive handling. “The enum compiled” does not mean an older service recognizes the value.
- Reordering existing fields, changing types, or repurposing units can break decoding or behavior.
Stable AIDL restricts changes and generates compatibility machinery, but application logic still chooses fallback behavior. For an unavailable method, a client might use an older operation, decline the feature, or report unsupported according to contract. Retrying the same unknown transaction forever cannot upgrade the server.
Version and capability answer different questions
A service can implement interface V2 without supporting every optional physical feature described by V2. Version says what schema/method evolution is available; a capability bit says which defined feature the implementation supports. Neither proves the feature works on hardware. For vibration, use version checks for versioned protocol evolution and getCapabilities()/supported-effect queries for optional behavior. A version check cannot replace a capability check.
- Stable AIDL schema
- Do the communicating versions encode and interpret compatible calls?
- Optional capability
- Does this implementation support the requested feature?
- VINTF requirements
- Do assembled declarations satisfy the supported product requirements?
- Native dependencies
- Can each process load its permitted compatible libraries?
- Hardware behavior
- Does the actual device perform the intended operation correctly?
VINTF: what exists versus what is required#
A device manifest declares interfaces provided by the device/vendor side. A framework compatibility matrix describes requirements on that side for a supported framework compatibility level. VINTF also includes the opposite direction: framework manifests and device matrices express framework-provided services and device requirements. Do not reduce the entire system to a single XML file.
In the actual example fragment, the HAL format is aidl, name is android.hardware.vibrator, version is 2, and instance is IVibrator/default. Those fields are not interchangeable with the init process name. See the VINTF overview and matching rules.
A framework compatibility matrix level organizes the set of requirements associated with a supported device/framework relationship. It is not simply the currently displayed Android version or a guarantee that every component was rebuilt together. Device launch level, declared target level, deprecated interfaces, and supported update relationships matter. Matching operates on the assembled configuration, including relevant fragments—not an isolated snippet pasted from another product.
Worked mismatch packet
Synthetic simplified requirement:
framework requires: android.hardware.demo, AIDL, version 2, IDemo/default
device declares: android.hardware.demo, AIDL, version 1, IDemo/default
running process: demo-hal, says "started"
The process state does not satisfy the version requirement. A successful old method call cannot prove the new required contract exists. Conversely, correcting XML to say version 2 while retaining a V1 implementation makes the declaration misleading; it does not add the method. The right repair is a supported interface/product change and matching implementation/tests, not changing whichever string makes the checker quiet.
Why native linkage still matters#
On the Android 14 baseline, VNDK and linker-namespace rules constrain vendor dependencies on platform native libraries. A linker namespace controls which libraries can be found/loaded and which symbols/dependencies are reachable; it is not a mount namespace and does not grant access to a device node. A service may have a correct AIDL schema and fail before registration because the dynamic linker cannot resolve a dependency.
The Android 14 VNDK documentation and linker namespace design explain that native dependency boundary. Newer Android releases have changed VNDK arrangements; treat this as baseline-specific, not an eternal packaging rule. Vendor-side AIDL native implementations use the supported stable NDK Binder boundary rather than assuming private libbinder C++ ABI stability.
That distinction gives three independent update failures: schema mismatch, native-link failure, or correct transport with incorrect device behavior. “The HAL is incompatible” is too vague to select a repair.
Practice#
Work through the invented compatibility matrix. Assume the example permits version negotiation and optional new operations; a product that requires V2 has an additional VINTF requirement and cannot rely on a V1 fallback.
| Client | Server | Required client behavior |
|---|---|---|
| V1 | V1 | Use the agreed V1 operations |
| V1 | V2 | V2 preserves V1 behavior |
| V2 | V1 | Check availability and use a contract-defined fallback or report unsupported |
| V2 | V2, optional hardware capability absent | Do not request that optional feature merely because version is 2 |
HOST Python 3, original model; no XML parsing or device modification. This deliberately models only an integer minimum and capability check, not the full VINTF matching algorithm:
def feature_available(server_version, required_version, capability):
return server_version >= required_version and capability
assert feature_available(2, 2, True)
assert not feature_available(1, 2, True)
assert not feature_available(2, 2, False)
print("3 version/capability cases passed; not a VINTF verifier")
Then inspect the real V1/V2 vibrator snapshots. Choose one actual addition, record its precise contract/default, and explain how an old caller/server differs. If you cannot establish the actual difference, keep the invented matrix and mark the source comparison incomplete; do not attribute the fictional strength field to the real HAL.
Knowledge check#
- Why is an interface hash not service attestation?
- Does version 2 guarantee amplitude control or other optional hardware support?
- Can a running V1 daemon satisfy a required V2 interface by changing XML alone?
- What can fail before an otherwise compatible HAL registers?
Answers#
- It identifies an API definition, not authenticated executable identity or runtime integrity.
- No. Query the relevant capabilities and respect the operation contract.
- No. Declaration must agree with the actual supported implementation.
- Native dependency/linking, process startup, configuration, SELinux, or registration failures.
Checkpoint#
Ready when the matrix distinguishes schema/version, optional capability, VINTF requirements, native ABI, and physical behavior, and the three model cases pass. Revise if a passing XML match is treated as hardware validation or interface hashes as attestation. Return to the manifest fields and write one separate test/evidence source for each compatibility layer. Full product compatibility is not yet evidenced by this worksheet.
Sources#
- AOSP Android 14 vibrator
Android.bp, frozen API directory, and example manifest — concrete version/declaration artifacts. - AOSP stable AIDL and AIDL HALs — allowed evolution, version/hash queries, backends, and defaults; moving documentation.
- AOSP VINTF and matching rules — bidirectional declarations and requirements; the model above implements only a stated simplification.
- AOSP VNDK and linker namespaces — native dependency separation; interpret against the historical Android 14 baseline.