Ở Android 8.1 trở lên, hệ thống build đã tích hợp hỗ trợ VNĐK. Khi bật hỗ trợ VNĐK, hệ thống xây dựng sẽ kiểm tra sự phụ thuộc giữa các mô-đun, xây dựng 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ụ hỗ trợ xây dựng VNĐK
Trong ví dụ này, định nghĩa mô-đun Android.bp
xác định thư viện có tên 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
:
Cả khung thực thi /system/bin/foo
và /vendor/bin/bar
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
của chúng.
Nếu libexample
được cả mô-đun khung và mô-đun nhà cung cấp sử dụng 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 sử dụng bởi các mô-đun khung và biến thể nhà cung cấp (được đặt tên theo libexample.vendor
) được sử dụng bởi các mô-đun nhà cung cấp. 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 chi tiết, xem Định nghĩa mô-đun .
Định cấu hình hỗ trợ xây dựng
Để kích hoạt hỗ trợ hệ thống xây dựng đầy đủ 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
Cài đặt này có hiệu lực toàn cầu : Khi được xác định trong BoardConfig.mk
, tất cả các mô-đun đều được chọn. Vì không có cơ chế đưa vào danh sách đen hoặc danh sách trắng một mô-đun vi phạm, bạn nên xóa 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 tra 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 của mình:
$ 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ị xóa . Bao gồm các:
-
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 các tiêu đề từ các thư mục này, bạn phải chỉ định (rõ ràng) các phần phụ thuộc với header_libs
, static_libs
và/hoặc shared_libs
.
ĐỈNH VNĐK
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 VNĐK được đóng gói theo định dạng APEX và tên của VNĐK APEX là com.android.vndk.v${VER}
. Tùy thuộc vào cấu hình thiết bị, VNDK APEX được làm phẳng hoặc không được làm phẳng và có sẵn từ đường dẫn chuẩn /apex/com.android.vndk.v${VER}
.
định nghĩa mô-đun
Để xây dựng Android với BOARD_VNDK_VERSION
, bạn phải sửa lại định nghĩa mô-đun trong Android.mk
hoặc Android.bp
. Phần này mô tả các loại định nghĩa mô-đun khác nhau, một số thuộc tính mô-đun liên quan đến VNDK và kiểm tra 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 hoặc thư viện dùng chung dành riêng cho nhà cung cấp phải được cài đặt vào phân vùng của nhà cung cấp. Trong tệp Android.bp
, mô-đun nhà cung cấp phải đặt thuộc tính nhà cung cấp hoặc độc quyền thành true
. Trong tệp Android.mk
, 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 không cho phép sự phụ thuộc giữa mô-đun nhà cung cấp và mô-đun khung và sẽ phát ra lỗi nếu:
- một 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
cũng khôngvendor_available:true
.
Kiểm tra phụ thuộc áp dụng cho header_libs
, static_libs
và shared_libs
trong Android.bp
và cho LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
và LOCAL_SHARED_LIBRARIES
trong Android.mk
.
LL-NDK
Thư viện chia sẻ LL-NDK là thư viện chia sẻ có ABI ổn định. Cả mô-đun khung và nhà cung cấp đều có chung cách triển khai mới nhất. Đối với mỗi thư viện chia sẻ LL-NDK, cc_library
chứa thuộc tính llndk
với tệp ký hiệu:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
Tệp biểu tượng mô tả các ký hiệu 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 ký hiệu, hệ thống xây dựng tạo ra một thư viện chia sẻ sơ khai cho các mô-đun nhà cung cấp, 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ẻ sơ khai nếu nó:
- Không được xác định ở phần cuối bằng
_PRIVATE
hoặc_PLATFORM
, - Không có thẻ
#platform-only
và - Không có thẻ
#introduce*
hoặc thẻ phù hợp với mục tiêu.
VNĐK
Trong các 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ì hai biến thể ( core và Vendor ) có thể được tạo. Biến thể cốt lõi phải được coi là mô-đun khung và biến thể của nhà cung cấp phải được coi là mô-đun của 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ể cốt lõi 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 kiểm tra phụ thuộc sau:
- Biến thể cốt lõi luôn chỉ có khung và không thể truy cập được đối với các mô-đun của nhà cung cấp.
- Biến thể của nhà cung cấp luôn không thể truy cập được vào các mô-đun khung.
- Tất cả cá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ột 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 được biến thể của nhà cung cấp. - Nếu
vendor_available
làfalse
thì biến thể nhà cung cấp chỉ có thể truy cập được từ các mô-đun VNĐK hoặc VNĐK-SP khác (tức là các mô-đun cóvendor:true
không thể liên kết các mô-vendor_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
, 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
, 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 bên dưới 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:
nhà cung cấp_có sẵn | vndk đã bật | vndk hỗ trợ_same_process | 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 CHỈ CÓ VNĐ . Thư viện dùng chung được cài đặt vào /vendor/lib[64] . |
true | Không hợp lệ (Lỗi xây dựng) | ||
true | false | Các biến thể của nhà cung cấp là VNĐK . Thư viện dùng chung được cài đặt vào VNĐK APEX. | |
true | Các biến thể của nhà cung cấp là VNĐK-SP . Thư viện dùng chung được cài đặt vào VNĐK APEX. | ||
| | | Không có biến thể của nhà cung cấp. Mô-đun này CHỈ FWK . |
true | Không hợp lệ (Lỗi xây dựng) | ||
true | false | Các biến thể của nhà cung cấp là VNĐK-Private . Thư viện dùng chung được cài đặt vào VNĐK APEX. Chúng không được sử dụng trực tiếp bởi các mô-đun của nhà cung cấp. | |
true | Các biến thể của nhà cung cấp là VNĐK-SP-Private . Thư viện dùng chung được cài đặt vào VNĐK APEX. Chúng không được sử dụng trực tiếp bởi các mô-đun của nhà cung cấp. |
Tiện ích mở rộng VNĐK
Tiện ích mở rộng VNĐK là thư viện chia sẻ VNĐK với các API bổ sung. Tiện ích mở rộng đượ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ẻ VNĐK gốc khi chạy.
Xác định phần mở rộng VNĐK
Trong Android 9 trở lên, Android.bp
vốn hỗ trợ các tiện ích mở rộng VNDK. Để xây dựng tiện ích mở rộng VNDK, hãy xác định một mô-đun khác với 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ột mô-đun có các thuộc tính của vendor:true
, vndk.enabled:true
và extends
xác định tiện ích mở rộng VNĐK:
- Thuộc tính
extends
phải chỉ định tên thư viện chia sẻ VNĐK cơ sở (hoặc tên thư viện chia sẻ VNĐK-SP). - Tiện ích mở rộng VNDK (hoặc tiện ích mở rộng VNDK-SP) được đặt tên theo tên mô-đun cơ sở mà chúng mở rộng. Ví dụ: nhị phân đầu ra của
libvndk_ext
làlibvndk.so
thay vìlibvndk_ext.so
. - Tiện ích mở rộng VNDK được cài đặt vào
/vendor/lib[64]/vndk
. - Tiện ích mở rộng VNDK-SP được cài đặt vào
/vendor/lib[64]/vndk-sp
. - Các thư viện chia sẻ cơ sở phải có cả
vndk.enabled:true
vàvendor_available:true
.
Tiện ích mở rộng VNDK-SP phải mở rộng từ thư viện chia sẻ 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, }, }
Tiện ích mở rộng VNDK (hoặc tiện ích mở rộng VNDK-SP) có thể phụ thuộc vào thư viện chia sẻ của nhà cung cấp khác:
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 mở rộng VNĐK
Nếu mô-đun nhà cung cấp phụ thuộc vào các API bổ sung được xác định bởi tiện ích mở rộng VNĐK, mô-đun phải chỉ định tên của tiện ích mở rộng VNĐK trong thuộc tính shared_libs
của nó:
// 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ô-đun nhà cung cấp phụ thuộc vào tiện ích mở rộng VNĐK, các tiện ích mở rộng VNĐK đó sẽ được cài đặt tự động 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 mở rộng VNĐK, hãy thêm một bước sạch vào CleanSpec.mk
để xóa 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 giải quyết những khác biệt nhỏ (ví dụ: thêm hoặc xóa một tính năng khỏi một trong các biến thể) giữa ba thư viện chia sẻ VNĐK sau:
- Biến thể cốt lõi (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
) - Phần mở rộng VNĐK (ví dụ
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Cờ biên dịch có điều kiện
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 mở rộng VNĐK theo mặc định. Bạn có thể bảo vệ mã bằng bộ bảo vệ tiền xử lý C:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
Ngoài __ANDROID_VNDK__
, cflags
hoặc cppflags
khác nhau có thể được chỉ định trong Android.bp
. cflags
hoặc cppflags
được chỉ định trong target.vendor
dành riêng cho biến thể của nhà cung cấp.
Ví dụ: Android.bp
sau đây định nghĩa 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 hai tệp này, hệ thống xây dựng tạo ra các thư viện dùng chung với các ký hiệu được xuất 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 về các ký hiệu được xuất
Trình kiểm tra ABI của VNĐK so sánh ABI của các biến thể của nhà cung cấp VNĐK và phần mở rộng của VNĐK với các kết xuất ABI tham chiếu trong prebuilts/abi-dumps/vndk
.
- Các ký hiệu được xuất bởi các biến thể của nhà cung cấp VNDK (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 cha của) các ký hiệu được xác định trong kết xuất ABI. - Các ký hiệu được xuất bởi tiện ích mở rộng VNĐK (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 kết xuất ABI.
Nếu các biến thể của nhà cung cấp VNDK hoặc tiện ích mở rộng VNDK không tuân thủ các yêu cầu trên, trình kiểm tra VNDK ABI sẽ phát ra lỗi xây dựng và dừng quá trình xây dựng.
Loại trừ các 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 chúng 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ể cốt lõi của libexample_cond_exclude
bao gồm mã từ fwk.c
và both.c
và 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ã từ both.c
vì fwk.c
bị thuộc tính exclude_srcs
loại trừ. Tương tự, nó chỉ phụ thuộc vào thư viện chia sẻ libboth
vì libfwk_only
bị loại trừ bởi thuộc tính exclude_shared_libs
.
Xuất tiêu đề từ tiện ích mở rộng VNĐK
Tiện ích mở rộng VNDK có thể thêm các lớp mới hoặc chức năng mới vào thư viện dùng chung VNDK. Bạn nên giữ những 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ụ: một tệp tiêu đề mới include-ext/example/ext/feature_name.h
được tạo cho phần mở rộng VNĐK libexample_ext
:
- Android.bp
- include-ext/example/ext/feature_name.h
- bao gồm/example/example.h
- src/example.c
- src/ext/feature_name.c
Trong Android.bp
sau đây, xuất libexample
chỉ include
, trong khi xuất libexample_ext
cả include
và include-ext
. Điều này đảm bảo feature_name.h
sẽ không được người dùng libexample
đưa 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 việc tách các phần mở rộng thành các tệp tiêu đề độc lập là không khả thi thì một giải pháp thay thế là thêm các bộ bảo vệ #ifdef
. Tuy nhiên, hãy đảm bảo rằng tất cả người dùng tiện ích mở rộng 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 viên mới Example2::get_b()
vào phần mở rộng VNĐK libexample2_ext
, bạn phải sửa đổi tệp tiêu đề hiện có và thêm bộ 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 libexample2_ext_defaults
được xác định cho người dùng 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
có thể chỉ cần đưa libexample2_ext_defaults
vào thuộc tính defaults
của họ:
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 sẽ được cài đặt vào thiết bị. Sự phụ thuộc bắc cầu của các mô-đun được chỉ định cũng được cài đặt ngầm vào thiết bị.
Nếu BOARD_VNDK_VERSION
được bật, các mô-đun có vendor_available
hoặc vndk.enabled
sẽ được xử lý đặc biệt. Nếu mô-đun khung phụ thuộc vào mô-đun có vendor_available
hoặc vndk.enabled
thì biến thể cốt lõi sẽ được bao gồm trong bộ cài đặt bắc cầu. Nếu mô-đun nhà cung cấp phụ thuộc vào mô-đun có vendor_available
, thì biến thể của nhà cung cấp sẽ được bao gồm trong bộ cài đặt chuyển tiếp. Tuy nhiên, các biến thể của mô-đun có vndk.enabled
được cài đặt cho dù chúng có được mô-đun của nhà cung cấp sử dụng hay không.
Khi hệ thống xây dựng không nhìn thấy được các phần phụ thuộc (ví dụ: các 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
, tên mô-đun là viết tắt của biến thể cốt lõi của nó. Để chỉ định rõ ràng biến thể của 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