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

يقوم 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 تم إنشاء المتغيرات
قبل التنفيذ بعد التنفيذ
الافتراضي (لا شيء) جوهر

(يتضمن /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 . تؤدي محاولة الارتباط بأي وحدات نمطية غير هذه إلى قيام نظام الإنشاء بإنشاء خطأ في التحقق من نوع الارتباط.

إنفاذ وقت التشغيل

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

فرض واجهات جافا

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

واجهة برمجة التطبيقات /نظام /system_ext /منتج /بائع /بيانات
واجهة برمجة التطبيقات العامة
@SystemApi
@إخفاء واجهة برمجة التطبيقات

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

بناء إنفاذ الوقت

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

إنفاذ وقت التشغيل

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

تمكين إنفاذ واجهة المنتج

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

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

الخطوة 1: إنشاء ملف تعريفي وتمكين التحقق من مسار القطعة الأثرية

في هذه الخطوة، يمكنك تحديد ملف تعريف 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 ، يمنع نظام البناء الحزم المحددة في ملفات تكوين أخرى من التثبيت على المسارات المحددة في 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 . يؤدي ذلك إلى استيفاء متطلبات المسار المصنوع (حيث أن الوحدات النمطية موجودة الآن في ملف تكوين مضمن) وبالتالي يسمح بالتثبيت على مجموعة المسارات في "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_specfic: 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 للحصول على نوع الاستخدام (الربط أو الانعكاس)، ومستوى التقييد، ومكدس الاستدعاءات.

  • بناء جملة فيريديكس:

    ./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