التوافق مع نظام إصدار 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.
  • تم تثبيت إصدار المورّد في VNDK APEX لأنّه vndk.enabled هو true.

لمزيد من التفاصيل، يُرجى الاطّلاع على تعريف الوحدة.

ضبط إعدادات دعم الإنشاء

لتفعيل التوافق الكامل مع نظام الإنشاء لجهاز منتج، أضِف BOARD_VNDK_VERSION إلى BoardConfig.mk:

BOARD_VNDK_VERSION := current

يكون لهذا الإعداد تأثير عام: عند تحديده في BoardConfig.mk، يتم التحقّق من جميع الوحدات. بما أنّه لا تتوفّر آلية لإدراج وحدة مزعجة في القائمة السوداء أو القائمة البيضاء، عليك إزالة كل التبعيات غير الضرورية قبل إضافة BOARD_VNDK_VERSION. يمكنك اختبار وحدة وتجميعها من خلال ضبط BOARD_VNDK_VERSION فيvariabels البيئة:

$ 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 من نظام Android والإصدارات الأقدم، تم تثبيت الوحدات التي تحتوي على vndk.enabled في /system/lib[64]/vndk[-sp]-${VER}. في الإصدار 11 من نظام التشغيل Android والإصدارات الأحدث، يتم تجميع مكتبات VNDK بتنسيق APEX، ويكون اسم VNDK APEX هو com.android.vndk.v${VER}. استنادًا إلى إعدادات الجهاز، يكون حِزمة VNDK APEX مسطّحة أو غير مسطّحة وتتوفّر من المسار الأساسي /apex/com.android.vndk.v${VER}.

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

الشكل 2: مجموعة تطوير أصلية للمورّدين (VNDK) APEX

تعريف الوحدة

لإنشاء نظام 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 هي مكتبات مشتركة تتضمّن واجهات برمجة تطبيقات ثابتة. تتشارك كلّ من وحدات الإطار العمل ووحدات المورّدين أحدث عملية تنفيذ. لكل مكتبة مشترَكة في 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
enabled
vndk
support_same_process
أوصاف الصيغ من المورّد
true false false تكون الأسعار المعروضة في خيارات المورّد بالدولار الفيتنامي فقط. يتم تثبيت المكتبات المشتركة في /vendor/lib[64].
true غير صالح (خطأ في الإنشاء)
true false الصيغ الخاصة بالمورّد هي VNDK. يتم تثبيت المكتبات المشتركة في VNDK APEX.
true تُعرف أنواع المورّدين باسم VNDK-SP. ويتم تثبيت المكتبات المشتركة في حزمة VNDK APEX.

false

false

false

ما مِن صِيَغ مورّد. هذه الوحدة مخصّصة لإطار العمل فقط.

true غير صالح (خطأ في عملية الإنشاء)
true false خيارات المورّد هي VNDK-Private. يتم تثبيت المكتبات المشترَكة في VNDK APEX. ويجب ألّا يتم استخدامها مباشرةً من خلال وحدات المورّدين.
true خيارات المورّد هي VNDK-SP-Private. يتم تثبيت المكتبات المشترَكة في VNDK APEX. ويجب ألّا يتم استخدامها مباشرةً من خلال وحدات المورّدين.

إضافات مجموعة تطوير البرامج الأصلية للمورّدين (VNDK)

إضافات VNDK هي مكتبات VNDK المشتركة التي تتضمّن واجهات برمجة تطبيقات إضافية. يتم تثبيت الإضافات في /vendor/lib[64]/vndk[-sp] (بدون إضافة اللاحقة للإصدار) وتتجاهل المكتبات المشتركة الأصلية لنظام التشغيل VNDK أثناء التشغيل.

تحديد إضافات VNDK

في الإصدار 9 من نظام التشغيل Android والإصدارات الأحدث، يتيح 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 وبيانات واجهة التطبيق الثنائية المرجعية ضمن 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 التالي، تُصدِّر 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 حارس:

#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