دعم نظام إنشاء مجموعة تطوير أصلية للمورّدين (VNDK)

في الإصدار 8.1 من نظام التشغيل Android والإصدارات الأحدث، يتضمّن نظام الإنشاء إمكانية استخدام VNDK. عند تفعيل إمكانية استخدام VNDK، يتحقّق نظام الإصدار من التبعيات بين الوحدات، وينشئ صيغة خاصة بالمورّد لوحدات المورّد، ويُثبّت هذه الوحدات تلقائيًا في الدلائل المحدّدة.

مثال على دعم إنشاء VNDK

في هذا المثال، يحدّد تعريف الوحدة Android.bp مكتبة باسم libexample. تشير السمة vendor_available إلى أنّ وحدات إطار العمل ووحدات المورّد قد تعتمد على libexample:

libexample vendor_available:true and vndk.enabled:true

تم تفعيل دعم الشكل 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/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.

حزمة 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}.

حزمة APEX لمجموعة تطوير أصلية للمورّدين (VNDK)

الشكل 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 المشترَكة هي مكتبات مشترَكة تتضمّن واجهات ثنائية مستقرة للتطبيق. يتشارك كل من إطار العمل ووحدات المورّد النمط نفسه وأحدث إصدار. بالنسبة إلى كل مكتبة مشترَكة منخفضة التأخير في 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].
  • قد يختلف مسار تثبيت حزمة APK المتغيرة الخاصة بالمورّد:
    • إذا كانت قيمة 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 تكون صيغ المورّد VND-ONLY. يتم تثبيت المكتبات المشتركة في /vendor/lib[64].
true غير صالح (خطأ في الإنشاء)
true false تكون صيغ المورّد VNDK. يتم تثبيت المكتبات المشتركة في حزمة APEX الخاصة بـ VNDK.
true تتضمّن متغيرات المورّد VNDK-SP، ويتم تثبيت المكتبات المشتركة في حزمة APEX الخاصة بـ VNDK.

false

false

false

ما مِن صِيَغ للمورّد. هذه الوحدة هي FWK-ONLY.

true غير صالح (خطأ في الإنشاء)
true false تكون صيغ المورِّد VNDK-Private. يتم تثبيت المكتبات المشتركة في حزمة APEX الخاصة بـ VNDK. ويجب ألا تستخدم وحدات المورّد هذه القيم مباشرةً.
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",
    },
}

يحدّد أحد الوحدات النمطية إضافة VNDK باستخدام السمات vendor:true وvndk.enabled:true وextends على النحو التالي:

  • يجب أن تحدّد السمة 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 فقط لأنّ السمة exclude_shared_libs تستبعد libfwk_only.

تصدير العناوين من إضافات 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