VNDK 建構系統支援

在 Android 8.1 以上版本中,建構系統內建 VNDK 支援功能。時間 已啟用 VNDK 支援,建構系統會檢查 模組,為供應商模組建構供應商專屬的變化版本 這些模組會自動安裝到指定的目錄。

VNDK 版本支援範例

在這個範例中,Android.bp 模組定義定義了 名為 libexample 的程式庫。vendor_available 屬性代表架構模組和供應商模組可能會依賴 libexample

libexampleVendor_available:true 和 vndk.enabled:true

圖 1. 支援已啟用。

架構可執行 /system/bin/foo 和供應商 可執行檔的 /vendor/bin/bar 依附於 libexampleshared_libs 屬性中使用 libexample

如果架構模組和供應商都使用 libexample 模組,即建構兩個 libexample 的變化版本。核心變化版本 (以 libexample 命名) 由架構模組和 供應商使用供應商子類 (以 libexample.vendor 命名) 模組。這兩個變化版本會安裝至不同的目錄:

  • 核心變化版本的安裝位置 /system/lib[64]/libexample.so
  • 供應商子類已安裝至 VNDK APEX,因為 vndk.enabledtrue

詳情請參閱「模組定義」。

設定建構支援

如要啟用產品裝置的完整建構系統支援,請新增 BOARD_VNDK_VERSIONBoardConfig.mk

BOARD_VNDK_VERSION := current

這項設定具有「全域」效果:如果在 BoardConfig.mk,所有模組皆已勾選。我們並未提供機制 將違規的模組加入黑名單或加入許可清單, 加入 BOARD_VNDK_VERSION 之前不需要的依附元件。個人中心 只要在BOARD_VNDK_VERSION 環境變數:

$ BOARD_VNDK_VERSION=current m module_name.vendor

啟用 BOARD_VNDK_VERSION 時,會有多個預設全域通用 標頭搜尋路徑會「移除」。其中包括:

  • frameworks/av/include
  • frameworks/native/include
  • frameworks/native/opengl/include
  • hardware/libhardware/include
  • hardware/libhardware_legacy/include
  • hardware/ril/include
  • libnativehelper/include
  • libnativehelper/include_deprecated
  • system/core/include
  • system/media/audio/include

如果模組依附於這些目錄的標頭,您必須指定 (明確) 使用 header_libs 建立依附元件。 static_libs 和/或 shared_libs

越南盾

在 Android 10 以下版本中,已安裝 vndk.enabled 的模組 /system/lib[64]/vndk[-sp]-${VER}。在 Android 11 以上版本中, VNDK 程式庫以 APEX 格式封裝,VNDK APEX 的名稱為 com.android.vndk.v${VER}。視裝置設定而定 VNDK APEX 採用整併未整併的形式,且可從標準路徑取得 /apex/com.android.vndk.v${VER}

越南盾

圖 2. VNDK APEX。

模組定義

如要使用 BOARD_VNDK_VERSION 建構 Android,您必須修改 Android.mkAndroid.bp。本節說明不同類型的模組 定義、多個 VNDK 相關模組屬性,以及依附元件檢查 建構系統

供應商模組

供應商模組是供應商專屬的執行檔或共用程式庫, 必須安裝到供應商分區中。在 Android.bp 個檔案中, 供應商模組必須將供應商或專屬屬性設為「true」。 在 Android.mk 檔案中,必須設定供應商模組 LOCAL_VENDOR_MODULELOCAL_PROPRIETARY_MODULEtrue

如果已定義 BOARD_VNDK_VERSION,建構系統會禁止 供應商模組與架構模組之間的依附元件,且在下列情況中會發出錯誤:

  • 沒有 vendor:true 的模組依附於含有 vendor:true,或
  • 包含 vendor:true 的模組依附於 非 llndk_library 模組 vendor:true,或 vendor_available:true

依附元件檢查適用於 header_libsstatic_libs,和 shared_libs 英寸 Android.bpLOCAL_HEADER_LIBRARIESLOCAL_STATIC_LIBRARIESLOCAL_SHARED_LIBRARIES 英寸 Android.mk

LL-NDK

LL-NDK 共用程式庫是採用穩定 ABI 的共用程式庫。兩個架構 和供應商模組共用最新實作項目。對於每項 LL-NDK 共用資料庫,cc_library 中會包含 含有符號檔案的 llndk 屬性:

cc_library {
    name: "libvndksupport",
    llndk: {
        symbol_file: "libvndksupport.map.txt",
    },
}

符號檔案說明供應商模組可以看見的符號。例如:

LIBVNDKSUPPORT {
  global:
    android_load_sphal_library; # llndk
    android_unload_sphal_library; # llndk
  local:
    *;
};

建構系統會根據符號檔案,為 以及這些程式庫模組 已啟用「BOARD_VNDK_VERSION」。虛設常式包含符號 共用程式庫的條件:

  • 未在該部分中以 _PRIVATE_PLATFORM,
  • 不含 #platform-only 標記,且
  • 沒有 #introduce* 標記或是與 目標。
,瞭解如何調查及移除這項存取權。

越南盾

Android.bp 個檔案 (cc_library) 中, cc_library_staticcc_library_sharedcc_library_headers 模組定義支援三個 VNDK 相關 屬性:vendor_availablevndk.enabledvndk.support_system_process

如果 vendor_availablevndk.enabledtrue,兩個變體 (核心供應商) 可能是 。核心變化版本應視為架構模組和廠商 變數應視為供應商模組。如果部分架構模組 核心變數是由這個單元建構而成如果某些供應商模組 必須建構供應商變化版本建構系統會強制執行 下列依附元件檢查:

  • 核心變化版本一律僅限架構,供應商無法存取 模組。
  • 架構模組一律無法存取供應商變化版本。
  • 供應商子類的所有依附元件, header_libsstatic_libs 和/或 shared_libs,必須是 llndk_libraryvendor_availablevndk.enabled 模組。
  • 如果 vendor_availabletrue,就是供應商子類 所有供應商模組均可存取。
  • 如果 vendor_availablefalse,就是供應商子類 只能供其他 VNDK 或 VNDK-SP 模組存取 (也就是說 vendor:true 無法連結 vendor_available:false 模組)。

cc_librarycc_library_shared 取決於下列規則:

  • 核心變化版本會安裝至 /system/lib[64]
  • 供應商變化版本的安裝路徑可能有所不同:
    • 如果 vndk.enabledfalse,就是供應商子類 已安裝至 /vendor/lib[64]
    • 如果 vndk.enabledtrue,就是供應商子類 已安裝至 VNDK APEX(com.android.vndk.v${VER})。

下表摘要說明建構系統如何處理供應商變化版本:

供應商可使用 已啟用
vndk
vndk
support_same_process
供應商變化版本說明
true false false 供應商子類僅限 VND。共用程式庫是 已安裝至 /vendor/lib[64]
true 無效 (建構錯誤)
true false 供應商子類為 VNDK。已安裝共用程式庫 變更為 VNDK APEX。
true 供應商子類為 VNDK-SP。共用程式庫是 已安裝至 VNDK APEX。

false

false

false

沒有供應商子類。本單元僅適用於

true 無效 (建構錯誤)
true false 供應商子類為 VNDK-Private。共用程式庫是 已安裝至 VNDK APEX。不得出現 方便供應商模組直接使用
true 供應商子類為 VNDK-SP-Private。共用程式庫是 已安裝至 VNDK APEX。不得出現 方便供應商模組直接使用

VNDK 擴充功能

VNDK 擴充功能是 VNDK 共用程式庫與其他 API。副檔名是 已安裝至 /vendor/lib[64]/vndk[-sp] (沒有版本後置字串) 並在執行階段覆寫原始 VNDK 共用程式庫

定義 VNDK 擴充功能

在 Android 9 以上版本中,Android.bp 原生支援 VNDK 。如要建構 VNDK 擴充功能,請使用 vendor:trueextends 屬性:

cc_library {
    name: "libvndk",
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
}

具有 vendor:truevndk.enabled:trueextends 屬性會定義 VNDK 擴充功能:

  • extends 屬性必須指定基礎 VNDK 共用資料庫 name (或 VNDK-SP 共用程式庫名稱),
  • VNDK 擴充功能 (或 VNDK-SP 擴充功能) 是以基本模組命名 從擴充到擴充的另一個名稱例如, libvndk_extlibvndk.so,而不是 libvndk_ext.so
  • VNDK 擴充功能已安裝至 /vendor/lib[64]/vndk
  • VNDK-SP 擴充功能已安裝至 /vendor/lib[64]/vndk-sp
  • 基本共用程式庫必須同時包含 vndk.enabled:truevendor_available:true

VNDK-SP 擴充功能必須從 VNDK-SP 共用資料庫擴充 (vndk.support_system_process 必須相等):

cc_library {
    name: "libvndk_sp",
    vendor_available: true,
    vndk: {
        enabled: true,
        support_system_process: true,
    },
}

cc_library {
    name: "libvndk_sp_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk_sp",
        support_system_process: true,
    },
}

VNDK 擴充功能 (或 VNDK-SP 擴充功能) 可能會依附於其他供應商共用 程式庫:

cc_library {
    name: "libvndk",
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
    shared_libs: [
        "libvendor",
    ],
}

cc_library {
    name: "libvendor",
    vendor: true,
}

使用 VNDK 擴充功能

如果供應商模組依賴 VNDK 擴充功能定義的其他 API, 模組必須在其依附元件中指定 VNDK 擴充功能的名稱 shared_libs 屬性:

// A vendor shared library example
cc_library {
    name: "libvendor",
    vendor: true,
    shared_libs: [
        "libvndk_ext",
    ],
}

// A vendor executable example
cc_binary {
    name: "vendor-example",
    vendor: true,
    shared_libs: [
        "libvndk_ext",
    ],
}

如果供應商模組需要使用 VNDK 擴充功能,則這些 VNDK 擴充功能 已自動安裝至「/vendor/lib[64]/vndk[-sp]」。如果模組 不再需要使用 VNDK 擴充功能,請將簡潔的步驟加入 CleanSpec.mk即可移除共用資料庫。例如:

$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)

條件編譯

本節說明如何處理細微差異 (例如 在其中一個變化版本中加入或移除特徵), 三個 VNDK 共用程式庫:

  • 核心變化版本 (例如 /system/lib[64]/libexample.so)
  • 供應商子類 (例如 /apex/com.android.vndk.v${VER}/lib[64]/libexample.so)
  • VNDK 擴充功能 (例如 /vendor/lib[64]/vndk[-sp]/libexample.so)

條件編譯器標記

Android 建構系統為供應商定義 __ANDROID_VNDK__ 和 VNDK 擴充功能。你可以保護密碼 兩邊的 C 前置處理器防護:

void all() { }

#if !defined(__ANDROID_VNDK__)
void framework_only() { }
#endif

#if defined(__ANDROID_VNDK__)
void vndk_only() { }
#endif

除了 __ANDROID_VNDK__ 之外,其他 cflagscppflags可在「Android.bp」中指定。 已在以下位置指定 cflagscppflagstarget.vendor 是供應商子類專用,

舉例來說,下列 Android.bp 定義 libexamplelibexample_ext

cc_library {
    name: "libexample",
    srcs: ["src/example.c"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
    target: {
        vendor: {
            cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"],
        },
    },
}

cc_library {
    name: "libexample_ext",
    srcs: ["src/example.c"],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample",
    },
    cflags: [
        "-DLIBEXAMPLE_ENABLE_VNDK=1",
        "-DLIBEXAMPLE_ENABLE_VNDK_EXT=1",
    ],
}

以下是 src/example.c 的程式碼清單:

void all() { }

#if !defined(LIBEXAMPLE_ENABLE_VNDK)
void framework_only() { }
#endif

#if defined(LIBEXAMPLE_ENABLE_VNDK)
void vndk() { }
#endif

#if defined(LIBEXAMPLE_ENABLE_VNDK_EXT)
void vndk_ext() { }
#endif

根據這兩個檔案,建構系統會產生共用程式庫 包含下列匯出符號:

安裝路徑 已匯出的符號
/system/lib[64]/libexample.so allframework_only
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so allvndk
/vendor/lib[64]/vndk/libexample.so allvndkvndk_ext

匯出符號相關規定

VNDK ABI 檢查工具 比較 VNDK 供應商變體的 ABI,以及 可對參照 ABI 傾印的參考 ABI 傾印的 VNDK 擴充功能 prebuilts/abi-dumps/vndk

  • VNDK 供應商變化版本匯出的符號 (例如 /apex/com.android.vndk.v${VER}/lib[64]/libexample.so) 必須相同 傳遞至 ABI 傾印中定義的符號 (非 的超集)。
  • VNDK 擴充功能 (例如 /vendor/lib[64]/vndk/libexample.so) 必須是 代表 ABI 傾印中定義的符號。

如果 VNDK 供應商變體VNDK 擴充功能不符合規定 ,VNDK ABI 檢查工具會發出建構錯誤並停止 建構應用程式

從供應商變數中排除來源檔案或共用資料庫

如要從供應商子類排除來源檔案,請將該檔案新增到 exclude_srcs 屬性。同樣地,確保共用程式庫 請將這些程式庫加入 exclude_shared_libs 屬性。例如:

cc_library {
    name: "libexample_cond_exclude",
    srcs: ["fwk.c", "both.c"],
    shared_libs: ["libfwk_only", "libboth"],
    vendor_available: true,
    target: {
        vendor: {
            exclude_srcs: ["fwk.c"],
            exclude_shared_libs: ["libfwk_only"],
        },
    },
}

在這個範例中,libexample_cond_exclude 的核心變化版本 包含 fwk.cboth.c 的程式碼,且取決於 共用程式庫 libfwk_onlylibboth libexample_cond_exclude 的供應商子類只包含程式碼 從 both.c 排除,因為 fwk.c 已被排除 exclude_srcs 屬性。同樣地,這只取決於共用資料庫 libboth,因為libfwk_only被排除 exclude_shared_libs 屬性。

從 VNDK 擴充功能匯出標頭

VNDK 擴充功能可能會新增類別或新函式至 VNDK 共用 資源庫。建議將這些宣告保留在獨立的標頭中 並避免變更現有的標頭

例如:新的標頭檔案 已為 VNDK 建立 include-ext/example/ext/feature_name.h 擴充功能 libexample_ext

  • Android.bp
  • include-ext/example/ext/feature_name.h
  • include/example/example.h
  • src/example.c
  • src/ext/feature_name.c

在下列Android.bp中,有 libexample 個匯出項目 僅限 includelibexample_ext 則會匯出兩者 includeinclude-ext。這可以確保 系統將不會誤將「feature_name.hlibexample

cc_library {
    name: "libexample",
    srcs: ["src/example.c"],
    export_include_dirs: ["include"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libexample_ext",
    srcs: [
        "src/example.c",
        "src/ext/feature_name.c",
    ],
    export_include_dirs: [
        "include",
        "include-ext",
    ],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample",
    },
}

如果無法將副檔名與獨立的標頭檔案分開, 另一種方式是新增 #ifdef 守衛不過, VNDK 擴充功能使用者新增定義標記。您可以定義 cc_defaults:在 cflags 和連結中新增定義標記 與 shared_libs 共用程式庫。

例如,如要將新成員函式 Example2::get_b() 新增至 VNDK 擴充功能 libexample2_ext,您必須修改現有的 標頭檔案,並新增 #ifdef 防護機制:

#ifndef LIBEXAMPLE2_EXAMPLE_H_
#define LIBEXAMPLE2_EXAMPLE_H_

class Example2 {
 public:
  Example2();

  void get_a();

#ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT
  void get_b();
#endif

 private:
  void *impl_;
};

#endif  // LIBEXAMPLE2_EXAMPLE_H_

名為 libexample2_ext_defaultscc_defaults 已 為 libexample2_ext 的使用者定義:

cc_library {
    name: "libexample2",
    srcs: ["src/example2.cpp"],
    export_include_dirs: ["include"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libexample2_ext",
    srcs: ["src/example2.cpp"],
    export_include_dirs: ["include"],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample2",
    },
    cflags: [
        "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1",
    ],
}

cc_defaults {
    name: "libexample2_ext_defaults",
    shared_libs: [
        "libexample2_ext",
    ],
    cflags: [
        "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1",
    ],
}

libexample2_ext 的使用者可能只需包括 defaultslibexample2_ext_defaults 資源:

cc_binary {
    name: "example2_user_executable",
    defaults: ["libexample2_ext_defaults"],
    vendor: true,
}

產品套件

在 Android 建構系統中,PRODUCT_PACKAGES 變數 會指明應當根據 安裝到裝置上。指定的指定依附元件 模組同樣也會自動安裝到裝置上

如果啟用 BOARD_VNDK_VERSION,則含有 vendor_availablevndk.enabled可享特別優惠 治療方式,如果架構模組依附於含有 vendor_availablevndk.enabled,核心變化版本 包含在遞移安裝組中。如果供應商模組 依附於包含 vendor_available 的模組,供應商變數會是 包含在遞移安裝組中。不過,模組的供應商變化版本 無論是否由供應商模組使用,vndk.enabled 都會安裝。

在建構系統看不到依附元件時 (例如共用程式庫) 通常可在執行階段中使用 dlopen() 開啟),因此您需要指定 PRODUCT_PACKAGES 中的模組名稱以安裝這些模組 。

如果模組有 vendor_availablevndk.enabled 模組名稱代表其核心變化版本。如要明確指定 PRODUCT_PACKAGES 中的供應商子類,附加 .vendor 新增至模組名稱。例如:

cc_library {
    name: "libexample",
    srcs: ["example.c"],
    vendor_available: true,
}

在這個範例中,libexample 代表 /system/lib[64]/libexample.solibexample.vendor 代表 /vendor/lib[64]/libexample.so。如何安裝 /vendor/lib[64]/libexample.so,新增libexample.vendorPRODUCT_PACKAGES

PRODUCT_PACKAGES += libexample.vendor