您可以使用 APEX 檔案格式封裝及安裝較低層級的 Android OS 模組。允許獨立的建築物 安裝原生服務和程式庫等元件 安裝、韌體、設定檔等
供應商 APEX 會由建構系統自動安裝在 /vendor
區段中,並由 apexd
在執行階段啟用,就像其他區段中的 APEX 一樣。
用途
供應商映像檔模組化
APEX 可協助在供應商映像檔上自然地將功能實作項目進行捆綁和模組化。
當供應商映像檔以獨立建構的供應商 APEX 組合而成時,裝置製造商就能輕鬆挑選自家裝置所需的特定供應商實作項目。製造商甚至能建立 如果所提供的 APEX 不符合他們的需求,或具備 全新的自訂硬體
舉例來說,原始設備製造商 (OEM) 可能會選擇使用 Android 開放原始碼計畫 Wi-Fi 設計裝置 實作 APEX、SoC 藍牙實作 APEX,以及自訂原始設備製造商 (OEM) 電話實作 APEX。
沒有廠商 APEXs 時,在實作中 供應商元件需要謹慎的協調和追蹤。只要在 APEX 中包裝所有元件 (包括設定檔和額外程式庫),並在任何跨功能通訊點使用明確定義的介面,就能讓不同元件可互換。
開發人員疊代作業
供應商 APEX 可在開發供應商模組時,將整個功能實作 (例如 Wi-Fi HAL) 整合至供應商 APEX,協助開發人員加快迭代速度。開發人員接著可以建構並個別推送供應商 APEX,以測試變更,而非重新建構整個供應商映像檔。
對於主要從事單一功能領域,且只想針對該功能領域進行迭代的開發人員而言,這可簡化並加快開發人員的迭代週期。
將特徵區域的自然繫結至 APEX 時,也會簡化 建構、推送及測試該特徵區域的變更。例如: 重新安裝 APEX 時,系統會自動更新所有封裝程式庫或設定檔 APEX 包括
將功能區域整合至 APEX 後,在發現裝置行為異常時,也可以簡化偵錯或還原作業。舉例來說,如果通訊服務在新版本中運作不良,開發人員可以嘗試在裝置上安裝較舊的通訊服務實作 APEX (無須刷新完整版本),並查看是否已還原正常行為。
工作流程範例:
# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w
# Test the device.
... testing ...
# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...
# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...
範例
基本概念
如需一般 APEX 資訊,包括裝置需求、檔案格式詳細資料和安裝步驟,請參閱主要的 APEX 檔案格式頁面。
在 Android.bp
中,設定 vendor: true
屬性可將 APEX 模組設為供應商 APEX。
apex {
..
vendor: true,
..
}
二進位檔和共用程式庫
除非 APEX 酬載具有穩定的介面,否則 APEX 會在 APEX 酬載中納入傳遞式依附元件。
供應商 APEX 依附元件的穩定原生介面包括 cc_library
和 stubs
以及 LLNDK 程式庫。這些依附元件會從封裝作業中排除,且依附元件會記錄在 APEX 資訊清單中。資訊清單
由 linkerconfig
處理,因此外部原生依附元件
使用這些內容
在以下程式碼片段中,APEX 包含二進位檔 (my_service
) 和其非穩定依附元件 (*.so
檔案)。
apex {
..
vendor: true,
binaries: ["my_service"],
..
}
在以下程式碼片段中,APEX 包含共用資料庫
my_standalone_lib
及其任何不可穩定版的依附元件 (如上所述)。
apex {
..
vendor: true,
native_shared_libs: ["my_standalone_lib"],
..
}
縮小 APEX
APEX 可能會變大,因為它會將不穩定的依附元件打包。建議您使用靜態連結。libc++.so
和 libbase.so
等常見程式庫可靜態連結至 HAL 二進位檔。建立依附元件以提供穩定的
也可以是另一種選擇依附元件不會隨附在 APEX 中。
HAL 實作
如要定義 HAL 實作,請在供應商 APEX 中提供相應的二進位檔和程式庫,如以下範例所示:
為充分封裝 HAL 實作,APEX 也應指定任何相關的 VINTF 片段和初始化指令碼。
VINTF 片段
如果片段位於 APEX 的 etc/vintf
,即可從供應商 APEX 提供 VINTF 片段。
使用 prebuilts
屬性,將 VINTF 片段嵌入 APEX。
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
查詢 API
將 VINTF 片段新增至 APEX 時,請使用 libbinder_ndk
API 取得 HAL 介面和 APEX 名稱的對應項目。
AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default")
:如果 HAL 例項是在 APEX 中定義,則為true
。AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...)
:取得定義 HAL 例項的 APEX 名稱。AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...)
:用於開啟轉送 HAL。
Init 指令碼
APEX 可透過兩種方式加入 init 指令碼:(A)
APEX 酬載或 (B) /vendor/etc
中的一般初始化指令碼。您可以同時設定
。
APEX 中的 Init 指令碼:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
供應商 APEX 中的初始化指令碼可以包含 service
定義和 on <property or event>
指令。
請確認 service
定義會指向同一個 APEX 中的二進位檔。舉例來說,com.android.foo
APEX 可能會定義名為 foo-service
的服務。
on foo-service /apex/com.android.foo/bin/foo
...
使用 on
指令時請務必謹慎。由於 APEX 中的 init 指令碼會
會在啟用 APEX「之後」,針對部分事件或屬性進行剖析及執行
。使用 apex.all.ready=true
盡快觸發動作。
Bootstrap APEXes 可以使用 on init
,但無法使用
on early-init
。
韌體
範例:
使用 prebuilt_firmware
模組類型,在供應商 APEX 中嵌入韌體,如下所示。
prebuilt_firmware {
name: "my.bin",
src: "path_to_prebuilt_firmware",
vendor: true,
}
apex {
..
vendor: true,
prebuilts: ["my.bin"], // installed inside APEX as /etc/firmware/my.bin
..
}
prebuilt_firmware
模組會安裝在 APEX 的 <apex name>/etc/firmware
目錄中。ueventd
會掃描 /apex/*/etc/firmware
目錄,找出韌體模組。
APEX 的 file_contexts
應正確標示任何韌體酬載項目,確保 ueventd
可在執行階段存取這些檔案;通常,vendor_file
標籤就足夠了。例如:
(/.*)? u:object_r:vendor_file:s0
核心模組
將核心模組以預建模組的形式嵌入供應商 APEX 中,如下所示。
prebuilt_etc {
name: "my.ko",
src: "my.ko",
vendor: true,
sub_dir: "modules"
}
apex {
..
vendor: true,
prebuilts: ["my.ko"], // installed inside APEX as /etc/modules/my.ko
..
}
APEX 的 file_contexts
應為所有核心模組酬載項目加上標籤
正確做法。例如:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
必須明確安裝核心模組。以下是供應商分割區中的初始化指令碼範例,顯示透過 insmod
安裝的情況:
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
執行階段資源重疊
範例:
使用 rros
屬性,在供應商 APEX 中嵌入執行階段資源覆蓋層。
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
其他設定檔
供應商 APEX 支援供應商區段中通常會出現的其他設定檔,這些檔案通常是供應商 APEX 中的預先建構檔案,我們也正在新增更多設定檔。
這些檢查包括:
- 功能宣告 XML
- 感應器功能 XML 在感應器 HAL 供應商 APEX 中預先建構
- 輸入設定檔
- 將觸控螢幕設定做為預先建構在僅限設定供應商 APEX
啟動供應商 APEX
在啟用 APEX 之前,應先提供 keymint
等部分 HAL 服務。這些 HAL 通常會在服務定義中設定 early_hal
,
初始化指令碼。另一個例子是 animation
類別,通常會比 post-fs-data
事件更早啟動。當這種早期 HAL 服務
已封裝在供應商 APEX 中,請在其 APEX 中加入 Pex "vendorBootstrap": true
以便提早啟用。請注意,啟動 APEX 可以是
僅從預建位置 (例如 /vendor/apex
) 啟用,而非從
/data/apex
。
系統屬性
以下是架構讀取的系統屬性,用於支援供應商 APEX:
input_device.config_file.apex=<apex name>
:設定後,輸入內容 設定檔 (*.idc
、*.kl
和*.kcm
) 是從中搜尋/etc/usr
目錄。ro.vulkan.apex=<apex name>
- 設定後,系統會從 APEX 載入 Vulkan 驅動程式。由於早期 HAL 會使用 Vulkan 驅動程式,因此請將 APEX 設為 啟動 APEX,並設定該連結器命名空間 顯示。
使用 setprop
在 init 指令碼中設定系統屬性
指令
額外的開發人員功能
開機時的 APEX 選項
範例:
開發人員也可以安裝多個版本的供應商 APEX,
相同的 APEX 名稱和金鑰,然後選取要啟用的各版本
持續開機。對於某些開發人員用途而言,這可能比使用 adb install
安裝新的 APEX 副本更簡單。
應用情境範例:
- 安裝 3 個版本的 Wi-Fi HAL 供應商 APEX:品質確保團隊可以使用某個版本執行手動或自動化測試,然後重新啟動至另一個版本並重新執行測試,再比較最終結果。
- 安裝 2 種版本的相機 HAL 供應商 APEX 實驗版:內部測試人員可以使用實驗版本,不需要 下載及安裝額外的檔案,方便使用者更換檔案
在啟動期間,apexd
會尋找遵循特定格式的 sysprops,
啟用正確的 APEX 版本。
房源鍵的預期格式如下:
- Bootconfig
- 用於設定
BoardConfig.mk
中的預設值。 androidboot.vendor.apex.<apex name>
- 用於設定
- Persistent sysprop
- 用於變更已啟動的裝置上設定的預設值。
- 會覆寫開機設定值 (如有)。
persist.vendor.apex.<apex name>
屬性的值應為要啟用的 APEX 檔案名稱。
// Default version.
apex {
name: "com.oem.camera.hal.my_apex_default",
vendor: true,
..
}
// Non-default version.
apex {
name: "com.oem.camera.hal.my_apex_experimental",
vendor: true,
..
}
預設版本也應使用
BoardConfig.mk
:
# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default
裝置啟動後,請設定持久性 sysprop,以便變更已啟用的版本:
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
如果裝置支援在刷新後更新開機設定 (例如透過 fastboot
oem
指令),請變更多個安裝項目的 bootconfig 屬性。
APEX 也會變更開機時啟用的版本。
如果是基於 Cuttlefish 的虛擬參考裝置,您可以使用 --extra_bootconfig_args
指令,在啟動時直接設定 bootconfig 屬性。例如:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";