The Latency Cost of Project Treble
Project Treble forced a massive architectural shift by moving hardware drivers out of the Android framework. This isolation required the system to use Binder IPC for every hardware interaction. Most subsystems handle this overhead gracefully. Graphics rendering does not. SurfaceFlinger maps and unmaps massive memory buffers thousands of times per second. Forcing those calls through a binder interface introduces unacceptable latency.
The system needed a bypass mechanism. Engineers had to find a way to run vendor code directly inside the framework process without violating the strict Treble API boundary. The interface had to remain identical to a remote HAL. The execution had to be local.
Bypassing IPC with Passthrough Mode
Maintaining a strict API boundary without inter-process communication requires a different loading mechanism. Passthrough Mode allows the framework client to load the vendor shared library directly into its own memory space. The client process calls dlopen on the vendor library instead of querying the service manager for a remote proxy.
You trigger this behavior by requesting the stub implementation explicitly. When a client requests a service, a boolean argument forces the system to load the local library. The true value indicates that you want the actual implementation object, not a Binder proxy.
// Requesting a passthrough HAL
sp<IMapper> mapper = IMapper::getService("default", true);
Common Mistake: Forgetting to pass
truewhen requesting a passthrough HAL will cause the system to search for a remote service that does not exist. The call will block or fail entirely.
This local loading strategy gives SurfaceFlinger zero-IPC latency. It preserves the exact same hardware interface as a fully isolated HAL.
Bridging the API Gap
Loading a C++ library directly introduces a structural problem. The raw C++ methods in the vendor library do not natively match the HIDL interface that the client expects. Client processes expect to call standard HIDL methods. The system must bridge this API gap.
The Android build system solves this by generating a wrapper class. This wrapper automatically implements the requested HIDL interface. The generated code intercepts the client method calls and directly invokes the underlying C++ functions of the loaded library. Function calls execute instantly because the wrapper serializes no data into a parcel.
We will compare a standard binderized HAL against a passthrough HAL to see this structural difference. This flowchart shows how passthrough eliminates the process boundary. Look for the local call bypassing the kernel entirely.
The binderized architecture requires two context switches through the kernel for every hardware request. Passthrough architecture keeps all execution within the client process. Client code remains oblivious to the underlying implementation details.
The Security Cost
Bypassing process isolation trades security and stability for pure speed. Vendor code running in Passthrough Mode executes directly inside critical system processes. A segmentation fault in the vendor graphics mapper will instantly crash SurfaceFlinger. Memory leaks in the vendor library will bloat the host framework process until the system runs out of memory.
Android accepted these risks during the initial Treble rollout to ease the transition for legacy HALs. Today, the platform aggressively restricts passthrough usage. Modern Android runs almost all HALs as fully binderized services. The Graphics Mapper HAL remains the sole major exception because display technology still demands absolute minimum latency.
You will likely never author a new passthrough HAL in modern Android. You will encounter them when debugging graphics crashes. Understanding that vendor code shares memory space with SurfaceFlinger provides the exact context you need to track down native crashes. When the system does enforce strict process isolation, it needs a fast and reliable way to pass messages back and forth across boundaries.