دعم نظام بناء VNDK

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

مثال على دعم بناء VNDK

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

libexample sales_available:true وvndk.enabled:true

الشكل 1. تمكين دعم VNDK

يعتمد كل من إطار العمل القابل للتنفيذ /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 .

في إن دي كيه أبيكس

في نظام التشغيل Android 10 والإصدارات الأقدم، تم تثبيت الوحدات ذات 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. قمة 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 المشتركة هي مكتبات مشتركة ذات واجهات 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 ، فقد يتم إنشاء متغيرين ( الأساسي والمورد ). يجب التعامل مع المتغير الأساسي كوحدة إطارية ويجب التعامل مع متغير البائع كوحدة بائع. إذا كانت بعض وحدات إطار العمل تعتمد على هذه الوحدة، فسيتم إنشاء المتغير الأساسي. إذا كانت بعض وحدات البائع تعتمد على هذه الوحدة، فسيتم إنشاء متغير البائع. يفرض نظام البناء فحوصات التبعية التالية:

  • يكون المتغير الأساسي دائمًا إطارًا فقط ولا يمكن الوصول إليه من قبل وحدات البائع.
  • لا يمكن دائمًا الوصول إلى متغير البائع لوحدات إطار العمل.
  • يجب أن تكون جميع التبعيات الخاصة بمتغير البائع، والتي تم تحديدها في 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} ).

يلخص الجدول أدناه كيفية تعامل نظام البناء مع متغيرات البائع:

بائع_متوفر vndk
ممكن
vndk
support_same_process
أوصاف متغيرات البائع
true false false متغيرات البائع هي VND-ONLY . يتم تثبيت المكتبات المشتركة في /vendor/lib[64] .
true غير صالح (خطأ في الإنشاء)
true false متغيرات البائع هي VNDK . تم تثبيت المكتبات المشتركة على VNDK APEX.
true متغيرات البائع هي VNDK-SP . تم تثبيت المكتبات المشتركة على VNDK APEX.

false

false

false

لا توجد متغيرات البائع. هذه الوحدة هي FWK فقط .

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

ملحقات 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

المتطلبات على الرموز المصدرة

يقوم مدقق VNDK ABI بمقارنة ABI لمتغيرات بائعي 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 في اتباع المتطلبات المذكورة أعلاه، فسيقوم مدقق 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 :

  • 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 فقط، بينما يصدر 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