في 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 | الصيغ التي تم إنشاؤها | |
|---|---|---|
| قبل الفرض | بعد الفرض | |
| default (none) | core
(includes /system, /system_ext and
/product) |
core
(includes /system and /system_ext but not
/product) |
system_ext_specific: true |
core | core |
product_specific: true |
core | product |
vendor: true |
vendor | vendor |
vendor_available: true |
core, vendor | core, vendor |
product_available: true |
لا ينطبق | core, product |
vendor_available: true AND product_available:
true |
لا ينطبق | core, product, vendor |
system_ext_specific: true AND vendor_available:
true |
core, vendor | core, vendor |
product_specific: true AND vendor_available:
true |
core, vendor | product, 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 | حدِّد ملف make الخاص بالنظام الذي يحدّد الحِزم لقسم system، ثم اضبط التحقّق من متطلبات مسار العناصر في device.mk (لمنع تثبيت الوحدات غير التابعة للنظام في قسم system). |
N |
| 2 | نظِّف القائمة المسموح بها. | N |
| 3 | افرِض الواجهات الأصلية وحدِّد حالات فشل الربط في وقت التشغيل (يمكن تشغيلها بالتوازي مع فرض Java). | نعم |
| 4 | افرِض واجهات Java وتحقَّق من سلوك وقت التشغيل (يمكن تشغيلها بالتوازي مع فرض الواجهات الأصلية). | نعم |
| 5 | تحقَّق من سلوكيات وقت التشغيل. | نعم |
| 6 | عدِّل device.mk باستخدام فرض واجهة المنتج. |
نعم |
الخطوة 1: إنشاء ملف make وتفعيل التحقّق من مسار العنصر
في هذه الخطوة، عليك تحديد ملف make لقسم system.
أنشِئ ملف make يحدّد الحِزم لقسم
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),)في ملف
device.mk، استخدِم ملف make الشائع لقسم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، يمنع نظام التصميم تثبيت الحِزم المحدّدة في ملفات make الأخرى في المسارات المحدّدة في require-artifacts-in-path ويمنع تثبيت الحِزم المحدّدة في ملف make الحالي للعناصر خارج المسارات المحدّدة في require-artifacts-in-path.
في المثال أعلاه، عند ضبط PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS على
strict، لا يمكن لملفات make خارج oem_system.mk تضمين الوحدات المثبَّتة في
قسمَي root أو system. لتضمين هذه الوحدات، عليك تحديدها في ملف oem_system.mk نفسه أو في ملف make مضمَّن.
إذا حاولت تثبيت الوحدات في مسارات غير مسموح بها، سيؤدي ذلك إلى حدوث أعطال في التصميم. لإصلاح الأعطال، اتّبِع أحد الإجراءَين التاليَين:
الخيار 1: ضَمِّن وحدة النظام في ملفات make المضمَّنة في
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 أو أضِفها إلى ملفات make لقسم system. هذه الخطوة اختيارية لأنّه ليس من الضروري تحديد صورة system شائعة لتفعيل فرض واجهة المنتج. ومع ذلك، فإنّ إفراغ القائمة المسموح بها مفيد لتحديد حدود system باستخدام system_ext.
الخطوة 3: فرض الواجهات الأصلية
في هذه الخطوة، عليك ضبط PRODUCT_PRODUCT_VNDK_VERSION := current، ثم البحث عن أخطاء التصميم ووقت التشغيل وحلّها. للتحقّق من عملية تشغيل الجهاز والسجلات والعثور على حالات فشل الربط في وقت التشغيل وإصلاحها:
اضبط
PRODUCT_PRODUCT_VNDK_VERSION := current.أنشئ الجهاز وابحث عن أخطاء الإنشاء. من المحتمل أن تظهر لك بعض الأعطال في الإصدار بسبب عدم توفّر خيارات المنتجات أو صيغ النواة. تشمل الأعطال الشائعة ما يلي:
- لن تكون أي وحدة
hidl_interfaceتحتوي علىproduct_specific: trueمتاحة لوحدات النظام. لحلّ هذه المشكلة، استبدِلproduct_specific: trueبـsystem_ext_specific: true. - قد لا تحتوي الوحدات على خيار المنتج المطلوب لوحدات المنتج. لحلّ هذه المشكلة، اجعل هذه الوحدة متاحة لقسم
productمن خلال ضبطproduct_available: trueأو انقل الوحدة إلى قسمproductمن خلال ضبطproduct_specific: true.
- لن تكون أي وحدة
حِلّ أخطاء التصميم وتأكَّد من إمكانية تصميم الجهاز بنجاح.
ثبِّت الصورة وابحث عن أخطاء وقت التشغيل في عملية تشغيل الجهاز والسجلات.
- إذا كانت العلامة
linkerمن سجلّ إطار اختبار تعرض الرسالةCANNOT LINK EXECUTABLE، يعني ذلك أنّ ملف make لا يحتوي على اعتمادية (ولم يتم رصدها في مدّة التصميم). - للتحقّق من ذلك من نظام التصميم، أضِف المكتبة المطلوبة إلى الحقلَين
shared_libs:أوrequired:.
- إذا كانت العلامة
حِلّ التبعيات غير المتوفّرة باستخدام الإرشادات الواردة أعلاه.
الخطوة 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 := currentPRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true