في الإصدار 8.1 من نظام التشغيل Android والإصدارات الأحدث، يتضمّن نظام الإنشاء إمكانية استخدام 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. - يتم تثبيت حزمة APEX الخاصة بالمورّد في 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/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.
حزمة APEX لمجموعة تطوير أصلية للمورّدين (VNDK)
في الإصدار 10 من نظام Android والإصدارات الأقدم، تم تثبيت الوحدات التي تتضمّن 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}.

الشكل 2: حزمة APEX لمجموعة تطوير أصلية للمورّدين (VNDK)
تعريف الوحدة
لإنشاء 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 المشترَكة هي مكتبات مشترَكة تتضمّن واجهات ثنائية مستقرة لتطبيقات Android. يتشارك كل من إطار العمل ووحدات المورّد النمط نفسه وأحدث إصدار منه. بالنسبة إلى كل مكتبة مشترَكة منخفضة التأخير في 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، قد يتم إنشاء صيغتين (أساسية وخاصة بالمورّد). يجب التعامل مع الإصدار الأساسي على أنّه وحدة إطار عمل، والتعامل مع إصدار المورّد على أنّه وحدة مورّد. إذا كانت بعض وحدات الحزمة تعتمد على هذه الوحدة، يتم إنشاء الصيغة الأساسية. إذا كانت بعض وحدات المورّد تعتمد على هذه الوحدة، يتم إنشاء صيغة المورّد. يفرض نظام الإنشاء عمليات التحقّق التالية من التبعيات:
- يكون الإصدار الأساسي دائمًا مخصصًا للإطار فقط ولا يمكن لوحدات المورّد الوصول إليه.
- لا يمكن لوحدات إطار العمل الوصول إلى صيغة المورّد.
- يجب أن تكون جميع التبعيات الخاصة بخيار المورّد، والمحدّدة في
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، يتم تثبيت صيغة المورّد في حزمة APEX الخاصة بـ VNDK (com.android.vndk.v${VER}).
- إذا كانت قيمة
يلخّص الجدول أدناه كيفية تعامل نظام التصميم مع متغيرات المورّد:
| vendor_available | vndk enabled |
vndk support_system_process |
أوصاف خيارات المورّدين |
|---|---|---|---|
true |
false |
false |
تكون حِزم APK الخاصة بالمورّد VND-ONLY، ويتم تثبيت المكتبات المشتركة في /vendor/lib[64]. |
true |
غير صالح (خطأ في الإنشاء) | ||
true |
false |
تكون صيغ المورّد VNDK. يتم تثبيت المكتبات المشتركة في حزمة APEX الخاصة بـ VNDK. | |
true |
تتضمّن متغيرات المورّد VNDK-SP، ويتم تثبيت المكتبات المشتركة في حزمة APEX الخاصة بـ VNDK. | ||
|
|
|
ما مِن صِيَغ للمورّد. هذه الوحدة هي FWK-ONLY. |
true |
غير صالح (خطأ في الإنشاء) | ||
true |
false |
تكون صيغ المورّد VNDK-Private، ويتم تثبيت المكتبات المشتركة في حزمة VNDK APEX، ويجب ألا تستخدم وحدات المورّد هذه المكتبات مباشرةً. | |
true |
تكون صيغ البائعين VNDK-SP-Private. يتم تثبيت المكتبات المشتركة في حزمة APEX الخاصة بـ VNDK. ويجب ألا تستخدم وحدات المورّد هذه القيم مباشرةً. |
إضافات VNDK
إضافات VNDK هي مكتبات VNDK مشترَكة تتضمّن واجهات برمجة تطبيقات إضافية. يتم تثبيت الإضافات في /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.soبدلاً منlibvndk_ext.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)
الترجمة البرمجية الشرطية
يوضّح هذا القسم كيفية التعامل مع الاختلافات الطفيفة (مثل إضافة ميزة أو إزالتها من أحد الأنواع) بين مكتبات 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 __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 واجهة التطبيق الثنائية لمتغيرات المورّد لحزمة 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 الخاصة بمورّدين مع المتطلبات المذكورة أعلاه، سيصدر مدقق توافق واجهة التطبيق الثنائية (ABI) في VNDK أخطاء في الإصدار وسيتم إيقاف الإصدار.
استبعاد الملفات المصدر أو المكتبات المشترَكة من صيغ المورّد
لاستبعاد ملفات المصدر من صيغة المورّد، أضِفها إلى السمة 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 التالية، يتم تصدير include فقط، بينما يتم في عملية التصدير libexample تصدير كل من include وinclude-ext.libexample_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