本頁面說明 Android 8 中 binder 驅動程式的變更,並提供使用 binder IPC 的詳細資訊,以及必要的 SELinux 政策。
繫結器驅動程式的變更
自 Android 8 起,Android 架構和 HAL 會使用繫結器相互通訊。由於這項通訊會大幅增加 Binder 流量,Android 8 包含了幾項改善功能,旨在讓 Binder IPC 保持快速。SoC 供應商和原始設備製造商 (OEM) 應直接從 kernel/common 專案的 android-4.4、android-4.9 以上版本的相關分支合併。
多個繫結器網域 (情境)
Common-4.4 以上版本,包括上游版本為了在架構 (裝置獨立) 和供應商 (裝置專屬) 程式碼之間清楚劃分 Binder 流量,Android 8 引入了 Binder 內容的概念。每個 Binder 內容都有自己的裝置節點和內容 (服務) 管理員。您只能透過所屬裝置節點存取情境管理器,而且當您透過特定情境傳遞繫結器節點時,只有另一個程序才能從該情境存取該節點,因此可完全隔離各個網域。如需詳細資訊,請參閱 vndbinder 和 vndservicemanager。
散佈-收集
Common-4.4 以上版本,包括上游版本在先前版本的 Android 中,繫結器呼叫中的每個資料都會複製三次:
- 在呼叫程序中將其序列化為
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 中以即時優先順序執行的程序數量增加,在某些情況下,如果即時執行緒發出 Binder 呼叫,處理該呼叫的程序中的執行緒也會以即時優先順序執行,這也是合理的做法。為支援這些用途,Android 8 現在會在 Binder 驅動程式中實作即時優先順序繼承功能。
除了交易層級優先順序繼承之外,節點優先順序繼承功能還可讓節點 (Binder 服務物件) 指定應執行對此節點的呼叫的最低優先順序。先前版本的 Android 已支援節點優先順序繼承,並提供不錯的值,但 Android 8 則新增了對即時排程政策節點繼承的支援。
使用者空間變更
Android 8 包含所有使用者空間變更,可與通用核心中的目前 Binder 驅動程式搭配運作,但有一個例外狀況:為 /dev/binder
停用即時優先順序繼承功能的原始實作方式使用了 ioctl。後續開發作業將優先順序繼承的控制權改為更精細的方法,也就是依 Binder 模式 (而非依情境) 進行。因此,ioctl 不在 Android 通用分支中,而是提交至通用核心。
這項變更的影響是,系統會預設為停用每個節點的即時優先順序繼承功能。Android 效能團隊發現,為 hwbinder
網域中的所有節點啟用即時優先順序繼承功能相當有益。如要達到相同的效果,請在使用者空間中挑選這個變更。
常見核心的 SHA
如要取得 Binder 驅動程式的必要變更,請同步至適當的 SHA:
- Common-3.18
cc8b90c121de ANDROID:Binder:請勿在還原時檢查 prio 權限。 - Common-4.4
76b376eac7a2 ANDROID:Binder:請勿在還原時檢查優先權限。 - Common-4.9
ecd972d4f9b5 ANDROID:binder:請勿在還原時檢查 prio 權限。
使用 Binder IPC
以往,供應商程序會使用 Binder 處理序間通訊 (IPC) 進行通訊。在 Android 8 中,/dev/binder
裝置節點會專屬於架構程序,這表示供應商程序不再有存取權。供應商程序可以存取 /dev/hwbinder
,但必須將 AIDL 介面轉換為使用 HIDL。如果供應商想繼續在供應商程序之間使用 AIDL 介面,Android 會支援下文所述的繫結器 IPC。在 Android 10 中,Stable AIDL 允許所有程序使用 /dev/binder
,同時解決 HIDL 和 /dev/hwbinder
解決的穩定性保證問題。如要瞭解如何使用穩定版 AIDL,請參閱「HAL 專用 AIDL」一文。
vndbinder
Android 8 支援新的繫結器網域,供供應商服務使用,可透過 /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 驅動程式,而是連結至 libbinder
使用者空間程式庫,後者會開啟 Binder 驅動程式。新增 ::android::ProcessState()
的方法會選取 libbinder
的繫結器驅動程式。供應商程序應在呼叫 ProcessState,
IPCThreadState
之前,或在一般情況下呼叫任何 Binder 之前,呼叫這個方法。如要使用,請在供應商程序 (用戶端和伺服器) 的 main()
後方放置下列呼叫:
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
先前,繫結器服務會註冊至 servicemanager
,其他程序可從該處擷取這些服務。在 Android 8 中,servicemanager
現已專供架構和應用程式程序使用,供應商程序則無法再存取該程序。
不過,供應商服務現在可以使用 vndservicemanager
,這是 servicemanager
的新例項,使用 /dev/vndbinder
而非 /dev/binder
,且與架構 servicemanager
使用相同的來源建構。供應商程序不需要變更就能與 vndservicemanager
通訊;當供應商程序開啟 /dev/vndbinder
時,服務查詢會自動轉到 vndservicemanager
。
vndservicemanager
二進位檔已納入 Android 的預設裝置 makefile。
SELinux 政策
供應商程序如要使用 Binder 功能相互通訊,就需要以下項目:
- 有權存取
/dev/vndbinder
。 - Binder
{transfer, call}
鉤入vndservicemanager
。 binder_call(A, B)
:任何供應商網域 A 如要透過供應商 Binder 介面呼叫供應商網域 B,vndservicemanager
中的{add, find}
服務權限。
如要滿足第 1 和第 2 項規定,請使用 vndbinder_use()
巨集:
vndbinder_use(some_vendor_process_domain);
為了滿足第 3 項規定,需要透過繫結器通訊的供應商程序 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;