در 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.vendor) توسط واحدهای
فروشنده استفاده میشود. دو گونه در دایرکتوریهای مختلف نصب میشوند:
- گونه اصلی در
/system/lib[64]/libexample.soنصب میشود. - نوع فروشنده در VNDK APEX نصب شده است زیرا
vndk.enabledtrueاست.
برای جزئیات بیشتر، به تعریف ماژول مراجعه کنید.
پیکربندی پشتیبانی ساخت
برای فعال کردن پشتیبانی کامل سیستم ساخت برای دستگاه محصول،
BOARD_VNDK_VERSION را به BoardConfig.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/includeframeworks/native/includeframeworks/native/opengl/includehardware/libhardware/includehardware/libhardware_legacy/includehardware/ril/includelibnativehelper/includelibnativehelper/include_deprecatedsystem/core/includesystem/media/audio/include
اگر واحدی به سرایندهای این دایرکتوریها وابسته است، باید وابستگیها را با header_libs،
static_libs، و/یا shared_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.
تعریف واحد
برای ساختن Android با BOARD_VNDK_VERSION، باید تعریف ماژول را در 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به پیمانه غیرllndk_libraryکه نهvendor:trueدارد و نهvendor_available:trueبستگی دارد.
بررسی وابستگی برای header_libs،
static_libs، و shared_libs در
Android.bp، و برای LOCAL_HEADER_LIBRARIES،
LOCAL_STATIC_LIBRARIES، و LOCAL_SHARED_LIBRARIES در
Android.mk اعمال میشود.
LL-NDK
کتابخانههای مشترک LL-NDK کتابخانههای مشترکی با رابطهای باینری کاربردی پایدار هستند. هم چارچوب
و هم واحدهای فروشنده از پیادهسازی یکسان و جدید استفاده میکنند. برای هر کتابخانه مشترک 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_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مشخص شدهاند، باید یاllndk_libraryیا واحدی باvendor_availableیاvndk.enabledباشند. - اگر
vendor_availableبرابر باtrueباشد، گونه فروشنده برای همه پیمانههای فروشنده دردسترس است. - اگر
vendor_availablefalseباشد، گونه فروشنده فقط برای سایر ماژولهای VNDK یا VNDK-SP دردسترس است (یعنی ماژولهای دارایvendor:trueنمیتوانند ماژولهایvendor_available:falseرا پیوند دهند).
مسیر نصب پیشفرض برای cc_library یا
cc_library_shared براساس قوانین زیر تعیین میشود:
- گونه اصلی در
/system/lib[64]نصب شده است. - مسیر نصب گونه فروشنده ممکن است متفاوت باشد:
- اگر
vndk.enabledfalseباشد، گونه فروشنده در/vendor/lib[64]نصب میشود. - اگر
vndk.enabledtrueباشد، گونه فروشنده در VNDK APEX(com.android.vndk.v${VER}) نصب میشود.
- اگر
جدول زیر نحوه مدیریت انواع فروشنده توسط سیستم ساخت را خلاصه میکند:
| vendor_available | vndk فعال شد |
vndk support_system_process |
توضیحات متغیر فروشنده |
|---|---|---|---|
true |
false |
false |
گونههای فروشنده فقط به دونگ ویتنام است. کتابخانههای مشترک در /vendor/lib[64] نصب میشوند. |
true |
نامعتبر (خطای ساخت) | ||
true |
false |
گونههای فروشنده VNDK است. کتابخانههای مشترک در VNDK APEX نصب میشوند. | |
true |
انواع فروشنده VNDK-SP هستند. کتابخانههای مشترک در VNDK APEX نصب میشوند. | ||
|
|
|
بدون متغیرهای فروشنده. این واحد FWK-ONLY است. |
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 نسخه ۹ و بالاتر، 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.so،libvndk.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 تعریف شدهاند وابسته باشد، واحد باید نام افزونه 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)
ترجمه شرطی
این بخش نحوه برخورد با تفاوتهای ظریف (برای نمونه، افزودن یا برداشتن ویژگی از یکی از گونهها) بین سه کتابخانه مشترک زیر را توضیح میدهد:
- متغیر اصلی (مثلاً
/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__، 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 |
الزامات مربوط به نمادهای صادرشده
بررسیکننده ABI مربوط به VNDK
ABI مربوط به گونههای فروشنده VNDK و
افزونههای 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 فقط کد
both.c را دارد زیرا fwk.c با دارایی
exclude_srcs مستثنا شده است. بههمین ترتیب، فقط به کتابخانه مشترک
libboth بستگی دارد زیرا libfwk_only توسط
خصوصیت exclude_shared_libs مستثنا شده است.
صادر کردن سرصفحهها از افزونههای VNDK
افزونه VNDK ممکن است کلاسها یا عملکردهای جدیدی به کتابخانه مشترک VNDK اضافه کند. توصیه میشود این اظهارات را در سرایندهای مستقل نگه دارید و از تغییر سرایندهای موجود خودداری کنید.
برای مثال، فایل سرصفحه جدیدی
include-ext/example/ext/feature_name.h برای افزونه
libexample_ext VNDK ایجاد میشود:
- 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 را صادر میکند. این کار تضمین میکند که
feature_name.h بهاشتباه توسط کاربران
libexample اضافه نشود:
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 میتوانند بهسادگی
libexample2_ext_defaults را در دارایی 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