使用 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 使用scatter-gather 優化將副本數量從 3 減少到 1。不是先序列化Parcel中的數據,而是數據保持其原始結構和內存佈局,驅動程序立即將其複製到目標進程。數據進入目標進程後,結構和內存佈局相同,無需再次復制即可讀取數據。

細粒度鎖定

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

在以前的 Android 版本中,binder 驅動程序使用全局鎖來防止對關鍵數據結構的並發訪問。雖然對鎖的爭用很少,但主要問題是如果低優先級線程獲得鎖然後被搶占,它可能會嚴重延遲需要獲得相同鎖的高優先級線程。這導致平台卡頓。

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

在確定了細粒度鎖定實現中的小問題後,我們設計了一個具有不同鎖定架構的改進解決方案,並在所有常見內核分支中提交了更改。我們繼續在大量不同的設備上測試這個實現;由於我們不知道有任何未解決的問題,因此建議對搭載 Android 8 的設備執行此操作。

實時優先級繼承

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

binder 驅動程序一直支持良好的優先級繼承。隨著 Android 中越來越多的進程以實時優先級運行,在某些情況下,如果實時線程進行綁定器調用,那麼處理該調用的進程中的線程也以實時優先級運行是有意義的.為了支持這些用例,Android 8 現在在 binder 驅動程序中實現了實時優先級繼承。

除了事務級優先級繼承之外,節點優先級繼承還允許節點(綁定服務對象)指定執行對該節點的調用的最低優先級。以前的 Android 版本已經支持具有不錯值的節點優先級繼承,但 Android 8 增加了對實時調度策略節點繼承的支持。

用戶空間更改

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

此更改的效果是默認情況下每個節點都禁用實時優先級繼承。 Android 性能團隊發現為hwbinder域中的所有節點啟用實時優先級繼承是有益的。為了達到同樣的效果,在用戶空間中挑選這種變化

通用內核的 SHA

要獲得對 binder 驅動程序的必要更改,請同步到適當的 SHA:

  • Common-3.18
    cc8b90c121de ANDROID:活頁夾:不要在恢復時檢查 prio 權限。
  • Common-4.4
    76b376eac7a2 ANDROID:活頁夾:不要檢查恢復時的優先權。
  • Common-4.9
    ecd972d4f9b5 ANDROID:活頁夾:不要檢查恢復時的prio權限。

使用活頁夾 IPC

歷史上,供應商進程使用綁定器進程間通信 (IPC) 進行通信。在 Android 8 中, /dev/binder設備節點成為框架進程獨有的,這意味著供應商進程不再有權訪問它。供應商進程可以訪問/dev/hwbinder ,但必須將其 AIDL 接口轉換為使用 HIDL。對於希望在供應商進程之間繼續使用 AIDL 接口的供應商,Android 支持 binder IPC,如下所述。

vndbinder

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 常見內核樹中的默認設置)。

通常,供應商進程不會直接打開 binder 驅動程序,而是鏈接到打開 binder 驅動程序的libbinder用戶空間庫。為::android::ProcessState()添加一個方法會選擇libbinder的 binder 驅動程序。供應商進程應在調用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 政策

想要使用 binder 功能相互通信的供應商進程需要以下內容:

  1. 訪問/dev/vndbinder
  2. Binder {transfer, call}掛鉤到vndservicemanager
  3. binder_call(A, B)用於希望通過供應商綁定接口調用供應商域 B 的任何供應商域 A。
  4. vndservicemanager{add, find}服務的權限。

要滿足要求 1 和 2,請使用vndbinder_use()宏:

vndbinder_use(some_vendor_process_domain);

為了滿足要求 3,需要通過 binder 進行對話的供應商進程 A 和 B 的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;