供應商 APEX

您可以使用APEX 檔案格式來打包和安裝較低層級的 Android 作業系統模組。它允許獨立建置和安裝本機服務和庫、HAL 實作、韌體、設定檔等元件。

供應商 APEX 由建置系統自動安裝在/vendor分割區中,並在執行時由apexd激活,就像其他分割區中的 APEX 一樣。

用例

供應商鏡像的模組化

APEX 有助於供應商映像上功能實現的自然捆綁和模組化。

當供應商映像建置為獨立建置的供應商 APEX 的組合時,設備製造商能夠輕鬆挑選和選擇其設備上所需的特定供應商實現。如果所提供的 APEX 都不符合製造商的需求,或者他們擁有全新的客製化硬件,製造商甚至可以創建新的供應商 APEX。

例如,OEM 可能選擇使用 AOSP wifi 實作 APEX、SoC 藍牙實作 APEX 和自訂 OEM 電話實作 APEX 來組合其裝置。

如果沒有供應商 APEX,供應商組件之間具有如此多依賴關係的實作需要仔細協調和追蹤。透過將所有元件(包括設定檔和額外函式庫)包裝在 APEX 中,並在跨功能通訊的任何點上具有明確定義的接口,不同的元件就可以互換。

開發者迭代

供應商 APEX 透過將整個功能實作(例如 wifi 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 依賴項的穩定本機介麵包括具有stubs cc_libraryndk_libraryllndk_library 。這些依賴項會從打包中排除,並且依賴項記錄在 APEX 清單中。清單由linkerconfig處理,以便外部本機相依性在執行時可用。

/system分割區中的 APEX 不同,供應商 APEX 通常與特定的 VNDK 版本相關聯。 VNDK 庫保證版本內的 ABI 穩定性,因此我們可以將 VNDK 庫視為穩定庫,並透過使用use_vndk_as_stable屬性將其從 APEX 中排除來減少供應商 APEX 的大小。

在下面的程式碼片段中,APEX 將包含二進位檔案 ( my_service ) 及其不穩定的依賴項 ( *.so檔案)。即使my_service是使用libbase等 VNDK 庫建構的,它也不會包含 VNDK 庫。相反,在執行時間my_service將使用系統提供的 VNDK 庫中的libbase

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

在下面的程式碼片段中,APEX 將包含共用程式庫my_standalone_lib及其任何不穩定依賴項(如上所述)。

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

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",
}

初始化腳本

APEX 可以透過兩種方式包含初始化腳本:(A) APEX 有效負載中的預先建置文字文件,或 (B) /vendor/etc中的常規初始化腳本。您可以將兩者設定為相同的 APEX。

APEX 中的初始化腳本:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

APEX 中的初始化腳本只能有service定義。供應商 APEX 中的初始化腳本也可以有on <property>指令。

使用on指令時要小心。由於APEX中的init腳本是在APEX啟動解析並執行的,因此某些事件或屬性無法使用。使用apex.all.ready=true儘早觸發操作。

韌體

例子:

使用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

內核模組必須明確安裝。供應商分區中的以下範例 init 腳本顯示了透過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 內預先建置的文件,並且正在新增更多設定檔。

例子:

額外的開發功能

啟動時選擇 APEX

例子:

開發人員還可以安裝共享相同 APEX 名稱和金鑰的多個版本的供應商 APEX,然後使用持久性 sysprops 選擇在每次啟動期間啟動哪個版本。對於某些開發人員用例,這可能比使用adb install安裝 APEX 的新副本更簡單。

範例用例:

  • 安裝 3 個版本的 wifi HAL 供應商 APEX: QA 團隊可以使用一個版本執行手動或自動測試,然後重新啟動到另一個版本並重新執行測試,然後比較最終結果。
  • 安裝相機 HAL 供應商 APEX 的 2 個版本,當前版本實驗版本 Dogfooders 可以使用實驗版本,而無需下載和安裝附加文件,因此他們可以輕鬆換回。

在啟動過程中, apexd會依照特定格式尋找 sysprops,以啟動正確的 APEX 版本。

屬性鍵的預期格式為:

  • 啟動配置
    • 用於設定預設值,在BoardConfig.mk
    • androidboot.vendor.apex.<apex name>
  • 持久性 sysprop
    • 用於變更在已啟動的裝置上設定的預設值。
    • 覆寫 bootconfig 值(如果存在)。
    • 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中的 bootconfig 進行設定:

# 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;

如果裝置支援在刷新後更新 bootconfig(例如透過fastboot oem指令),則變更多重安裝 APEX 的 bootconfig 屬性也會變更啟動時啟動的版本。

對於基於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";
,

您可以使用APEX 檔案格式來打包和安裝較低層級的 Android 作業系統模組。它允許獨立建置和安裝本機服務和庫、HAL 實作、韌體、設定檔等元件。

供應商 APEX 由建置系統自動安裝在/vendor分割區中,並在執行時由apexd激活,就像其他分割區中的 APEX 一樣。

用例

供應商鏡像的模組化

APEX 有助於供應商映像上功能實現的自然捆綁和模組化。

當供應商映像建置為獨立建置的供應商 APEX 的組合時,設備製造商能夠輕鬆挑選和選擇其設備上所需的特定供應商實現。如果所提供的 APEX 都不符合製造商的需求,或者他們擁有全新的客製化硬件,製造商甚至可以創建新的供應商 APEX。

例如,OEM 可能選擇使用 AOSP wifi 實作 APEX、SoC 藍牙實作 APEX 和自訂 OEM 電話實作 APEX 來組合其裝置。

如果沒有供應商 APEX,供應商組件之間具有如此多依賴關係的實作需要仔細協調和追蹤。透過將所有元件(包括設定檔和額外函式庫)包裝在 APEX 中,並在跨功能通訊的任何點上具有明確定義的接口,不同的元件就可以互換。

開發者迭代

供應商 APEX 透過將整個功能實作(例如 wifi 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 依賴項的穩定本機介麵包括具有stubs cc_libraryndk_libraryllndk_library 。這些依賴項會從打包中排除,並且依賴項記錄在 APEX 清單中。清單由linkerconfig處理,以便外部本機相依性在執行時可用。

/system分割區中的 APEX 不同,供應商 APEX 通常與特定的 VNDK 版本相關聯。 VNDK 庫保證版本內的 ABI 穩定性,因此我們可以將 VNDK 庫視為穩定庫,並透過使用use_vndk_as_stable屬性將其從 APEX 中排除來減少供應商 APEX 的大小。

在下面的程式碼片段中,APEX 將包含二進位檔案 ( my_service ) 及其不穩定的依賴項 ( *.so檔案)。即使my_service是使用libbase等 VNDK 庫建構的,它也不會包含 VNDK 庫。相反,在執行時間my_service將使用系統提供的 VNDK 庫中的libbase

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

在下面的程式碼片段中,APEX 將包含共用程式庫my_standalone_lib及其任何不穩定依賴項(如上所述)。

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

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",
}

初始化腳本

APEX 可以透過兩種方式包含初始化腳本:(A) APEX 有效負載中的預先建置文字文件,或 (B) /vendor/etc中的常規初始化腳本。您可以將兩者設定為相同的 APEX。

APEX 中的初始化腳本:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

APEX 中的初始化腳本只能有service定義。供應商 APEX 中的初始化腳本也可以有on <property>指令。

使用on指令時要小心。由於APEX中的init腳本是在APEX啟動解析並執行的,因此某些事件或屬性無法使用。使用apex.all.ready=true儘早觸發操作。

韌體

例子:

使用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

內核模組必須明確安裝。供應商分區中的以下範例 init 腳本顯示了透過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 內預先建置的文件,並且正在新增更多設定檔。

例子:

額外的開發功能

啟動時選擇 APEX

例子:

開發人員還可以安裝共享相同 APEX 名稱和金鑰的多個版本的供應商 APEX,然後使用持久性 sysprops 選擇在每次啟動期間啟動哪個版本。對於某些開發人員用例,這可能比使用adb install安裝 APEX 的新副本更簡單。

範例用例:

  • 安裝 3 個版本的 wifi HAL 供應商 APEX: QA 團隊可以使用一個版本執行手動或自動測試,然後重新啟動到另一個版本並重新執行測試,然後比較最終結果。
  • 安裝相機 HAL 供應商 APEX 的 2 個版本,當前版本實驗版本 Dogfooders 可以使用實驗版本,而無需下載和安裝附加文件,因此他們可以輕鬆換回。

在啟動過程中, apexd會依照特定格式尋找 sysprops,以啟動正確的 APEX 版本。

屬性鍵的預期格式為:

  • 啟動配置
    • 用於設定預設值,在BoardConfig.mk
    • androidboot.vendor.apex.<apex name>
  • 持久性 sysprop
    • 用於變更在已啟動的裝置上設定的預設值。
    • 覆寫 bootconfig 值(如果存在)。
    • 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中的 bootconfig 進行設定:

# 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;

如果裝置支援在刷新後更新 bootconfig(例如透過fastboot oem指令),則變更多重安裝 APEX 的 bootconfig 屬性也會變更啟動時啟動的版本。

對於基於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";
,

您可以使用APEX 檔案格式來打包和安裝較低層級的 Android 作業系統模組。它允許獨立建置和安裝本機服務和庫、HAL 實作、韌體、設定檔等元件。

供應商 APEX 由建置系統自動安裝在/vendor分割區中,並在執行時由apexd激活,就像其他分割區中的 APEX 一樣。

用例

供應商鏡像的模組化

APEX 有助於供應商映像上功能實現的自然捆綁和模組化。

當供應商映像建置為獨立建置的供應商 APEX 的組合時,設備製造商能夠輕鬆挑選和選擇其設備上所需的特定供應商實現。如果所提供的 APEX 都不符合製造商的需求,或者他們擁有全新的客製化硬件,製造商甚至可以創建新的供應商 APEX。

例如,OEM 可能選擇使用 AOSP wifi 實作 APEX、SoC 藍牙實作 APEX 和自訂 OEM 電話實作 APEX 來組合其裝置。

如果沒有供應商 APEX,供應商組件之間具有如此多依賴關係的實作需要仔細協調和追蹤。透過將所有元件(包括設定檔和額外函式庫)包裝在 APEX 中,並在跨功能通訊的任何點上具有明確定義的接口,不同的元件就可以互換。

開發者迭代

供應商 APEX 透過將整個功能實作(例如 wifi 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 依賴項的穩定本機介麵包括具有stubs cc_libraryndk_libraryllndk_library 。這些依賴項會從打包中排除,並且依賴項記錄在 APEX 清單中。清單由linkerconfig處理,以便外部本機相依性在執行時可用。

/system分割區中的 APEX 不同,供應商 APEX 通常與特定的 VNDK 版本相關聯。 VNDK 庫保證版本內的 ABI 穩定性,因此我們可以將 VNDK 庫視為穩定庫,並透過使用use_vndk_as_stable屬性將其從 APEX 中排除來減少供應商 APEX 的大小。

在下面的程式碼片段中,APEX 將包含二進位檔案 ( my_service ) 及其不穩定的依賴項 ( *.so檔案)。即使my_service是使用libbase等 VNDK 庫建構的,它也不會包含 VNDK 庫。相反,在執行時間my_service將使用系統提供的 VNDK 庫中的libbase

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  binaries: ["my_service"],
  ..
}

在下面的程式碼片段中,APEX 將包含共用程式庫my_standalone_lib及其任何不穩定依賴項(如上所述)。

apex {
  ..
  vendor: true,
  use_vndk_as_stable: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

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",
}

初始化腳本

APEX 可以透過兩種方式包含初始化腳本:(A) APEX 有效負載中的預先建置文字文件,或 (B) /vendor/etc中的常規初始化腳本。您可以將兩者設定為相同的 APEX。

APEX 中的初始化腳本:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

APEX 中的初始化腳本只能有service定義。供應商 APEX 中的初始化腳本也可以有on <property>指令。

使用on指令時要小心。由於APEX中的init腳本是在APEX啟動解析並執行的,因此某些事件或屬性無法使用。使用apex.all.ready=true儘早觸發操作。

韌體

例子:

使用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

內核模組必須明確安裝。供應商分區中的以下範例 init 腳本顯示了透過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 內預先建置的文件,並且正在新增更多設定檔。

例子:

額外的開發功能

啟動時選擇 APEX

例子:

開發人員還可以安裝共享相同 APEX 名稱和金鑰的多個版本的供應商 APEX,然後使用持久性 sysprops 選擇在每次啟動期間啟動哪個版本。對於某些開發人員用例,這可能比使用adb install安裝 APEX 的新副本更簡單。

範例用例:

  • 安裝 3 個版本的 wifi HAL 供應商 APEX: QA 團隊可以使用一個版本執行手動或自動測試,然後重新啟動到另一個版本並重新執行測試,然後比較最終結果。
  • 安裝相機 HAL 供應商 APEX 的 2 個版本,當前版本實驗版本 Dogfooders 可以使用實驗版本,而無需下載和安裝附加文件,因此他們可以輕鬆換回。

在啟動過程中, apexd會依照特定格式尋找 sysprops,以啟動正確的 APEX 版本。

屬性鍵的預期格式為:

  • 啟動配置
    • 用於設定預設值,在BoardConfig.mk
    • androidboot.vendor.apex.<apex name>
  • 持久性 sysprop
    • 用於變更在已啟動的裝置上設定的預設值。
    • 覆寫 bootconfig 值(如果存在)。
    • 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中的 bootconfig 進行設定:

# 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;

如果裝置支援在刷新後更新 bootconfig(例如透過fastboot oem指令),則變更多重安裝 APEX 的 bootconfig 屬性也會變更啟動時啟動的版本。

對於基於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";