در اندروید ۸.۱ و بالاتر، سیستم ساخت (build system) از VNDK پشتیبانی میکند. وقتی پشتیبانی VNDK فعال باشد، سیستم ساخت وابستگیهای بین ماژولها را بررسی میکند، یک نسخه مخصوص فروشنده برای ماژولهای فروشنده میسازد و بهطور خودکار آن ماژولها را در دایرکتوریهای تعیینشده نصب میکند.
مثال پشتیبانی از ساخت VNDK
در این مثال، تعریف ماژول Android.bp کتابخانهای به نام libexample را تعریف میکند. ویژگی vendor_available نشان میدهد که ماژولهای فریمورک و ماژولهای vendor ممکن است به libexample وابسته باشند:

شکل ۱. پشتیبانی فعال شده.
هر دو فایل اجرایی framework با /system/bin/foo و vendor با نام /vendor/bin/bar به libexample وابسته هستند و در ویژگیهای shared_libs خود دارای libexample هستند.
اگر libexample هم توسط ماژولهای چارچوب و هم توسط ماژولهای فروشنده استفاده شود، دو نوع libexample ساخته میشود. نوع اصلی (که از libexample نامگذاری شده است) توسط ماژولهای چارچوب و نوع فروشنده (که از libexample.vendor نامگذاری شده است) توسط ماژولهای فروشنده استفاده میشود. این دو نوع در دایرکتوریهای مختلف نصب میشوند:
- نوع اصلی در
/system/lib[64]/libexample.soنصب شده است. - نوع vendor در 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
در اندروید ۱۰ و پایینتر، ماژولهایی با vndk.enabled در /system/lib[64]/vndk[-sp]-${VER} نصب میشدند. در اندروید ۱۱ و بالاتر، کتابخانههای 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*ندارد یا تگ با تگ هدف مطابقت دارد.
وندک
در فایلهای 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 ) ساخت. نوع core باید به عنوان یک ماژول فریمورک و نوع vendor باید به عنوان یک ماژول vendor در نظر گرفته شود. اگر برخی از ماژولهای فریمورک به این ماژول وابسته باشند، نوع core ساخته میشود. اگر برخی از ماژولهای vendor به این ماژول وابسته باشند، نوع vendor ساخته میشود. سیستم ساخت، بررسیهای وابستگی زیر را اعمال میکند:
- نوع اصلی همیشه فقط مختص چارچوب است و برای ماژولهای فروشنده غیرقابل دسترسی است.
- نوع فروشنده همیشه برای ماژولهای چارچوب غیرقابل دسترسی است.
- تمام وابستگیهای نوع vendor که در
header_libs،static_libsو/یاshared_libsمشخص شدهاند، باید یا یکllndk_libraryیا یک ماژول باvendor_availableیاvndk.enabledباشند. - اگر
vendor_availabletrueباشد، نوع vendor برای همه ماژولهای vendor قابل دسترسی است. - اگر
vendor_availableمقدارfalseداشته باشد، متغیر vendor فقط برای سایر ماژولهای VNDK یا VNDK-SP قابل دسترسی است (یعنی ماژولهایی کهvendor:trueدارند نمیتوانند ماژولهایvendor_available:falseبه هم لینک کنند).
مسیر نصب پیشفرض برای cc_library یا cc_library_shared با قوانین زیر تعیین میشود:
- نوع اصلی در
/system/lib[64]نصب شده است. - مسیر نصب نوع فروشنده ممکن است متفاوت باشد:
- اگر
vndk.enabledfalseباشد، نوع vendor در/vendor/lib[64]نصب میشود. - اگر
vndk.enabledtrueباشد، نسخه فروشنده در VNDK APEX(com.android.vndk.v${VER}) نصب میشود.
- اگر
جدول زیر خلاصه میکند که چگونه سیستم ساخت، انواع فروشنده را مدیریت میکند:
| فروشنده_موجود | وندک فعال شده | وندک پشتیبانی_سیستم_فرآیند | توضیحات مربوط به انواع فروشنده |
|---|---|---|---|
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، کتابخانههای اشتراکی VNDK با APIهای اضافی هستند. افزونهها در مسیر /vendor/lib[64]/vndk[-sp] (بدون پسوند نسخه) نصب میشوند و در زمان اجرا، کتابخانههای اشتراکی اصلی VNDK را نادیده میگیرند.
تعریف افزونههای VNDK
در اندروید ۹ و بالاتر، 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 مختص نوع 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 را با فایلهای مرجع ABI dumps در 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 برای افزونهی VNDK به libexample_ext ایجاد میشود:
- اندروید.بیپی
- شامل-فایلهای داخلی/مثال/فایلهای داخلی/نام_ویژگی.h
- شامل/مثال/مثال.h
- src/example.c
- src/ext/feature_name.c
در فایل Android.bp زیر، فایلهای export شده libexample فقط include ، در حالی که فایلهای export شده 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,
}بستههای محصول
در سیستم ساخت اندروید، متغیر PRODUCT_PACKAGES فایلهای اجرایی، کتابخانههای اشتراکی یا بستههایی را که باید در دستگاه نصب شوند، مشخص میکند. وابستگیهای انتقالی ماژولهای مشخص شده نیز به طور ضمنی در دستگاه نصب میشوند.
اگر BOARD_VNDK_VERSION فعال باشد، ماژولهایی که دارای vendor_available یا vndk.enabled هستند، رفتار ویژهای با آنها میشود. اگر یک ماژول چارچوب به ماژولی با vendor_available یا vndk.enabled وابسته باشد، نوع اصلی در مجموعه نصب انتقالی گنجانده میشود. اگر یک ماژول فروشنده به ماژولی با vendor_available وابسته باشد، نوع فروشنده در مجموعه نصب انتقالی گنجانده میشود. با این حال، انواع فروشنده ماژولهایی که دارای vndk.enabled هستند، چه توسط ماژولهای فروشنده استفاده شوند و چه نشوند، نصب میشوند.
وقتی وابستگیها برای سیستم ساخت (build system) قابل مشاهده نیستند (مثلاً کتابخانههای اشتراکی که ممکن است با 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