Android HIDL 官方文檔(六)—— 使用 Binder 進程間通信機制(Using Binder IPC)



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

        這一章節描述了 Android O 中關於 Binder 的一些變化,提供了使用 Binder IPC 機制的細節,以及列出了一些所需要的 SELinux 相關策略。

1. Binder 驅動的改變

(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.

       從 Android O 開始,Android 框架層與 HAL 層之間就要通過 Binder 機制來進行通訊。這導致通過 Binder 傳輸的數據流量大大提升,爲了保持 Binder IPC 的高效,Android O 中對 Binder 進行了一些能可提升性能的修改。集成了最新版本驅動的 SoC 供應商 與 OEM 應查看所列出的相應的改進,關於用於 3.184.44.9 內核的 SHA,以及所需求的用戶空間的修改。

1.1 多個 Binder 域(上下文)

(Multiple binder domains (contexts))
In common-3.10, common-3.18, common-4.4, common-4.9, and upstream

       在 common-3.10, common-3.18, common-4.4, common-4.9 以及更上游的版本中。

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.

       爲了明確劃分框架(獨立於設備)和供應商(特定於設備)代碼之間的 Binder 流量,Android O 介紹了一個 Binder 上下文的概念。每個 Binder 上下文都擁有自己的設備節點以及上下文(服務)管理者。當您通過某個上下文傳遞 Binder 節點時,您只能通過它所屬的設備節點來訪問對應的上下文管理器,它只能通過另一個進程來訪問,從而使得各個域完全隔離。更多詳細信息在 vndbindervndservicemanager 小節中有描述。

1.2 散集列表

(Scatter-gather)
In common-3.10, common-3.18, common-4.4, common-4.9, and upstream

       在 common-3.10, common-3.18, common-4.4, common-4.9 以及更上游的版本中。

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 版本中,Binder 調用的每一個數據都會被複制三次:

  • 一次是在調用的進程中將數據序列化爲一個 Parcel
  • 一次是在內核驅動中將 Parcel 拷貝給目標進程。
  • 一次是在目標進程中將 Parcel 反序列化。

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.

       Android O 採用散集優化的方式將拷貝次數從三次減少到一次。數據保持原本的結構與內存佈局,而驅動則立即將其複製到目標進程中,這樣第一次拷貝操作就省下了。當數據到達目標進程中,其結構與內存佈局是不變的,因此可以不需要另外的拷貝操作就讀取數據(將序列化與反序列化過程去掉了)。

1.3 更細化地加鎖

(Fine-grained locking)
In common-3.18, common-4.4, common-4.9, and upstream

       在 common-3.18, common-4.4, common-4.9 以及更上游的版本中。

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.

       在以往的 Android 版本中, Binder 驅動會使用一個全局的鎖來防止對於關鍵數據結構的併發訪問。雖然對於鎖的搶奪情況很少,但主要的問題在於,如果一個低優先級線程獲得了鎖,隨後被搶佔,它就會使需要獲得相同鎖的高優先級線程嚴重地延遲。這在平臺中導致了 jank(PS:我不知道是什麼東西) 這種情況。

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.

       最初,通過嘗試在持有全局鎖時禁用搶佔來解決這個問題。然而這更像是一種 “hack” 行爲,而非真正的解決方案,並且最終被更上游的版本所拒絕與棄用。隨後進行的嘗試專注於更細化地加鎖,自 2017 年 1 月開始,這一版本一直在 Pixel 設備上運行。目前主要的改動已經發布到公開版本中,在以後的版本中還會繼續有大量的改進加入其中。

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.

       在解決了實現細粒度鎖中的一些問題之後,我們設計了一個改進的解決方案,它採用不同的鎖架構,這個更改方案已經提交到 3.184.44.9 common 分支中。我們繼續要大量不同的設備上測試了這一實現,沒有發現任何突出的問題,因此目前這是 Android O 的推薦實現方案。

Note: We strongly encourage budgeting sufficient testing hours for fine-grained locking.

       注意:我們強烈建議爲細粒度鎖制定足夠的測試時間。

1.4 實時優先級繼承

(Real-time priority inheritance)
In common-3.18, common-4.4, common-4.9 (upstream coming soon)

       在 common-3.18, common-4.4, common-4.9 (上游版本即將開放)

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.

       Binder 驅動一直很好地支持優先級繼承。隨着越來越多的 Android 進程在實時優先級運行,某些情況下,如果一個實時線程發出一個 Binder 調用,則處理該調用的進程中的線程也會在實時優先級中運行。爲了支持這些用例,Android O 在 Binder 驅動程序中實現了實時優先繼承。

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.

       除了事務級的優先級繼承以外,節點優先級繼承允許節點(Binder 服務對象)指定一個最低優先級,該節點應執行調用該節點的請求。在以前的 Android 版本中,已經很好地支持了節點優先級繼承,而 Android O 則增加了對於實時調度策略節點繼承的支持。

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 性能團隊發現,實時優先級繼承在框架的 Binder 域(/dev/binder)中造成了不必要的副作用,所以在該域中,實時優先級繼承是被禁用的。

1.5 用戶空間更改

(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.

       Android O 中包含了所有需要的用戶空間更改,這些變化需要與公共內核中的當前 Binder 驅動一起工作,但有一個例外:原始的實現中採用一個 ioctl 操作禁用 /dev/binder 的實時優先級繼承。隨後的開發會將優先級繼承轉換爲一種更具細粒度的方法,即每個 Binder 模式(而非每個上下文)。因此,ioctl 在我們的公共內核中,而不是在 Android 公共分支中提交。

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.

       這些關於實時優先級繼承的改變的效果,在默認情況下對於每個節點都是禁用的。Android 性能團隊發現,在 hwbinder 域中啓用實時優先級繼承是有好處的。爲實現同樣的效果,需要在用戶空間中選擇這個更改。

1.6 公共內核中的一些 SHA

(SHAs for common kernels)

To obtain necessary changes to the binder driver, sync to the SHAs below (or later):

  • 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.

       爲了獲得必要的關於 Binder 驅動的更改,需要同步下面這些 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.

2. 使用 Binder IPC

(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.

       從以往的情況來看,供應商進程使用 Binder 進程間通訊機制進行通信,在 Android O 中,/dev/binder 設備節點成爲了獨立於框架進程的存在,這就意味着供應商進程不能再訪問它。供應商進程可以訪問 /dev/hwbinder,但必須將它們的 AIDL 接口轉換爲 HIDL 接口。對於需要繼續在供應商進程間使用 AILD 接口的供應商,Android 支持如下所述的 Binder IPC。

2.1 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 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

       Android O 支持由供應商服務所使用的一個新的域,使用 /dev/vndbinder 代替對 /dev/binder 的訪問。在添加 /dev/vndbinder 之後,目前 Binder IPC 共有以下三個域:

IPC 域 相關信息
/dev/binder framework/app 進程與 AIDL 接口之間的 IPC
/dev/hwbinder framework/vendor 進程與 HIDL 接口之間的 IPC
vendor 進程與 HIDL 接口之間的 IPC
/dev/vndbinder vendor/vendor 進程與 AIDL 接口之間的 IPC

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).

       對於 /dev/vndbinder 的出現,確保 CONFIG_ANDROID_BINDER_DEVICES 這一內核配置項被設置爲 binder,hwbinder,vndbinder(這在 Android 公共內核樹中是默認的)。

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):

       通常供應商進程不會直接打開 Binder 驅動,而是連接到 libbinder 用戶空間庫去,這個庫打開了 Binder 驅動。加入一個方法爲 ::android::ProcessState() 選擇用於 libbinder 的 Binder 驅動程序。在供應商進程調用 ProcessStateIPCThreadState 或對任何 Binder 的一般性調用之前,這一方法就應該被調用了。要使用它,則請在供應商進程(客戶端和服務端)的主函數之後進行如下調用:

ProcessState::initWithDriver("/dev/vndbinder");

2.2 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.

       在以前,Binder 驅動會註冊到 servicemanager 中,這樣它可以被其它進程獲取。而在 Android O 中,servicemanager 目前已經完全只由框架與應用程序來使用,而供應商進程已經無法訪問它。

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.

       供應商服務現在可以使用 vndservicemanager,這是用 /dev/vndbinder 代替了 /dev/binder 而構成的新的 servicemanager 實例,它與框架層的 servicemanager 是用同一源碼所構建的。供應商進程不需要爲了與 vndservicemanager 進行通訊而做出更改,當供應商進程打開 /dev/vndbinder 後,服務就會自動查找到 vndservicemanager

The vndservicemanager binary is included in Android’s default device makefiles.

       vndservicemanager 的二進制文件已經包含在 Android 默認的設備 makefile 中。

3. SELinux 策略

(SELinux policy)

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

  • Access to /dev/vndbinder.
  • Binder {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.
  • Permission to {add, find} services in vndservicemanager.

       需要使用 Binder 的功能以同其它進程通訊的供應商進程需要以下幾個條件:

  • 訪問 /dev/vndbinder
  • Binder 的鉤子函數 {transfer, call} 設置到 vndservicemanager 中。
  • binder_call(A, B) 用於想要通過供應商 Binder 接口來調用到供應商域 B 的供應商域 A。
  • vndservicemanager 中獲得 {add, find} 的服務權限。

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

       爲完成第一第二個需求,則要使用到宏 vndbinder_use()

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.

       爲完成第三個需求,對供應商進程 A 和 B 的 binder_call(A, B) 可以保持在一個恰當的位置,並不需要重命名。

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.

       對於 SELinux 的更詳細的細節,可以閱讀 Android 中的安全增強型 Linux。對於 Android O 的 SELinux,可以參看 Android 8.0 的安全增強型 Linux

3.1 服務名稱

(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:

       在之前,供應商進程將服務名稱註冊到 service_contexts 文件中,並且會增加相應的訪問該文件的規則。一個關於 device/google/marlin/sepolicyservice_contexts 文件的例子:

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.

       在 Android O 中,採用 vndservicemanager 來加載 vndservice_contexts 文件以替代上述過程。遷移到 vndservicemanager 中的供應商服務應該增加到相應的 vndservice_contexts 文件中。

3.2 服務標籤

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

       以往的服務標籤,比如 u:object_r:atfwd_service:s0 會定義在一個 service.te 文件中,如下:

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:

       在 Android O 中,您必須將類型改變爲 vndservice_manager_type ,並且將規則移動到 vndservice.te 文件中,如下:

type atfwd_service,      vndservice_manager_type;

3.3 服務管理者規則

(Servicemanager rules)

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

       以前,規則授權域訪問從 servicemanager 添加或查找服務,比如:

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:

       在 Android O 中,這樣的設置可以不被更改,保持原位,比如:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;
發佈了28 篇原創文章 · 獲贊 82 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章