در اندروید 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.enabled
true
است.
برای جزئیات بیشتر، به تعریف ماژول مراجعه کنید.
پشتیبانی ساخت را پیکربندی کنید
برای فعال کردن پشتیبانی کامل سیستم ساخت برای یک دستگاه محصول، 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_available
true
باشد، نوع فروشنده برای همه ماژولهای فروشنده قابل دسترسی است. - اگر
vendor_available
false
باشد، نوع فروشنده فقط برای سایر ماژولهای VNDK یا VNDK-SP قابل دسترسی است (یعنی ماژولهای دارایvendor:true
نمیتوانندvendor_available:false
ماژولها را پیوند دهند).
مسیر نصب پیش فرض برای cc_library
یا cc_library_shared
با قوانین زیر تعیین می شود:
- نوع اصلی در
/system/lib[64]
نصب شده است. - مسیر نصب نوع فروشنده ممکن است متفاوت باشد:
- اگر
vndk.enabled
false
باشد، نوع فروشنده در/vendor/lib[64]
نصب میشود. - اگر
vndk.enabled
true
باشد، نوع فروشنده در VNDK APEX (com.android.vndk.v${VER}
) نصب میشود.
- اگر
جدول زیر نحوه عملکرد سیستم ساخت با انواع فروشنده را خلاصه می کند:
vendor_available | vndk فعال شد | vndk support_same_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
، و extensions 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 استفاده کنید
اگر یک ماژول فروشنده به 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