在Android 8.1及更高版本中,構建系統具有內置的VNDK支持。啟用VNDK支持後,構建系統將檢查模塊之間的依賴性,為供應商模塊構建特定於供應商的變體,並將這些模塊自動安裝到指定目錄中。
VNDK構建支持示例
在此示例中, Android.bp
模塊定義定義了一個名為libexample
的庫。 vendor_available
屬性指示框架模塊和供應商模塊可能取決於libexample
:
框架可執行文件/system/bin/foo
和供應商可執行文件/vendor/bin/bar
依賴於libexample
, libexample
在shared_libs
屬性中具有libexample
。
如果框架模塊和供應商模塊都使用libexample
, libexample
構建libexample
兩個變體。框架模塊使用core變體(以libexample
命名),vendor變體(以libexample.vendor
命名)由供應商模塊使用。這兩個變量安裝在不同的目錄中:
- 核心變體安裝在
/system/lib[64]/libexample.so
。 - 由於
vndk.enabled
為true
因此將供應商變體安裝到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_libs
, static_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}
模塊定義
要使用BOARD_VNDK_VERSION
構建Android,必須在Android.mk
或Android.bp
修改模塊定義。本節描述了各種類型的模塊定義,與VNDK相關的一些模塊屬性以及在構建系統中實現的依賴項檢查。
供應商模塊
供應商模塊是特定於供應商的可執行文件或共享庫,必須將其安裝到供應商分區中。在Android.bp
文件中,供應商模塊必須將供應商或專有屬性設置為true
。在Android.mk
文件中,供應商模塊必須將LOCAL_VENDOR_MODULE
或LOCAL_PROPRIETARY_MODULE
設置為true
。
如果定義了BOARD_VNDK_VERSION
,則在以下情況下,構建系統將禁止供應商模塊和框架模塊之間的依賴關係並產生錯誤:
- 沒有
vendor:true
的模塊取決於帶有vendor:true
的模塊,或者 - 具有
vendor:true
的模塊依賴於既不具有vendor:true
也不具有vendor_available:true
的非llndk_library
模塊。
依賴檢查適用於header_libs
, static_libs
和shared_libs
在Android.bp
,並LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
和LOCAL_SHARED_LIBRARIES
在Android.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; # llndk android_unload_sphal_library; # llndk local: *; };
基於符號文件,構建系統將為供應商模塊生成存根共享庫,當啟用BOARD_VNDK_VERSION
時,該存根共享庫將與這些庫鏈接。僅在存根共享庫中包含符號:
- 在
_PRIVATE
或_PLATFORM
結尾的部分中_PLATFORM
, - 沒有
#platform-only
標記,並且 - 沒有#introduce
#introduce*
標籤或標籤與目標匹配。
越南盾
在Android.bp
文件中, cc_library
, cc_library_static
, cc_library_shared
和cc_library_headers
模塊定義支持三個與VNDK相關的屬性: vendor_available
, vndk.enabled
和vndk.support_system_process
。
如果vendor_available
或vndk.enabled
為true
,則可以構建兩個變體( core和vendor )。核心變體應被視為框架模塊,而供應商變體應被視為供應商模塊。如果某些框架模塊依賴於此模塊,則將構建核心變體。如果某些供應商模塊依賴於此模塊,則會構建供應商變體。構建系統強制執行以下依賴項檢查:
- 核心變體始終僅是框架,並且供應商模塊無法訪問。
- 供應商變體始終是框架模塊無法訪問的。
- 在
header_libs
,static_libs
和/或shared_libs
中指定的vendor變體的所有依賴關係都必須是llndk_library
或具有vendor_available
或vndk.enabled
的模塊。 - 如果
vendor_available
為true
,則所有賣方模塊均可訪問賣方變體。 - 如果
vendor_available
為false
,則僅其他VNDK或VNDK-SP模塊可訪問vendor變體(即,具有vendor:true
模塊無法鏈接vendor_available:false
模塊)。
cc_library
或cc_library_shared
的默認安裝路徑由以下規則確定:
- 核心版本已安裝到
/system/lib[64]
。 - 供應商變體安裝路徑可能會有所不同:
- 如果
vndk.enabled
為false
,則將供應商變體安裝到/vendor/lib[64]
。 - 如果
vndk.enabled
為true
,則將供應商變體安裝到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。 | ||
| | | 沒有供應商的變體。該模塊僅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:true
和extends
屬性的模塊:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
具有vendor:true
, vndk.enabled:true
並extends
屬性的模塊定義了VNDK擴展:
-
extends
屬性必須指定基本的VNDK共享庫名稱(或VNDK-SP共享庫名稱)。 - VNDK擴展名(或VNDK-SP擴展名)以擴展它們的基礎模塊名稱命名。例如,
libvndk_ext
的輸出二進製libvndk_ext
是libvndk.so
而不是libvndk_ext.so
。 - VNDK擴展已安裝到
/vendor/lib[64]/vndk
。 - VNDK-SP擴展已安裝到
/vendor/lib[64]/vndk-sp
。 - 基本共享庫必須同時具有
vndk.enabled:true
和vendor_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__
,不同cflags
或cppflags
可以指定Android.bp
。的cflags
或cppflags
中指定target.vendor
是特定於供應商的變體。
例如,以下Android.bp
定義了libexample
和libexample_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 | all , framework_only |
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so | all , vndk |
/vendor/lib[64]/vndk/libexample.so | all , vndk , vndk_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.c
和both.c
的代碼,並取決於共享庫libfwk_only
和libboth
。 libexample_cond_exclude
的供應商變體libexample_cond_exclude
包含來自both.c
的代碼,因為fwk.c
被exclude_srcs
屬性排除。同樣,它僅依賴共享庫libboth
因為libfwk_only
被exclude_shared_libs
屬性排除。
從VNDK擴展導出頭
VNDK擴展可能會向VNDK共享庫添加新的類或新功能。建議將這些聲明保留在獨立的標頭中,並避免更改現有的標頭。
例如,為VNDK擴展libexample_ext
創建了一個新的頭文件include-ext/example/ext/feature_name.h
:
- Android.bp
- include-ext / example / ext / feature_name.h
- include / example / example.h
- src / example.c
- src / ext / feature_name.c
在以下Android.bp
, libexample
導出僅include
,而libexample_ext
導出同時include
和include-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_available
或vndk.enabled
得到特殊待遇。如果框架模塊依賴於具有vendor_available
或vndk.enabled
的模塊,則核心變體將包含在可傳遞安裝集中。如果供應商模塊依賴於帶有vendor_available
的模塊,則該供應商變體將包含在可傳遞安裝集中。但是,安裝了帶有vndk.enabled
的模塊的供應商變體,無論供應商模塊是否使用它們。
如果依賴關係對於構建系統不可見(例如,可以在運行時使用dlopen()
打開的共享庫),則應在PRODUCT_PACKAGES
指定模塊名稱以顯式安裝這些模塊。
如果模塊具有vendor_available
或vndk.enabled
,則模塊名稱代表其核心變量。要在PRODUCT_PACKAGES
顯式指定供應商變體,請在模塊名稱後附加.vendor
後綴。例如:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
在此示例中, libexample
代表/system/lib[64]/libexample.so
而libexample.vendor
代表/vendor/lib[64]/libexample.so
。要安裝/vendor/lib[64]/libexample.so
,請將libexample.vendor
添加到PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor