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

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

فرض واجهات أصلية

لتفعيل فرض استخدام الواجهة الأصلية، اضبط PRODUCT_PRODUCT_VNDK_VERSION على current. (يتم ضبط الإصدار تلقائيًا على current عندما يكون مستوى shipping API للهدف أكبر من 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 الأسعار المتغيرة التي تم إنشاؤها
قبل التنفيذ بعد التنفيذ
تلقائي (بدون) الأساسية
(تشمل /system و/system_ext /product)
الأساسية
(تشمل /system و/system_ext ولكن ليس /product)
system_ext_specific: true قلب الأساسية
product_specific: true الأساسية المنتج
vendor: true المُورِّد المُورِّد
vendor_available: true الأساسية، المورّد الأساسية، المورّد
product_available: true لا ينطبق أساسي، منتج
vendor_available: true وproduct_available: true لا ينطبق الأساسية، المنتج، المورّد
system_ext_specific: true وvendor_available: true الأساسية، المورّد الأساسية، المورّد
product_specific: true وvendor_available: true الأساسية، المورّد المنتج، المورّد

فرض وقت التصميم (ملف 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 عندما يكون مستوى Shipping API للهدف أكبر من 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 حدِّد ملف make الخاص بالنظام الذي يحدِّد الحِزم للقسيمة system، ثم اضبط عملية التحقّق من متطلبات مسار العناصر في device.mk (لمنع تثبيت وحدات غير نظامية على قسم system). N
2 تنظيف القائمة المسموح بها N
3 فرض الواجهات الأصلية وتحديد حالات تعذُّر ربط وقت التشغيل (يمكن تشغيله في موازاةً مع فرض Java) Y
4 يمكنك فرض واجهات Java والتحقُّق من سلوك بيئة التشغيل (يمكن أن يتم تشغيله بالتوازي مع التنفيذ الأصلي). Y
5 التحقّق من سلوكيات وقت التشغيل Y
6 تعديل device.mk مع فرض واجهة المنتج Y

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

في هذه الخطوة، يمكنك تحديد ملف الإنشاء system.

  1. يمكنك إنشاء ملف إعداد يحدد الحِزم للقسم 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، لا يمكن أن تتضمّن ملفات الإنشاء خارج oem_system.mk وحدات تم تثبيتها في القسم root أو system. لتضمين هذه الوحدات، عليك تحديدها في ملف oem_system.mk نفسه أو في ملف makefile مضمَّن. تؤدي محاولات تثبيت الوحدات في مسارات غير مسموح بها إلى حدوث أعطال في عملية الإنشاء. لحلّ مشكلة المقاطعات، نفِّذ أحد الإجراءات التالية:

  • الخيار 1: تضمين وحدة النظام في ملفات makefiles المضمّنة في oem_system.mk. يؤدي ذلك إلى استيفاء متطلبات مسار العنصر (بما أنّه تتوفر الوحدات الآن في ملف make مضمّن)، وبالتالي يسمح بالتركيب في مجموعة المسارات في 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 ، يعني ذلك أنّ ملف make لا يتضمّن عنصرًا تابعًا (لم يتم تسجيله في وقت compiling).
    • للتحقّق من المكتبة من نظام التصميم، أضِف المكتبة المطلوبة إلى الحقل 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