در اندروید 8.1 و بالاتر، سیستم ساخت دارای پشتیبانی داخلی VNDK است. وقتی پشتیبانی VNDK فعال است، سیستم ساخت وابستگیهای بین ماژولها را بررسی میکند، یک نوع خاص فروشنده برای ماژولهای فروشنده میسازد و به طور خودکار آن ماژولها را در فهرستهای مشخص شده نصب میکند.
نمونه پشتیبانی ساخت VNDK
در این مثال، تعریف ماژول Android.bp کتابخانه ای به نام libexample تعریف می کند. ویژگی vendor_available نشان میدهد که ماژولهای چارچوب و ماژولهای فروشنده ممکن است به libexample وابسته باشند:

شکل 1. پشتیبانی فعال است.
هر دو چارچوب اجرایی /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/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 (به طور صریح) مشخص کنید.
VNDK APEX
در اندروید 10 و پایینتر، ماژولهایی با vndk.enabled در /system/lib[64]/vndk[-sp]-${VER} نصب شدند. در اندروید 11 و بالاتر، کتابخانه های VNDK در قالب APEX بسته بندی می شوند و نام VNDK APEX com.android.vndk.v${VER} است. بسته به پیکربندی دستگاه، VNDK APEX صاف یا بدون مسطح است و از مسیر متعارف /apex/com.android.vndk.v${VER} در دسترس است.

شکل 2. VNDK APEX.
تعریف ماژول
برای ساخت اندروید با 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، کتابخانه های مشترک با ABI های پایدار هستند. هر دو ماژول فریمورک و فروشنده، یکسان و آخرین پیاده سازی را به اشتراک می گذارند. برای هر کتابخانه مشترک 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*ندارد یا تگ با هدف مطابقت دارد.
VNDK
در فایلهای 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_availabletrueباشد، نوع فروشنده برای همه ماژولهای فروشنده قابل دسترسی است. - اگر
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 | انواع فروشنده فقط VND-ONLY هستند. کتابخانه های مشترک در /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 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.solibvndk.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 استفاده کنید
اگر یک ماژول فروشنده به APIهای اضافی تعریف شده توسط پسوندهای 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)
تدوین مشروط
این بخش نحوه برخورد با تفاوت های ظریف (به عنوان مثال اضافه کردن یا حذف یک ویژگی از یکی از انواع) بین سه کتابخانه مشترک 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__ برای انواع فروشنده و افزونه های 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 ABI انواع فروشنده VNDK و افزونههای VNDK را با dumpهای ABI مرجع تحت prebuilts/abi-dumps/vndk مقایسه میکند.
- نمادهای صادر شده توسط انواع فروشنده VNDK (به عنوان مثال
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so) باید با نمادهای تعریف شده در ABI dumps (نه ابرمجموعه) یکسان باشند. - نمادهای صادر شده توسط پسوندهای VNDK (به عنوان مثال
/vendor/lib[64]/vndk/libexample.so) باید ابرمجموعه نمادهای تعریف شده در dumps ABI باشند.
اگر انواع VNDK فروشنده یا افزونه های VNDK از الزامات بالا پیروی نکنند، VNDK ABI checker خطاهای ساخت منتشر می کند و ساخت را متوقف می کند.
فایل های منبع یا کتابخانه های مشترک را از انواع فروشنده حذف کنید
برای حذف فایل های منبع از نوع فروشنده، آنها را به ویژگی 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 برای پسوند VNDK libexample_ext ایجاد میشود:
- 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 guard اضافه کنید:
#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,
}بسته های محصول
در سیستم ساخت اندروید، متغیر 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