Trong Android 8.1 trở lên, hệ thống xây dựng đã tích hợp tính năng hỗ trợ VNDK. Khi bạn bật tính năng hỗ trợ VNDK, hệ thống xây dựng sẽ kiểm tra các phần phụ thuộc giữa các mô-đun, tạo một biến thể dành riêng cho nhà cung cấp cho các mô-đun của nhà cung cấp và tự động cài đặt các mô-đun đó vào các thư mục được chỉ định.
Ví dụ về tính năng hỗ trợ bản dựng VNDK
Trong ví dụ này, định nghĩa mô-đun Android.bp
sẽ xác định một thư viện có tên là libexample
. Thuộc tính vendor_available
cho biết các mô-đun khung và mô-đun nhà cung cấp có thể phụ thuộc vào libexample
:
Hình 1. đã bật tính năng hỗ trợ.
Cả /system/bin/foo
có thể thực thi khung và /vendor/bin/bar
có thể thực thi của nhà cung cấp đều phụ thuộc vào libexample
và có libexample
trong thuộc tính shared_libs
.
Nếu cả mô-đun khung và mô-đun nhà cung cấp đều sử dụng libexample
, thì hai biến thể của libexample
sẽ được tạo. Biến thể cốt lõi (được đặt tên theo libexample
) được các mô-đun khung sử dụng và biến thể nhà cung cấp (được đặt tên theo libexample.vendor
) được các mô-đun nhà cung cấp sử dụng. Hai biến thể được cài đặt vào các thư mục khác nhau:
- Biến thể cốt lõi được cài đặt vào
/system/lib[64]/libexample.so
. - Biến thể của nhà cung cấp được cài đặt vào VNDK APEX vì
vndk.enabled
làtrue
.
Để biết thêm thông tin chi tiết, hãy xem phần Định nghĩa mô-đun.
Định cấu hình tính năng hỗ trợ bản dựng
Để bật tính năng hỗ trợ đầy đủ cho hệ thống xây dựng cho một thiết bị sản phẩm, hãy thêm BOARD_VNDK_VERSION
vào BoardConfig.mk
:
BOARD_VNDK_VERSION := current
Chế độ cài đặt này có hiệu lực chung: Khi được xác định trong BoardConfig.mk
, tất cả các mô-đun sẽ được kiểm tra. Vì không có cơ chế nào để đưa một mô-đun vi phạm vào danh sách đen hoặc danh sách trắng, nên bạn nên xoá tất cả các phần phụ thuộc không cần thiết trước khi thêm BOARD_VNDK_VERSION
. Bạn có thể kiểm thử và biên dịch một mô-đun bằng cách đặt BOARD_VNDK_VERSION
trong các biến môi trường:
$ BOARD_VNDK_VERSION=current m module_name.vendor
Khi BOARD_VNDK_VERSION
được bật, một số đường dẫn tìm kiếm tiêu đề chung mặc định sẽ bị xoá. bao gồm:
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
Nếu một mô-đun phụ thuộc vào tiêu đề của các thư mục này, thì bạn phải chỉ định (rõ ràng) các phần phụ thuộc bằng header_libs
, static_libs
và/hoặc shared_libs
.
VNDK APEX
Trong Android 10 trở xuống, các mô-đun có vndk.enabled
được cài đặt trong /system/lib[64]/vndk[-sp]-${VER}
. Trong Android 11 trở lên, thư viện VNDK được đóng gói ở định dạng APEX và tên của VNDK APEX là com.android.vndk.v${VER}
. Tuỳ thuộc vào cấu hình thiết bị, VNDK APEX sẽ được làm phẳng hoặc không làm phẳng và có sẵn trong đường dẫn chính tắc /apex/com.android.vndk.v${VER}
.
Hình 2. VNDK APEX.
Định nghĩa mô-đun
Để tạo Android bằng BOARD_VNDK_VERSION
, bạn phải sửa đổi định nghĩa mô-đun trong Android.mk
hoặc Android.bp
. Phần này mô tả nhiều loại định nghĩa mô-đun, một số thuộc tính mô-đun liên quan đến VNDK và các bước kiểm tra phần phụ thuộc được triển khai trong hệ thống xây dựng.
Mô-đun nhà cung cấp
Mô-đun nhà cung cấp là các tệp thực thi dành riêng cho nhà cung cấp hoặc thư viện dùng chung phải được cài đặt vào phân vùng nhà cung cấp. Trong tệp Android.bp
, các mô-đun của nhà cung cấp phải đặt thuộc tính của nhà cung cấp hoặc thuộc tính độc quyền thành true
.
Trong tệp Android.mk
, các mô-đun của nhà cung cấp phải đặt LOCAL_VENDOR_MODULE
hoặc LOCAL_PROPRIETARY_MODULE
thành true
.
Nếu BOARD_VNDK_VERSION
được xác định, hệ thống xây dựng sẽ không cho phép các phần phụ thuộc giữa mô-đun nhà cung cấp và mô-đun khung, đồng thời phát lỗi nếu:
- mô-đun không có
vendor:true
phụ thuộc vào mô-đun cóvendor:true
, hoặc - một mô-đun có
vendor:true
phụ thuộc vào một mô-đun không phảillndk_library
, không cóvendor:true
hoặcvendor_available:true
.
Quy trình kiểm tra phần phụ thuộc áp dụng cho header_libs
, static_libs
và shared_libs
trong Android.bp
, cũng như LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
và LOCAL_SHARED_LIBRARIES
trong Android.mk
.
LL-NDK
Thư viện dùng chung LL-NDK là thư viện dùng chung có ABI ổn định. Cả mô-đun khung và nhà cung cấp đều có chung cách triển khai và là cách triển khai mới nhất. Đối với mỗi thư viện dùng chung LL-NDK, cc_library
chứa một thuộc tính llndk
có tệp biểu tượng:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
Tệp biểu tượng mô tả các biểu tượng hiển thị cho các mô-đun của nhà cung cấp. Ví dụ:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
Dựa trên tệp biểu tượng, hệ thống xây dựng sẽ tạo một thư viện dùng chung mã giả lập cho các mô-đun nhà cung cấp. Các mô-đun này liên kết với các thư viện này khi BOARD_VNDK_VERSION
được bật. Một biểu tượng chỉ được đưa vào thư viện chia sẻ mã giả lập nếu:
- Không được xác định ở cuối phần bằng
_PRIVATE
hoặc_PLATFORM
, - Không có thẻ
#platform-only
và - Không có thẻ
#introduce*
hoặc thẻ này không khớp với mục tiêu.
VNDK
Trong tệp Android.bp
, các định nghĩa mô-đun cc_library
, cc_library_static
, cc_library_shared
và cc_library_headers
hỗ trợ ba thuộc tính liên quan đến VNDK: vendor_available
, vndk.enabled
và vndk.support_system_process
.
Nếu vendor_available
hoặc vndk.enabled
là true
, thì bạn có thể tạo hai biến thể (core và vendor). Biến thể cốt lõi phải được coi là mô-đun khung và biến thể nhà cung cấp phải được coi là mô-đun nhà cung cấp. Nếu một số mô-đun khung phụ thuộc vào mô-đun này, thì biến thể chính sẽ được tạo. Nếu một số mô-đun của nhà cung cấp phụ thuộc vào mô-đun này, thì biến thể của nhà cung cấp sẽ được tạo. Hệ thống xây dựng thực thi các bước kiểm tra phần phụ thuộc sau:
- Biến thể cốt lõi luôn chỉ dành cho khung và không thể truy cập được các mô-đun của nhà cung cấp.
- Các mô-đun khung luôn không thể truy cập vào biến thể của nhà cung cấp.
- Tất cả phần phụ thuộc của biến thể nhà cung cấp được chỉ định trong
header_libs
,static_libs
và/hoặcshared_libs
phải làllndk_library
hoặc mô-đun cóvendor_available
hoặcvndk.enabled
. - Nếu
vendor_available
làtrue
, thì tất cả các mô-đun của nhà cung cấp đều có thể truy cập vào biến thể của nhà cung cấp. - Nếu
vendor_available
làfalse
, thì chỉ các mô-đun VNDK hoặc VNDK-SP khác mới có thể truy cập vào biến thể của nhà cung cấp (tức là các mô-đun cóvendor:true
không thể liên kết các mô-đunvendor_available:false
).
Đường dẫn cài đặt mặc định cho cc_library
hoặc cc_library_shared
được xác định theo các quy tắc sau:
- Biến thể cốt lõi được cài đặt vào
/system/lib[64]
. - Đường dẫn cài đặt biến thể của nhà cung cấp có thể khác nhau:
- Nếu
vndk.enabled
làfalse
, thì biến thể của nhà cung cấp sẽ được cài đặt vào/vendor/lib[64]
. - Nếu
vndk.enabled
làtrue
, thì biến thể của nhà cung cấp sẽ được cài đặt vào VNDK APEX(com.android.vndk.v${VER}
).
- Nếu
Bảng dưới đây tóm tắt cách hệ thống xây dựng xử lý các biến thể của nhà cung cấp:
vendor_available | đã bật vndk |
vndk support_same_process |
Nội dung mô tả biến thể của nhà cung cấp |
---|---|---|---|
true |
false |
false |
Các biến thể của nhà cung cấp là CHỈ VND. Thư viện dùng chung được cài đặt vào /vendor/lib[64] . |
true |
Không hợp lệ (Lỗi bản dựng) | ||
true |
false |
Các biến thể của nhà cung cấp là VNDK. Thư viện dùng chung được cài đặt vào VNDK APEX. | |
true |
Các biến thể của nhà cung cấp là VNDK-SP. Thư viện dùng chung được cài đặt vào VNDK APEX. | ||
|
|
|
Không có biến thể của nhà cung cấp. Mô-đun này CHỈ DÀNH CHO FWK. |
true |
Không hợp lệ (Lỗi bản dựng) | ||
true |
false |
Các biến thể của nhà cung cấp là VNDK-Private. Thư viện dùng chung được cài đặt vào VNDK APEX. Các mô-đun của nhà cung cấp không được sử dụng trực tiếp các mô-đun này. | |
true |
Các biến thể của nhà cung cấp là VNDK-SP-Private. Thư viện dùng chung được cài đặt vào VNDK APEX. Các mô-đun nhà cung cấp không được trực tiếp sử dụng những thông tin này. |
Phần mở rộng VNDK
Tiện ích VNDK là các thư viện dùng chung VNDK có các API bổ sung. Các tiện ích được cài đặt vào /vendor/lib[64]/vndk[-sp]
(không có hậu tố phiên bản) và ghi đè thư viện chia sẻ VNDK gốc trong thời gian chạy.
Xác định các tiện ích VNDK
Trên Android 9 trở lên, Android.bp
hỗ trợ các tiện ích VNDK ngay từ đầu. Để tạo một tiện ích VNDK, hãy xác định một mô-đun khác có thuộc tính vendor:true
và extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
Mô-đun có các thuộc tính vendor:true
, vndk.enabled:true
và extends
xác định tiện ích VNDK:
- Thuộc tính
extends
phải chỉ định tên thư viện dùng chung VNDK cơ sở (hoặc tên thư viện dùng chung VNDK-SP). - Các tiện ích VNDK (hoặc tiện ích VNDK-SP) được đặt tên theo tên mô-đun cơ sở mà các tiện ích đó mở rộng. Ví dụ: tệp nhị phân đầu ra của
libvndk_ext
làlibvndk.so
thay vìlibvndk_ext.so
. - Các tiện ích VNDK được cài đặt vào
/vendor/lib[64]/vndk
. - Các tiện ích VNDK-SP được cài đặt vào
/vendor/lib[64]/vndk-sp
. - Thư viện dùng chung cơ sở phải có cả
vndk.enabled:true
vàvendor_available:true
.
Tiện ích VNDK-SP phải mở rộng từ thư viện dùng chung VNDK-SP (vndk.support_system_process
phải bằng nhau):
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, }, }
Các tiện ích VNDK (hoặc tiện ích VNDK-SP) có thể phụ thuộc vào các thư viện dùng chung khác của nhà cung cấp:
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, }
Sử dụng tiện ích VNDK
Nếu mô-đun của nhà cung cấp phụ thuộc vào các API bổ sung do tiện ích VNDK xác định, thì mô-đun đó phải chỉ định tên của tiện ích VNDK trong thuộc tính 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", ], }
Nếu một mô-đun nhà cung cấp phụ thuộc vào các tiện ích VNDK, thì các tiện ích VNDK đó sẽ tự động được cài đặt vào /vendor/lib[64]/vndk[-sp]
. Nếu một mô-đun không còn phụ thuộc vào tiện ích VNDK, hãy thêm một bước dọn dẹp vào CleanSpec.mk
để xoá thư viện dùng chung. Ví dụ:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Biên dịch có điều kiện
Phần này mô tả cách xử lý những điểm khác biệt nhỏ (ví dụ: thêm hoặc xoá một tính năng khỏi một trong các biến thể) giữa 3 thư viện dùng chung VNDK sau:
- Biến thể chính (ví dụ:
/system/lib[64]/libexample.so
) - Biến thể của nhà cung cấp (ví dụ:
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - Tiện ích VNDK (ví dụ:
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Cờ trình biên dịch có điều kiện
Theo mặc định, hệ thống xây dựng Android xác định __ANDROID_VNDK__
cho các biến thể của nhà cung cấp và tiện ích VNDK. Bạn có thể bảo vệ mã bằng các trình bảo vệ trình xử lý trước C:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
Ngoài __ANDROID_VNDK__
, bạn có thể chỉ định nhiều cflags
hoặc cppflags
trong Android.bp
. cflags
hoặc cppflags
được chỉ định trong target.vendor
dành riêng cho biến thể nhà cung cấp.
Ví dụ: Android.bp
sau đây xác định libexample
và 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", ], }
Và đây là danh sách mã của 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
Theo 2 tệp này, hệ thống xây dựng tạo ra các thư viện dùng chung có các biểu tượng đã xuất như sau:
Đường dẫn cài đặt | Biểu tượng đã xuất |
---|---|
/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 |
Yêu cầu đối với các ký hiệu được xuất
Trình kiểm tra ABI VNDK so sánh ABI của các biến thể nhà cung cấp VNDK và các tiện ích VNDK với tệp kết xuất ABI tham chiếu trong prebuilts/abi-dumps/vndk
.
- Các ký hiệu do các biến thể nhà cung cấp VNDK xuất (ví dụ:
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) phải giống hệt (không phải tập hợp con của) các ký hiệu được xác định trong tệp báo lỗi ABI. - Các ký hiệu do tiện ích VNDK xuất (ví dụ:
/vendor/lib[64]/vndk/libexample.so
) phải là tập hợp con của các ký hiệu được xác định trong tệp báo lỗi ABI.
Nếu các biến thể nhà cung cấp VNDK hoặc các tiện ích VNDK không tuân thủ các yêu cầu ở trên, thì trình kiểm tra ABI VNDK sẽ phát lỗi bản dựng và dừng bản dựng.
Loại trừ tệp nguồn hoặc thư viện dùng chung khỏi các biến thể của nhà cung cấp
Để loại trừ các tệp nguồn khỏi biến thể của nhà cung cấp, hãy thêm các tệp đó vào thuộc tính exclude_srcs
. Tương tự, để đảm bảo các thư viện dùng chung không được liên kết với biến thể của nhà cung cấp, hãy thêm các thư viện đó vào thuộc tính exclude_shared_libs
. Ví dụ:
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"], }, }, }
Trong ví dụ này, biến thể chính của libexample_cond_exclude
bao gồm mã từ fwk.c
và both.c
, đồng thời phụ thuộc vào thư viện dùng chung libfwk_only
và libboth
. Biến thể nhà cung cấp của libexample_cond_exclude
chỉ bao gồm mã của both.c
vì fwk.c
bị thuộc tính exclude_srcs
loại trừ. Tương tự, lớp này chỉ phụ thuộc vào thư viện dùng chung libboth
vì libfwk_only
bị thuộc tính exclude_shared_libs
loại trừ.
Xuất tiêu đề từ các tiện ích VNDK
Tiện ích VNDK có thể thêm các lớp mới hoặc hàm mới vào thư viện VNDK dùng chung. Bạn nên giữ lại các nội dung khai báo đó trong các tiêu đề độc lập và tránh thay đổi các tiêu đề hiện có.
Ví dụ: hệ thống sẽ tạo một tệp tiêu đề mới include-ext/example/ext/feature_name.h
cho phần mở rộng libexample_ext
K của VND:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
Trong Android.bp
sau đây, libexample
chỉ xuất include
, trong khi libexample_ext
xuất cả include
và include-ext
. Điều này đảm bảo rằng người dùng libexample
sẽ không đưa feature_name.h
vào không chính xác:
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", }, }
Nếu không thể tách các phần mở rộng thành các tệp tiêu đề độc lập, bạn có thể thêm các trình bảo vệ #ifdef
. Tuy nhiên, hãy đảm bảo rằng tất cả người dùng tiện ích VNDK đều thêm cờ xác định. Bạn có thể xác định cc_defaults
để thêm cờ xác định vào cflags
và liên kết các thư viện dùng chung với shared_libs
.
Ví dụ: để thêm hàm thành phần mới Example2::get_b()
vào phần mở rộng libexample2_ext
của VNDK, bạn phải sửa đổi tệp tiêu đề hiện có và thêm lớp bảo vệ #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_
Một cc_defaults
có tên là libexample2_ext_defaults
được xác định cho người dùng của 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", ], }
Người dùng libexample2_ext
chỉ cần đưa libexample2_ext_defaults
vào thuộc tính defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Gói sản phẩm
Trong hệ thống xây dựng Android, biến PRODUCT_PACKAGES
chỉ định các tệp thực thi, thư viện dùng chung hoặc gói cần được cài đặt vào thiết bị. Các phần phụ thuộc bắc cầu của mô-đun được chỉ định cũng được cài đặt ngầm vào thiết bị.
Nếu bạn bật BOARD_VNDK_VERSION
, các mô-đun có vendor_available
hoặc vndk.enabled
sẽ được xử lý đặc biệt. Nếu một mô-đun khung phụ thuộc vào một mô-đun có vendor_available
hoặc vndk.enabled
, thì biến thể cốt lõi sẽ được đưa vào nhóm cài đặt bắc cầu. Nếu một mô-đun của nhà cung cấp phụ thuộc vào một mô-đun có vendor_available
, thì biến thể nhà cung cấp sẽ được đưa vào tập hợp cài đặt bắc cầu. Tuy nhiên, các biến thể của nhà cung cấp mô-đun có vndk.enabled
sẽ được cài đặt cho dù các mô-đun của nhà cung cấp có sử dụng các biến thể đó hay không.
Khi hệ thống xây dựng không nhìn thấy các phần phụ thuộc (ví dụ: thư viện dùng chung có thể được mở bằng dlopen()
trong thời gian chạy), bạn nên chỉ định tên mô-đun trong PRODUCT_PACKAGES
để cài đặt các mô-đun đó một cách rõ ràng.
Nếu một mô-đun có vendor_available
hoặc vndk.enabled
, thì tên mô-đun sẽ đại diện cho biến thể cốt lõi của mô-đun đó. Để chỉ định rõ biến thể nhà cung cấp trong PRODUCT_PACKAGES
, hãy thêm hậu tố .vendor
vào tên mô-đun. Ví dụ:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
Trong ví dụ này, libexample
là viết tắt của /system/lib[64]/libexample.so
và libexample.vendor
là viết tắt của /vendor/lib[64]/libexample.so
. Để cài đặt /vendor/lib[64]/libexample.so
, hãy thêm libexample.vendor
vào PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor