This page describes changes to the binder driver in Android O, provides details on using binder IPC, and lists required SELinux policy.
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.
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.
In previous releases of Android, every piece of data in a binder call was copied three times:
Parcel
in the calling processParcel
to the target
processParcel
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.
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.
Note: We strongly encourage budgeting sufficient testing hours for fine-grained locking.
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.
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.
To obtain necessary changes to the binder driver, sync to the SHAs below (or later):
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.
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 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");
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.
Vendor processes that want to use binder functionality to communicate with each other need the following:
/dev/vndbinder
.{transfer, call}
hooks into
vndservicemanager
.binder_call(A, B)
for any vendor domain A that wants to call
into vendor domain B over the vendor binder interface.{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.
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 O, 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.
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 O, 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;
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 O, 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;