فرض واجهات أقسام المنتجات

يزيل نظام التشغيل Android 11 حزمة القسم product، ما يجعله مستقلاً عن القسمَين system وvendor. في إطار هذه التغييرات، يمكنك الآن التحكّم في إذن وصول قسم product إلى الواجهات الأصلية وواجهات Java (وهو ما يشبه طريقة عمل فرض الواجهة لأقسام vendor).

فرض استخدام الواجهات الأصلية

لتفعيل فرض استخدام الواجهة الأصلية، اضبط قيمة PRODUCT_PRODUCT_VNDK_VERSION على current. (يتم ضبط الإصدار تلقائيًا على current عندما يكون مستوى واجهة برمجة التطبيقات للشحن المستهدف أكبر من 29). تتيح ميزة "فرض القيود" ما يلي:

  • الوحدات الأصلية في القسم product المطلوب ربطه:
    • بشكل ثابت أو ديناميكي إلى وحدات أخرى في القسم product التي تتضمّن مكتبات ثابتة أو مشتركة أو مكتبات عناوين
    • بشكل ديناميكي إلى مكتبات VNDK في القسم system
  • مكتبات JNI في حِزم APK غير المجمَّعة في القسم product للربط بالمكتبات في /product/lib أو /product/lib64 (بالإضافة إلى مكتبات NDK)

لا يسمح التنفيذ بربط أقسام أخرى غير قسم product.

فرض مدة التصميم (Android.bp)

في Android 11، يمكن لوحدات النظام إنشاء صيغة لصورة المنتج بالإضافة إلى صيغ الصور الأساسية وصور المورّد. عند تفعيل فرض استخدام واجهة برمجة التطبيقات الأصلية (ضبط PRODUCT_PRODUCT_VNDK_VERSION على current):

  • تكون الوحدات الأصلية في قسم product ضمن صيغة المنتج بدلاً من الصيغة الأساسية.

  • تتوفّر الوحدات التي تتضمّن product_available: true في ملفات Android.bp لخيار المنتج.

  • يمكن للمكتبات أو الملفات الثنائية التي تحدّد product_specific: true أن ترتبط بمكتبات أخرى تحدّد product_specific: true أو product_available: true في ملفات Android.bp الخاصة بها.

  • يجب أن تحتوي مكتبات VNDK على product_available: true في ملفات Android.bp حتى تتمكّن الثنائيات product من الربط بمكتبات VNDK.

يلخّص الجدول التالي سمات Android.bp المستخدَمة لإنشاء صيغ الصور.

السمات في ملف Android.bp الخيارات التي تم إنشاؤها
قبل التنفيذ بعد التنفيذ
تلقائي (بلا) core
(يتضمّن /system و/system_ext و/product)
الأساسية
(تشمل /system و/system_ext ولكن ليس /product)
system_ext_specific: true أساسي أساسي
product_specific: true أساسي المنتج
vendor: true المُورِّد المُورِّد
vendor_available: true core, vendor core, vendor
product_available: true لا ينطبق المنتج الأساسي
vendor_available: true وproduct_available: true لا ينطبق الأساسية والمنتج والبائع
system_ext_specific: true وvendor_available: true core, vendor core, vendor
product_specific: true وvendor_available: true core, vendor المنتج، البائع

فرض مدة التصميم (Android.mk)

عند تفعيل فرض استخدام الواجهة الأصلية، يكون للوحدات الأصلية المثبَّتة في القسم product نوع رابط native:product يمكنه الربط فقط بوحدات native:product أو native:vndk أخرى. سيؤدي محاولة الربط بأي وحدات أخرى إلى أن ينشئ نظام الإنشاء خطأ في التحقّق من نوع الرابط.

فرض القيود أثناء التشغيل

عند تفعيل فرض استخدام الواجهة الأصلية، لا يسمح إعداد الرابط لبرنامج الربط bionic لعمليات النظام باستخدام مكتبات product، ما يؤدي إلى إنشاء قسم product لعمليات product التي لا يمكنها الربط بمكتبات خارج قسم product (ومع ذلك، يمكن لهذه العمليات الربط بمكتبات VNDK). تؤدي محاولات انتهاك إعدادات رابط وقت التشغيل إلى تعذُّر تنفيذ العملية وإنشاء رسالة خطأ CANNOT LINK EXECUTABLE.

فرض استخدام واجهات Java

لتفعيل فرض استخدام واجهة Java، اضبط PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE على true. (يتم ضبط القيمة تلقائيًا على true عندما يكون مستوى واجهة برمجة التطبيقات للشحن المستهدَف أكبر من 29). عند تفعيل خيار فرض القيود، يمكن السماح بالوصول إلى ما يلي أو حظره:

واجهة برمجة التطبيقات /system /system_ext /product /vendor /data
واجهة برمجة التطبيقات العامة
@SystemApi
‫@hide API

كما هو الحال في القسم vendor، لا يُسمح لتطبيق أو مكتبة Java في القسم product باستخدام سوى واجهات برمجة التطبيقات العامة وتلك الخاصة بالنظام، ولا يُسمح بالربط بمكتبة تستخدم واجهات برمجة تطبيقات مخفية. يشمل هذا القيد الربط في وقت الإنشاء والانعكاس في وقت التشغيل.

فرض مدة التصميم

أثناء وقت الإنشاء، تتحقّق أداتا Make وSoong من أنّ وحدات Java النمطية في القسم product لا تستخدم واجهات برمجة تطبيقات مخفية من خلال التحقّق من الحقلَين platform_apis وsdk_version. يجب ملء sdk_version للتطبيقات في القسم product بالقيمة current أو system_current أو الإصدار الرقمي من واجهة برمجة التطبيقات، ويجب أن يكون الحقل platform_apis فارغًا.

فرض القيود أثناء التشغيل

يتحقّق وقت تشغيل Android من أنّ التطبيقات في قسم product لا تستخدم واجهات برمجة تطبيقات مخفية، بما في ذلك الانعكاس. لمزيد من التفاصيل، يُرجى الرجوع إلى القيود المفروضة على واجهات برمجة التطبيقات غير التابعة للحزمة SDK.

تفعيل فرض استخدام واجهة المنتج

اتّبِع الخطوات الواردة في هذا القسم لتفعيل فرض استخدام واجهة المنتج.

الخطوة المهمة مطلوب
1 حدِّد ملف makefile الخاص بالنظام والذي يحدِّد حِزم قسم system، ثم اضبط عملية التحقّق من متطلبات مسار العناصر في device.mk (لمنع تثبيت الوحدات غير التابعة للنظام في قسم system). N
2 تنظيف القائمة المسموح بها N
3 فرض استخدام الواجهات الأصلية وتحديد أخطاء الربط في وقت التشغيل (يمكن تشغيلها بالتوازي مع فرض استخدام Java). Y
4 فرض استخدام واجهات Java والتحقّق من سلوك وقت التشغيل (يمكن تشغيلها بالتوازي مع عملية الفرض الأصلية) Y
5 التحقّق من سلوكيات وقت التشغيل Y
6 تعديل device.mk من خلال فرض استخدام واجهة المنتج Y

الخطوة 1: إنشاء ملف makefile وتفعيل خيار التحقّق من مسار العنصر

في هذه الخطوة، عليك تحديد system makefile.

  1. أنشِئ ملف makefile يحدّد الحِزم لقسم system. على سبيل المثال، أنشئ ملف oem_system.mk يتضمّن ما يلي:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system.mk)
    $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk)
    
    # Applications
    PRODUCT_PACKAGES += \
        CommonSystemApp1 \
        CommonSystemApp2 \
        CommonSystemApp3 \
    
    # Binaries
    PRODUCT_PACKAGES += \
        CommonSystemBin1 \
        CommonSystemBin2 \
        CommonSystemBin3 \
    
    # Libraries
    PRODUCT_PACKAGES += \
        CommonSystemLib1 \
        CommonSystemLib2 \
        CommonSystemLib3 \
    
    PRODUCT_SYSTEM_NAME := oem_system
    PRODUCT_SYSTEM_BRAND := Android
    PRODUCT_SYSTEM_MANUFACTURER := Android
    PRODUCT_SYSTEM_MODEL := oem_system
    PRODUCT_SYSTEM_DEVICE := generic
    
    # For system-as-root devices, system.img should be mounted at /, so we
    # include ROOT here.
    _my_paths := \
     $(TARGET_COPY_OUT_ROOT)/ \
     $(TARGET_COPY_OUT_SYSTEM)/ \
    
    $(call require-artifacts-in-path, $(_my_paths),)
    
  2. في الملف device.mk، يمكنك استخدام ملف makefile المشترك للقسم system وتفعيل عملية التحقّق من متطلبات مسار العنصر. مثلاً:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk)
    
    # Enable artifact path requirements checking
    PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
    

لمحة عن متطلبات مسار العنصر

عند ضبط PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS على true أو strict، يمنع نظام الإصدار تثبيت الحِزم المحدّدة في ملفات makefile الأخرى في المسارات المحدّدة في require-artifacts-in-path ويمنع تثبيت الحِزم المحدّدة في ملف makefile الحالي في العناصر خارج المسارات المحدّدة في require-artifacts-in-path.

في المثال أعلاه، عند ضبط PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS على strict، لا يمكن لملفات makefile خارج oem_system.mk أن تتضمّن وحدات مثبَّتة في القسم root أو system. لتضمين هذه الوحدات، يجب تحديدها في ملف oem_system.mk نفسه أو في ملف makefile مضمّن. تتسبّب محاولات تثبيت الوحدات في مسارات غير مسموح بها في حدوث أخطاء في الإنشاء. لحلّ مشاكل التقطّع، يُرجى اتّخاذ أحد الإجراءات التالية:

  • الخيار 1: تضمين وحدة النظام في ملفات makefile المضمّنة في oem_system.mk يؤدي ذلك إلى استيفاء متطلبات مسار العنصر (لأنّ الوحدات النمطية أصبحت متوفرة في ملف makefile مضمّن)، وبالتالي يسمح بالتثبيت في مجموعة المسارات في `require-artifacts-in-path`.

  • الخيار 2: تثبيت الوحدات النمطية في القسم system_ext أو product (مع عدم تثبيت الوحدات النمطية في القسم system).

  • الخيار 3: إضافة وحدات إلى PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST تعرض هذه القائمة الوحدات المسموح بتثبيتها.

الخطوة 2: إفراغ القائمة المسموح بها

في هذه الخطوة، عليك جعل PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST فارغًا لكي تتمكّن جميع الأجهزة التي تشارك oem_system.mk من مشاركة صورة واحدة system أيضًا. لإفراغ القائمة المسموح بها، انقل أي وحدات في القائمة إلى القسم system_ext أو product أو أضِفها إلى system لإنشاء ملفات. هذه الخطوة اختيارية لأنّ تحديد system صورة مشتركة ليس مطلوبًا لتفعيل فرض واجهة المنتج. ومع ذلك، يكون إفراغ القائمة المسموح بها مفيدًا لتحديد حدود system باستخدام system_ext.

الخطوة 3: فرض استخدام واجهات مدمجة مع المحتوى

في هذه الخطوة، عليك ضبط PRODUCT_PRODUCT_VNDK_VERSION := current، ثم البحث عن أخطاء في الإنشاء ووقت التشغيل وحلّها. للتحقّق من عملية تشغيل الجهاز والسجلات والعثور على أخطاء الربط في وقت التشغيل وإصلاحها، اتّبِع الخطوات التالية:

  1. اضبط PRODUCT_PRODUCT_VNDK_VERSION := current.

  2. أنشئ الجهاز وابحث عن أخطاء في عملية الإنشاء. من المحتمل أن تظهر بعض الأخطاء في عملية الإنشاء بسبب عدم توفّر خيارات المنتج أو الخيارات الأساسية. تشمل الفواصل الشائعة ما يلي:

    • لن تكون أي وحدة hidl_interface تتضمّن product_specific: true متاحة لوحدات النظام. لحلّ هذه المشكلة، استبدِل product_specific: true بـ system_ext_specific: true.
    • قد لا تتضمّن الوحدات خيار المنتج المطلوب لوحدات المنتج. لحلّ هذه المشكلة، يجب إتاحة الوحدة النمطية لقسم product من خلال ضبط product_available: true أو نقل الوحدة النمطية إلى قسم product من خلال ضبط product_specific: true.
  3. حلّ أخطاء الإنشاء والتأكّد من إنشاء الجهاز بنجاح

  4. تثبيت الصورة والبحث عن أخطاء وقت التشغيل في عملية تشغيل الجهاز وسجلاته

    • إذا كانت العلامة linker من سجلّ حالة الاختبار تعرض الرسالة CANNOT LINK EXECUTABLE ، يعني ذلك أنّ ملف الإنشاء يفتقد إلى عنصر تابع (ولم يتم تسجيله في وقت الإنشاء).
    • للتحقّق من ذلك من نظام الإنشاء، أضِف المكتبة المطلوبة إلى الحقل shared_libs: أو required:.
  5. حلّ المشكلة المتعلقة بالموارد الاعتمادية غير المثبَّتة باستخدام الإرشادات الواردة أعلاه

الخطوة 4: فرض استخدام واجهات Java

في هذه الخطوة، عليك ضبط PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true، ثم العثور على أخطاء الإنشاء الناتجة وإصلاحها. ابحث عن نوعَين محدّدين من الأخطاء:

  • أخطاء في نوع الرابط: يشير هذا الخطأ إلى أنّ أحد التطبيقات يرتبط بوحدات Java التي تتضمّن sdk_version أوسع. لحلّ هذه المشكلة، يمكنك توسيع sdk_version التطبيق أو حصر sdk_version المكتبة. مثال على الخطأ:

    error: frameworks/base/packages/SystemUI/Android.bp:138:1: module "SystemUI" variant "android_common": compiles against system API, but dependency "telephony-common" is compiling against private API.Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.
    
  • أخطاء الرموز يشير هذا الخطأ إلى تعذُّر العثور على رمز لأنّه مضمّن في واجهة برمجة تطبيقات مخفية. لحلّ هذه المشكلة، استخدِم واجهة برمجة تطبيقات مرئية (غير مخفية) أو ابحث عن بديل. مثال على الخطأ:

    frameworks/opt/net/voip/src/java/com/android/server/sip/SipSessionGroup.java:1051: error: cannot find symbol
                ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
                                               ^
      symbol:   class ProxyAuthenticate
      location: class SipSessionGroup.SipSessionImpl
    

الخطوة 5: التحقّق من سلوكيات وقت التشغيل

في هذه الخطوة، يمكنك التأكّد من أنّ سلوكيات وقت التشغيل هي على النحو المتوقّع. بالنسبة إلى التطبيقات التي يمكن تصحيح أخطائها، يمكنك تتبُّع استخدام واجهات برمجة التطبيقات المخفية من خلال سجلّ باستخدام StrictMode.detectNonSdkApiUsage (الذي ينشئ سجلّاً عندما يستخدم التطبيق واجهة برمجة تطبيقات مخفية). بدلاً من ذلك، يمكنك استخدام أداة التحليل الثابت veridex للحصول على نوع الاستخدام (الربط أو الانعكاس) ومستوى القيود وحزمة الاستدعاء.

  • بنية Veridex:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
  • مثال على نتيجة veridex:

    #1: Linking greylist-max-o Landroid/animation/AnimationHandler;-><init>()V use(s):
           Lcom/android/systemui/pip/phone/PipMotionHelper;-><init>(Landroid/content/Context;Landroid/app/IActivityManager;Landroid/app/IActivityTaskManager;Lcom/android/systemui/pip/phone/PipMenuActivityController;Lcom/android/internal/policy/PipSnapAlgorithm;Lcom/android/systemui/statusbar/FlingAnimationUtils;)V
    
    #1332: Reflection greylist Landroid/app/Activity;->mMainThread use(s):
           Landroidx/core/app/ActivityRecreator;->getMainThreadField()Ljava/lang/reflect/Field;
    

لمزيد من التفاصيل حول استخدام veridex، يُرجى الرجوع إلى الاختبار باستخدام أداة veridex.

الخطوة 6: تعديل ملف device.mk

بعد إصلاح جميع الأخطاء في الإنشاء ووقت التشغيل والتأكّد من أنّ سلوكيات وقت التشغيل هي كما هو متوقّع، اضبط ما يلي في device.mk:

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true