使用 Binder IPC

本頁面介紹了 Android 8 中 Binder 驅動程式的更改,提供了有關使用 Binder IPC 的詳細信息,並列出了所需的 SELinux 策略。

活頁夾驅動程式的更改

從 Android 8 開始,Android 框架和 HAL 現在使用 Binder 相互通訊。由於這種通訊極大地增加了 Binder 流量,Android 8 進行了多項改進,旨在保持 Binder IPC 快速。 SoC 供應商和 OEM 應該直接從 android-4.4、android-4.9 以及核心/通用專案的更高版本的相關分支進行合併。

多個活頁夾域(上下文)

Common-4.4 及更高版本,包括上游

為了乾淨地劃分框架(獨立於設備)和供應商(特定於設備)代碼之間的綁定器流量,Android 8 引入了綁定器上下文的概念。每個綁定器上下文都有自己的設備節點和自己的上下文(服務)管理器。您只能透過上下文管理器所屬的設備節點來存取它,並且當透過某個上下文傳遞綁定器節點時,只能由另一個程序從同一上下文存取它,從而將域彼此完全隔離。有關使用的詳細信息,請參閱vndbindervndservicemanager

分散-聚集

Common-4.4 及更高版本,包括上游

在先前的 Android 版本中,binder 呼叫中的每個資料都會被複製 3 次:

  • 一次在呼叫過程中序列化成Parcel
  • 一旦在核心驅動中將Parcel複製到目標進程
  • 一次在目標進程中反序列化Parcel

Android 8 使用分散-聚集優化將副本數量從 3 個減少到 1 個。資料不再先序列化Parcel中的數據,而是保留其原始結構和記憶體佈局,驅動程式立即將其複製到目標進程。資料進入目標進程後,結構和記憶體佈局相同,無需再次複製即可讀取資料。

細粒度鎖定

Common-4.4 及更高版本,包括上游

在先前的 Android 版本中,binder 驅動程式使用全域鎖定來防止對關鍵資料結構的同時存取。雖然對鎖的爭用很少,但主要問題是,如果低優先級執行緒獲得鎖然後被搶佔,則可能會嚴重延遲需要獲得相同鎖的高優先級執行緒。這導致平台卡頓。

解決此問題的最初嘗試涉及在持有全域鎖定的同時停用搶佔。然而,這更像是一種駭客行為,而不是真正的解決方案,最終被上游拒絕並丟棄。隨後的嘗試集中在使鎖定更加細粒度,其版本自 2017 年 1 月以來一直在 Pixel 設備上運行。雖然其中大部分更改已公開,但後續版本中進行了實質性改進。

在識別出細粒度鎖定實作中的小問題後,我們設計了一種具有不同鎖定架構的改進解決方案,並在所有公共核心分支中提交了變更。我們繼續在大量不同的設備上測試此實作;由於我們不知道有任何未解決的問題,因此這是針對搭載 Android 8 的裝置的建議實作。

即時優先權繼承

Common-4.4 和 common-4.9(上游即將推出)

Binder 驅動程式始終支援良好的優先級繼承。隨著 Android 中越來越多的進程以實時優先權運行,在某些情況下,如果實時線程進行綁定器調用,則處理該調用的進程中的線程也以實時優先權運行是有意義的。為了支援這些用例,Android 8 現在在 Binder 驅動程式中實現了即時優先權繼承。

除了事務級優先權繼承之外,節點優先權繼承還允許節點(binder 服務物件)指定應執行對該節點的呼叫的最低優先權。先前版本的 Android 已經支援帶有 Nice 值的節點優先權繼承,但 Android 8 增加了對即時調度策略節點繼承的支援。

使用者空間變化

Android 8 包括在通用核心中使用當前 Binder 驅動程式所需的所有用戶空間更改,但有一個例外:禁用/dev/binder的即時優先權繼承的原始實作使用了ioctl 。隨後的開發將優先權繼承的控制切換為更細粒度的方法,即每個綁定器模式(而不是每個上下文)。因此,ioctl 不在 Android 公共分支中,而是在我們的公共核心中提交

此變更的效果是預設情況下每個節點都停用即時優先權繼承。 Android 效能團隊發現為hwbinder域中的所有節點啟用即時優先權繼承是有益的。為了達到相同的效果,請在使用者空間中挑選此變更

通用核心的 SHA

要獲得對活頁夾驅動程式的必要更改,請同步到適當的 SHA:

  • 普通-3.18
    cc8b90c121de ANDROID:活頁夾:恢復時不檢查 prio 權限。
  • 普通-4.4
    76b376eac7a2 ANDROID:活頁夾:在恢復時不檢查 prio 權限。
  • 普通-4.9
    ecd972d4f9b5 ANDROID:活頁夾:恢復時不檢查 prio 權限。

使用活頁夾IPC

從歷史上看,供應商進程使用綁定器進程間通訊(IPC)進行通訊。在 Android 8 中, /dev/binder裝置節點成為框架進程獨佔的,這意味著供應商程序不再有權限存取它。供應商進程可以存取/dev/hwbinder ,但必須將其 AIDL 介面轉換為使用 HIDL。對於想要繼續在供應商進程之間使用 AIDL 介面的供應商,Android 支援 Binder IPC,如下所述。在 Android 10 中,穩定的 AIDL 允許所有進程使用/dev/binder ,同時也解決了 HIDL 和/dev/hwbinder穩定性保證問題。有關如何使用 Stable AIDL,請參閱HAL 的 AIDL

虛擬綁定程式

Android 8 支援供應商服務使用新的 Binder 網域,使用/dev/vndbinder而不是/dev/binder進行存取。在新增/dev/vndbinder後,Android 現在擁有以下三個 IPC 網域:

IPC域描述
/dev/binder具有 AIDL 介面的框架/應用程式進程之間的 IPC
/dev/hwbinder具有 HIDL 介面的框架/供應商進程之間的 IPC
具有 HIDL 介面的供應商進程之間的 IPC
/dev/vndbinder使用 AIDL 介面在供應商/供應商進程之間進行 IPC

要出現/dev/vndbinder ,請確保核心配置項目CONFIG_ANDROID_BINDER_DEVICES設定為"binder,hwbinder,vndbinder" (這是 Android 通用核心樹中的預設值)。

通常,供應商進程不會直接打開活頁夾驅動程序,而是連結到libbinder用戶空間庫,該庫會打開活頁夾驅動程式。新增::android::ProcessState()方法會選擇libbinder的綁定器驅動程式。供應商程序應該在呼叫ProcessState, IPCThreadState之前或在進行任何綁定器呼叫之前呼叫此方法。要使用,請在供應商進程(客戶端和伺服器)的main()之後放置以下呼叫:

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

vnd服務管理員

以前,綁定器服務是在servicemanager中註冊的,其他進程可以在其中檢索它們。在 Android 8 中, servicemanager現在僅由框架和應用程式使用,供應商進程無法再存取它。

但是,供應商服務現在可以使用vndservicemanager ,這是servicemanager的新實例,它使用/dev/vndbinder而不是/dev/binder ,並且它是從與框架servicemanager相同的來源建構的。供應商程序不需要進行更改即可與vndservicemanager進行通訊;當供應商程序開啟 / dev/vndbinder時,服務查找會自動前往vndservicemanager

vndservicemanager二進位檔案包含在 Android 的預設裝置 makefile 中。

SELinux 政策

想要使用綁定器功能相互通訊的供應商程序需要滿足以下條件:

  1. 訪問/dev/vndbinder
  2. Binder {transfer, call}掛鉤到vndservicemanager
  3. binder_call(A, B)適用於任何想要透過供應商 Binder 介面呼叫供應商域 B 的供應商域 A。
  4. vndservicemanager{add, find}服務的權限。

若要滿足要求 1 和 2,請使用vndbinder_use()巨集:

vndbinder_use(some_vendor_process_domain);

為了滿足要求 3,需要透過 Binder 進行通訊的供應商流程 A 和binder_call(A, B)可以保留在原處,且不需要重新命名。

若要滿足要求 4,您必須變更服務名稱、服務標籤和規則的處理方式。

有關 SELinux 的詳細信息,請參閱Android 中的安全增強型 Linux 。有關 Android 8.0 中 SELinux 的詳細信息,請參閱Android 8.0 的 SELinux

服務名稱

先前,供應商處理service_contexts檔案中註冊的服務名稱,並新增存取該檔案的相應規則。 device/google/marlin/sepolicy中的範例service_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

在 Android 8 中, vndservicemanager改為載入vndservice_contexts檔案。遷移到vndservicemanager供應商服務(並且已經位於舊的service_contexts檔案中)應新增至新的vndservice_contexts檔案。

服務標籤

以前,諸如u:object_r:atfwd_service:s0之類的服務標籤是在service.te檔案中定義的。例子:

type atfwd_service,      service_manager_type;

在 Android 8 中,您必須將類型變更為vndservice_manager_type並將規則移至vndservice.te檔案。例子:

type atfwd_service,      vndservice_manager_type;

服務管理器規則

先前,規則授予網域存取權限以從servicemanager新增或尋找服務。例子:

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

在 Android 8 中,此類規則可以保留並使用相同的類別。例子:

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