Use binder IPC

This page describes changes to the binder driver in Android 8, provides details on using binder IPC, and lists required SELinux policy.

Changes to binder driver

Starting in Android 8, the Android framework and HALs now communicate with each other using binder. As this communication dramatically increases binder traffic, Android 8 includes several improvements designed to keep binder IPC fast. SoC vendors and OEMs should merge directly from the relevant branches of android-4.4, android-4.9, and higher of the kernel/common project.

Multiple binder domains (contexts)

Common-4.4 and higher, including upstream

To cleanly split the binder traffic between framework (device-independent) and vendor (device-specific) code, Android 8 introduced 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

Common-4.4 and higher, including 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 8 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

Common-4.4 and higher, including 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 subsequent 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 all common kernel 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 8.

Real-time priority inheritance

Common-4.4 and 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 8 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 8 adds support for real-time scheduling policies node inheritance.

Userspace changes

Android 8 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 isn't 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.

SHAs for common kernels

To obtain necessary changes to the binder driver, sync to the appropriate SHA:

  • Common-3.18
    cc8b90c121de ANDROID: binder: don't check prio permissions on restore.
  • Common-4.4
    76b376eac7a2 ANDROID: binder: don't check prio permissions on restore.
  • Common-4.9
    ecd972d4f9b5 ANDROID: binder: don't check prio permissions on restore.

Work with binder IPC

Historically, vendor processes have used binder interprocess communication (IPC) to communicate. In Android 8, 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. In Android 10, Stable AIDL allows all processes to use /dev/binder while also solving for the stability guarantees HIDL and /dev/hwbinder solved. For how to use Stable AIDL, see AIDL for HALs.

vndbinder

Android 8 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 Domain Description
/dev/binder IPC between framework/app processes with AIDL interfaces
/dev/hwbinder IPC between framework/vendor processes with HIDL interfaces
IPC between vendor processes with HIDL interfaces
/dev/vndbinder IPC between vendor/vendor 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 8, 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 don't 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.

SELinux policy

Vendor processes that want to use binder functionality to communicate with each other need the following:

  1. Access to /dev/vndbinder.
  2. Binder {transfer, call} hooks into vndservicemanager.
  3. binder_call(A, B) for any vendor domain A that wants to call into vendor domain B over the vendor binder interface.
  4. Permission to {add, find} services in vndservicemanager.

To fulfill requirements 1 and 2, use the vndbinder_use() macro:

vndbinder_use(some_vendor_process_domain);

To fulfill requirement 3, the binder_call(A, B) for vendor processes A and B that need to talk over binder can stay in place, and doesn't need renaming.

To fulfill requirement 4, you must make changes in the way service names, service labels, and rules are handled.

For details on SELinux, see Security-Enhanced Linux in Android. For details on SELinux in Android 8.0, see SELinux for Android 8.0.

Service names

Previously, vendor processes registered service names in a service_contexts file and added corresponding rules for accessing that file. Example service_contexts file from device/google/marlin/sepolicy:

AtCmdFwd                              u:object_r:atfwd_service:s0
cneservice                            u:object_r:cne_service:s0
qti.ims.connectionmanagerservice      u:object_r:imscm_service:s0
rcs                                   u:object_r:radio_service:s0
uce                                   u:object_r:uce_service:s0
vendor.qcom.PeripheralManager         u:object_r:per_mgr_service:s0

In Android 8, vndservicemanager loads the vndservice_contexts file instead. Vendor services migrating to vndservicemanager (and which are already in the old service_contexts file) should be added to the new vndservice_contexts file.

Service labels

Previously, service labels such as u:object_r:atfwd_service:s0 were defined in a service.te file. Example:

type atfwd_service,      service_manager_type;

In Android 8, you must change the type to vndservice_manager_type and move the rule to the vndservice.te file. Example:

type atfwd_service,      vndservice_manager_type;

servicemanager rules

Previously, rules granted domains access to add or find services from servicemanager. Example:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;

In Android 8, such rules can stay in place and use the same class. Example:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;