Changes to binder driver
Starting in Android O, the Android framework and HALs now communicate with each other using binder. As this communication dramatically increases binder traffic, Android O includes several improvements designed to keep binder IPC fast. SoC vendors and OEMs integrating the latest version of the driver should review the list of these improvements, relevant SHAs for the 3.18, 4.4, and 4.9 kernels, and required userspace changes.
Multiple binder domains (contexts)
In common-3.10, common-3.18, common-4.4, common-4.9, and upstream
To cleanly split the binder traffic between framework (device-independent) and vendor (device-specific) code, Android O introduces the concept of a binder context. Each binder context has its own device node and its own context (service) manager. You can access the context manager only through the device node to which it belongs and, when passing a binder node through a certain context, it is accessible from that same context only by another process, thus completely isolating the domains from each other. For details on using, see vndbinder and vndservicemanager.
Scatter-gather
In common-3.10, common-3.18, common-4.4, common-4.9, and upstream
In previous releases of Android, every piece of data in a binder call was copied three times:
- Once to serialize it into a
Parcel
in the calling process - Once in the kernel driver to copy the
Parcel
to the target process - Once to unserialize the
Parcel
in the target process
Android O uses scatter-gather optimization to reduce the number of copies from 3 to 1. Instead of serializing data in a Parcel
first, data remains in its original structure and memory layout and the driver immediately copies it to the target process. After the data is in the target process, the structure and memory layout is the same and the data can be read without requiring another copy.
Fine-grained locking
In common-3.18, common-4.4, common-4.9, and upstream
In previous Android releases, the binder driver used a global lock to protect against concurrent access to critical data structures. While there was minimal contention for the lock, the main problem was that if a low-priority thread obtained the lock and then got preempted, it could seriously delay higher-priority threads needing to obtain the same lock. This caused jank in the platform.
Initial attempts to resolve this problem involved disabling preemption while holding the global lock. However, this was more of a hack than a true solution, and was eventually rejected by upstream and discarded. Subsequent attempts focused on making locking more fine-grained, a version of which has been running on Pixel devices since January 2017. While the majority of those changes were made public, substantial improvements were made in future versions.
After identifying small issues in the fine-grained locking implementation, we devised an improved solution with a different locking architecture and submitted the changes in the 3.18, 4.4, and 4.9 common branches. We continue to test this implementation on a large number of different devices; as we are unaware of any outstanding issues, this is the recommended implementation for devices shipping with Android O.
Real-time priority inheritance
In common-3.18, common-4.4, common-4.9 (upstream coming soon)
The binder driver has always supported nice priority inheritance. As an increasing number of processes in Android run at real-time priority, in some cases it now makes sense that if a real-time thread makes a binder call, the thread in the process that handles that call also runs at real-time priority. To support these use cases, Android O now implements real-time priority inheritance in the binder driver.
In addition to transaction-level priority inheritance, node priority inheritance allows a node (binder service object) to specify a minimum priority at which calls into this node should be executed. Previous versions of Android already supported node priority inheritance with nice values, but Android O adds support for real-time scheduling policies node inheritance.
Note: The Android performance team found that real-time priority inheritance caused unwanted side-effects in the framework binder domain (/dev/binder
), so real-time priority inheritance is disabled for that domain.
Userspace changes
Android O includes all userspace changes required to work with the current binder driver in the common kernel with one exception: The original implementation to disable real-time priority inheritance for /dev/binder
used an ioctl. Subsequent development switched control of priority inheritance to a more fine-grained method that is per binder mode (and not per context). Thus, the ioctl is not in the Android common branch and is instead submitted in our common kernels.
The effect of this change is that real-time priority inheritance is disabled by default for every node. The Android performance team has found it beneficial to enable real-time priority inheritance for all nodes in the hwbinder
domain. To achieve that same effect, cherry-pick this change in userspace.
Using binder IPC
Historically, vendor processes have used binder interprocess communication (IPC) to communicate. In Android O, the /dev/binder
device node becomes exclusive to framework processes, meaning vendor processes no longer have access to it. Vendor processes can access /dev/hwbinder
, but must convert their AIDL interfaces to use HIDL. For vendors who want to continue using AIDL interfaces between vendor processes, Android supports binder IPC as described below.
vndbinder
Android O supports a new binder domain for use by vendor services, accessed using /dev/vndbinder
instead of /dev/binder
. With the addition of /dev/vndbinder
, Android now has the following three IPC domains:
IPC between framework/app processes with AIDL interfaces
For /dev/vndbinder
to appear, ensure the kernel configuration item CONFIG_ANDROID_BINDER_DEVICES
is set to"binder,hwbinder,vndbinder"
(this is the default in Android's common kernel trees).
Normally, vendor processes don't open the binder driver directly and instead link against the libbinder
userspace library, which opens the binder driver. Adding a method for ::android::ProcessState()
selects the binder driver for libbinder
. Vendor processes should call this method before calling into ProcessState,
IPCThreadState
, or before making any binder calls in general. To use, place the following call after the main()
of a vendor process (client and server):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Previously, binder services were registered with servicemanager
, where they could be retrieved by other processes. In Android O, servicemanager
is now used exclusively by framework and app processes and vendor processes can no longer access it.
However, vendor services can now use vndservicemanager
, a new instance of servicemanager
that uses /dev/vndbinder
instead of /dev/binder
and which is built from the same sources as framework servicemanager
. Vendor processes do not need to make changes to talk to vndservicemanager
; when a vendor process opens /dev/vndbinder
, service lookups automatically go to vndservicemanager
.
The vndservicemanager
binary is included in Android's default device makefiles.