供應商原生開發套件 (VNDK) 總覽

供應商原生開發套件 (VNDK)是一組程式庫,可供供應商或產品分割區中的其他程式庫或二進位檔在 dlopen 的執行階段使用。

淘汰

供應商 NDK 是在 Android 8.0 中推出,用於在架構和供應商程式碼之間提供 API。雖然 VNDK 已成功使用多年,但仍有以下缺點:
  • 儲存空間
    • 單一 VNDK APEX 會封裝所有 VNDK 程式庫,無論是否會在裝置上使用。
    • GSI 包含多個版本的 VNDK APEX,可支援多個版本的供應商映像檔。
  • 可更新性
    • 很難單獨更新 VNDK APEX 和平台更新。
    • 供應商映像檔經常透過無線更新 (OTA) 方式更新,因此將 VNDK 封裝在系統映像檔中就失去優勢。
基於這些問題,我們決定從 Android 15 開始淘汰 VNDK。

VNDK 淘汰詳情

所有 VNDK 程式庫都會封裝至 VNDK APEX,並安裝在系統 (-ext) 映像檔中。隨著 VNDK 淘汰,舊版 VNDK 程式庫會與其他供應商提供的程式庫一樣,安裝在供應商 (或產品) 映像檔中。以下功能會隨 VNDK 淘汰而一併移除:
  • Android 15 適用的 VNDK APEX
  • 如果供應商或產品分區是針對 Android 15 建構,系統會移除指示目標 VNDK 版本的系統屬性:
    • ro.vndk.version
    • ro.product.vndk.version
  • 由於沒有 VNDK,因此無法使用 VNDK 最佳化功能:
    • TARGET_VNDK_USING_CORE_VARIANT (適用於 Android Go 裝置)
    • use_vndk_as_stable (適用於供應商 APEX)
  • 供應商快照,高度依賴 VNDK

淘汰作業的例外狀況

這些功能不會因 VNDK 淘汰而有所變更:
  • 使用 VNDK 14 以下版本的 VNDK APEX,以便支援現有的供應商映像檔。
  • LL-NDK 並非 VNDK 的一部分。

為什麼要使用 VNDK?

AOSP 允許僅針對架構更新,允許系統分區升級至最新架構版本,而供應商分區則維持不變。雖然各個分區的二進位檔是在不同時間建構,但各分區的二進位檔必須能夠相互運作。

僅更新架構會面臨下列挑戰:

  • 架構模組與供應商模組之間的依附元件。在 Android 8.0 之前,供應商和系統分區中的模組可以彼此連結。不過,供應商模組的依附元件會對架構模組開發造成不必要的限制。
  • 擴充 AOSP 程式庫。當系統分區換成標準通用系統映像檔 (GSI) 時,Android 會要求所有 Android 裝置通過 CTS。不過,由於供應商會擴充 AOSP 程式庫來提升效能,或為 HIDL 實作項目新增額外功能,因此使用標準 GSI 刷新系統分區,可能會導致供應商的 HIDL 實作項目無法正常運作。如需預防這類故障的指南,請參閱 VNDK 擴充功能

為解決這些問題,Android 包含多項功能,例如 VNDK (本節所述)、HIDL、hwbinder、裝置樹狀結構疊加層和 sepolicy 疊加層。

VNDK 專屬條款

VNDK 相關文件使用以下術語:
  • 「模組」是指共用程式庫或執行檔。模組可讓建構時間依附元件。
  • 程序是從可執行檔產生的作業系統工作。程序會建立執行階段依附元件。
  • 架構限定條件與 system 分區相關:
    • 「架構可執行檔」是指 /system/bin/system/xbin 中的可執行檔。
    • 架構共用程式庫是指 /system/lib[64] 底下的共用程式庫。
    • 架構模組是指架構共用程式庫和架構可執行檔。
    • 架構程序是指從架構執行檔產生的程序,例如 /system/bin/app_process
  • 供應商資格條款與 vendor 個分區相關:
    • 供應商可執行檔是指 /vendor/bin 中的可執行檔
    • 「供應商共用程式庫」是指 /vendor/lib[64] 底下的共用程式庫。
    • 供應商模組是指供應商執行檔和供應商共用程式庫。
    • 供應商程序是從供應商可執行檔 (例如 /vendor/bin/android.hardware.camera.provider@2.4-service) 衍生的程序。

VNDK 概念

在理想的 Android 8.0 以上版本中,架構程序不會載入供應商共用程式庫,所有供應商程序只會載入供應商共用程式庫 (以及部分架構共用程式庫),而且架構程序和供應商程序之間的通訊則受 HIDL 和硬體繫結器規範。

在這種情況下,供應商模組開發人員可能無法充分利用架構共用程式庫中的穩定公用 API (雖然 API 可能會在 Android 版本之間變更),因此需要讓供應商程序能夠存取部分架構共用程式庫。此外,由於效能要求可能導致遭駭,因此某些回應時的關鍵 HAL 都必須以不同方式處理。

以下各節將詳細說明 VNDK 如何處理供應商和相同程序 HAL (SP-HAL) 的架構共用程式庫。

供應商適用的架構共用程式庫

本節說明供應商程序可存取的共用程式庫分類標準。有兩種方法可在多個 Android 版本中支援供應商模組:

  1. 穩定處理架構共用程式庫的 ABI/API。新的架構模組和舊的供應商模組可以使用相同的共用程式庫,以減少記憶體占用空間和儲存空間大小。獨特的共用程式庫還可避免發生多重載入問題。不過,維持穩定 ABI/API 的開發成本很高,而且要讓每個架構共用程式庫匯出的所有 ABI/API 都穩定,也是不切實際的做法。
  2. 複製舊版架構共用程式庫。對側通道實施嚴格限制,側通道是指在架構模組和供應商模組之間進行通訊的所有機制,包括 (但不限於) 繫結器、Socket、管道、共用記憶體、共用檔案和系統屬性。除非通訊協定凍結且處於穩定狀態 (例如透過 hwbinder 使用 HIDL),否則不得進行通訊。重複載入共用程式庫也可能會造成問題;舉例來說,如果新程式庫建立的物件傳遞至舊程式庫的函式,可能會因為這些程式庫以不同方式解讀物件而發生錯誤。

視共用程式庫的特性而定,會採用不同的方法。因此,架構共用程式庫可分為三個子類別:

  • LL-NDK 程式庫是眾所周知的架構共用程式庫。開發人員致力於維持 API/ABI 穩定性。
    • LL-NDK 包含下列程式庫:libEGL.solibGLESv1_CM.solibGLESv2.solibGLESv3.solibandroid_net.solibc.solibdl.soliblog.solibm.solibnativewindow.solibneuralnetworks.solibsync.solibvndksupport.solibvulkan.so
  • 符合資格的 VNDK 程式庫 (VNDK)架構共用程式庫,可安全地複製兩次。架構模組供應商模組可以連結至各自的副本。架構共用資料庫必須符合下列條件,才能成為符合資格的 VNDK 程式庫:
    • 不會傳送/接收來自/至架構的 IPC。
    • 與 ART 虛擬機器無關。
    • 不會讀取/寫入採用不穩定的檔案格式的檔案/分區。
    • 沒有需要法律審查的特殊軟體授權。
    • 程式碼擁有者不會反對供應商的用途。
  • 僅限架構程式庫 (僅限 FWK)架構共用程式庫,但不屬於上述類別。這些程式庫:
    • 視為架構內部實作詳細資料。
    • 供應商模組不得存取。
    • 使用不穩定的 ABI/API,且沒有 API/ABI 相容性保證。
    • 不會複製。

相同程序 HAL (SP-HAL)

同一個程序 HAL (SP-HAL) 是一組預先決定的 HAL,以供應商共用程式庫的形式實作,並載入至架構程序。SP-HAL 會透過連結器命名空間 (控制共用程式庫可見的程式庫和符號) 進行隔離。SP-HAL 必須只依賴 LL-NDKVNDK-SP

VNDK-SP 是可用的 VNDK 程式庫的預先定義子集。我們會仔細審查 VNDK-SP 程式庫,確保將 VNDK-SP 程式庫加載至架構程序不會造成問題。這兩種 HAL 都是由 Google 定義。

以下程式庫已獲准成為 SP-HAL:

  • libGLESv1_CM_${driver}.so
  • libGLESv2_${driver}.so
  • libGLESv3_${driver}.so
  • libEGL_${driver}.so
  • vulkan.${driver}.so
  • android.hardware.renderscript@1.0-impl.so
  • android.hardware.graphics.mapper@2.0-impl.so

VNDK-SP 程式庫會在 Android.bp 檔案中指定 vndk: { support_system_process: true }。如果也指定 vndk: {private:true},則這些程式庫會稱為 VNDK-SP-Private,且對 SP-HALS 而言是不可見的。

以下是僅含 RS 例外的 Framework 專用程式庫 (FWK-ONLY-RS)

  • libft2.so (Renderscript)
  • libmediandk.so (Renderscript)

VNDK 版本管理

VNDK 共用程式庫會分為不同版本:

  • ro.vndk.version 系統屬性會自動新增至 /vendor/default.prop
  • VNDK 和 VNDK-SP 共用程式庫會以 VNDK apex com.android.vndk.v${ro.vndk.version} 安裝,並掛接至 /apex/com.android.vndk.v${ro.vndk.version}

ro.vndk.version 的值會由下列演算法選擇:

  • 如果 BOARD_VNDK_VERSION「不等於」current,請使用 BOARD_VNDK_VERSION
  • 如果 BOARD_VNDK_VERSION 等於 current
    • 如果 PLATFORM_VERSION_CODENAMEREL,請使用 PLATFORM_SDK_VERSION (例如 28)。
    • 否則,請使用 PLATFORM_VERSION_CODENAME (例如 P)。

供應商測試套件 (VTS)

Android 供應商測試套件 (VTS) 規定必須使用非空白的 ro.vndk.version 屬性。新啟動的裝置和升級裝置都必須定義 ro.vndk.version。部分 VNDK 測試案例 (例如 VtsVndkFilesTestVtsVndkDependencyTest) 需要使用 ro.vndk.version 屬性載入相符的 VNDK 程式庫資料集。