Google is committed to advancing racial equity for Black communities. See how.
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

VNDK構建系統支持

在Android 8.1及更高版本中,構建系統具有內置的VNDK支持。啟用VNDK支持後,構建系統將檢查模塊之間的依賴性,為供應商模塊構建特定於供應商的變體,並將這些模塊自動安裝到指定目錄中。

VNDK構建支持示例

在此示例中, Android.bp模塊定義定義了一個名為libexample的庫。 vendor_available屬性指示框架模塊和供應商模塊可能取決於libexample

libexample vendor_available:true和vndk.enabled:true

圖1.啟用VNDK支持

框架可執行文件/system/bin/foo和供應商可執行文件/vendor/bin/bar依賴於libexamplelibexampleshared_libs屬性中具有libexample

如果框架模塊和供應商模塊都使用libexamplelibexample構建libexample兩個變體。核心變體(以libexample命名)由框架模塊使用,而賣方變體(以libexample.vendor命名)由賣方模塊使用。這兩個變量安裝在不同的目錄中:

  • 核心變體安裝在/system/lib[64]/libexample.so
  • 由於vndk.enabledtrue因此將供應商變體安裝到VNDK APEX中。

有關更多詳細信息,請參見模塊定義

配置構建支持

要為產品設備啟用完全構建系統支持,請將BOARD_VNDK_VERSION添加到BoardConfig.mk

BOARD_VNDK_VERSION := current

此設置具有全局作用:在BoardConfig.mk定義時,將檢查所有模塊。由於沒有將違規模塊列入黑名單或白名單的機制,因此您應在添加BOARD_VNDK_VERSION之前清除所有不必要的依賴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_libsstatic_libs和/或shared_libs指定依賴header_libs

VNDK APEX

在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}

VNDK APEX

圖2. VNDK APEX

模塊定義

要使用BOARD_VNDK_VERSION構建Android,必須在Android.mkAndroid.bp修改模塊定義。本節介紹了各種類型的模塊定義,與VNDK相關的一些模塊屬性以及在構建系統中實現的依賴項檢查。

供應商模塊

供應商模塊是特定於供應商的可執行文件或共享庫,必須將其安裝到供應商分區中。在Android.bp文件中,供應商模塊必須將供應商或專有屬性設置為true 。在Android.mk文件中,供應商模塊必須將LOCAL_VENDOR_MODULELOCAL_PROPRIETARY_MODULE設置為true

如果定義了BOARD_VNDK_VERSION ,則在以下情況下,構建系統將禁止供應商模塊和框架模塊之間的依賴關係並產生錯誤:

  • 沒有vendor:true的模塊取決於帶有vendor:true的模塊,或者
  • 具有vendor:true的模塊依賴於既不具有vendor:true也不具有vendor_available:true的非llndk_library模塊。

依賴檢查適用於header_libsstatic_libsshared_libsAndroid.bp ,並LOCAL_HEADER_LIBRARIESLOCAL_STATIC_LIBRARIESLOCAL_SHARED_LIBRARIESAndroid.mk

LL-NDK

LL-NDK共享庫是具有穩定ABI的共享庫。框架和供應商模塊都共享相同的最新實現。對於每個LL-NDK共享庫, Android.bp包含一個llndk_library模塊定義:

llndk_library {
    name: "libvndksupport",
    symbol_file: "libvndksupport.map.txt",
}

該模塊定義指定模塊名稱和符號文件,該文件描述了供應商模塊可見的符號。例如:

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

基於符號文件,構建系統為供應商模塊生成存根共享庫,當啟用BOARD_VNDK_VERSION時,該存根共享庫將與這些庫鏈接。僅在存根共享庫中包含符號:

  • _PRIVATE_PLATFORM結尾的部分中_PLATFORM
  • 沒有#platform-only標記,並且
  • 沒有#introduce #introduce*標籤或標籤與目標匹配。

越南盾

Android.bp文件中, cc_librarycc_library_staticcc_library_sharedcc_library_headers模塊定義支持三個與VNDK相關的屬性: vendor_availablevndk.enabledvndk.support_system_process

如果vendor_availablevndk.enabledtrue ,則可以構建兩個變體( corevendor )。核心變體應被視為框架模塊,供應商變體應被視為供應商模塊。如果某些框架模塊依賴於此模塊,則將構建核心變體。如果某些供應商模塊依賴於此模塊,則會構建供應商變體。構建系統強制執行以下依賴項檢查:

  • 核心變體始終僅是框架,並且供應商模塊無法訪問。
  • 供應商變體始終是框架模塊無法訪問的。
  • header_libsstatic_libs和/或shared_libs中指定的vendor變體的所有依賴項必須是llndk_library或具有vendor_availablevndk.enabled的模塊。
  • 如果vendor_availabletrue ,則所有賣方模塊均可訪問賣方變體。
  • 如果vendor_availablefalse ,則僅其他VNDK或VNDK-SP模塊可訪問vendor變體(即,具有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} )中。

下表總結了構建系統如何處理供應商變體:

vendor_available VNDK
已啟用
VNDK
support_same_process
供應商變體說明
true false false 供應商的變體是VND-ONLY 。共享庫安裝在/vendor/lib[64]
true 無效 (構建錯誤)
true false 供應商的變體是VNDK 。共享庫已安裝到VNDK APEX。
true 供應商的變體是VNDK-SP 。共享庫已安裝到VNDK APEX。

false

false

false

沒有供應商的變體。該模塊僅FWK

true 無效 (構建錯誤)
true false 供應商的變體是VNDK-Private 。共享庫已安裝到VNDK APEX。這些不得由供應商模塊直接使用。
true 供應商的變體是VNDK-SP-Private 。共享庫已安裝到VNDK APEX。這些不得由供應商模塊直接使用。

VNDK擴展

VNDK擴展是帶有其他API的VNDK共享庫。擴展安裝到/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共享庫名稱(或VNDK-SP共享庫名稱)。
  • VNDK擴展名(或VNDK-SP擴展名)以擴展它們的基礎模塊名稱命名。例如, libvndk_ext的輸出二進製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,則該模塊必須在其shared_libs屬性中指定VNDK擴展的名稱:

// 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構建系統為供應商變體和VNDK擴展定義了__ANDROID_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 。的cflagscppflags中指定target.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供應商變體VNDK擴展的ABI與prebuilts/abi-dumps/vndk下的參考ABI轉儲進行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_onlylibbothlibexample_cond_exclude的供應商變體libexample_cond_exclude包含來自both.c的代碼,因為fwk.cexclude_srcs屬性排除。同樣,它僅依賴於共享庫libboth因為libfwk_onlyexclude_shared_libs屬性排除。

從VNDK擴展導出頭

VNDK擴展可能會向VNDK共享庫添加新的類或新功能。建議將這些聲明保留在獨立的標頭中,並避免更改現有的標頭。

例如,為VNDK擴展libexample_ext創建了一個新的頭文件include-ext/example/ext/feature_name.h

  • Android.bp
  • include-ext / example / ext / feature_name.h
  • 包括/示例/ example.h
  • src / example.c
  • src / ext / feature_name.c

在以下Android.bplibexample導出僅include ,而libexample_ext導出同時includeinclude-ext 。這樣可以確保libexample的用戶不會錯誤地包含feature_name.h

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_

一個cc_defaults命名libexample2_ext_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的用戶可以在其defaults屬性中僅包含libexample2_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.vendor添加到PRODUCT_PACKAGES

PRODUCT_PACKAGES += libexample.vendor