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

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

淘汰

Android 8.0 推出供應商 NDK,在架構和供應商程式碼之間提供 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 APEX (VNDK 版本為 14 以下),支援現有供應商映像檔時需要用到。
  • LL-NDK 不屬於 VNDK。

為什麼要使用 VNDK?

AOSP 允許僅更新架構,也就是將系統分割區升級至最新架構版本,同時保留供應商分割區不變。儘管是在不同時間建構,每個分區中的二進位檔都必須能夠彼此搭配運作。

僅更新架構會遇到下列挑戰:

  • 架構模組和供應商模組之間的依附元件。在 Android 8.0 之前,供應商和系統分割區中的模組可以互相連結。不過,供應商模組的依附元件對架構模組開發造成不必要的限制。
  • Android 開放原始碼計畫程式庫的擴充功能。Android 規定所有 Android 裝置在系統分區替換為標準通用系統映像檔 (GSI) 時,都必須通過 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. 複製舊架構共用程式庫。並嚴格限制側邊通道,也就是架構模組和供應商模組之間的所有通訊機制,包括 (但不限於) 繫結器、插座、管道、共用記憶體、共用檔案和系統屬性。除非通訊協定已凍結且穩定 (例如透過 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-ONLY) 是不屬於上述類別的架構共用程式庫。這些程式庫:
    • 視為架構內部實作詳細資料。
    • 供應商模組不得存取。
    • 具有不穩定的 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 程式庫重複載入架構程序時不會發生問題。SP-HAL 和 VNDK-SP 都是由 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-HAL 看不到這些程式庫。

以下是僅限架構的程式庫,但有 RS 例外狀況 (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 程式庫資料集。