تنسيق ملف APEX

تم تقديم تنسيق حاوية Android Pony EXpress (APEX) في Android 10 ويتم استخدامه في تدفق التثبيت لوحدات النظام ذات المستوى الأدنى. يسهل هذا التنسيق تحديثات مكونات النظام التي لا تتناسب مع نموذج تطبيق Android القياسي. من أمثلة المكونات الخدمات والمكتبات الأصلية وطبقات تجريد الأجهزة ( HALs ) ووقت التشغيل ( ART ) ومكتبات الفئات.

يمكن أن يشير المصطلح "APEX" أيضًا إلى ملف APEX.

خلفية

على الرغم من أن Android يدعم تحديثات الوحدات النمطية التي تتلاءم مع نموذج التطبيق القياسي (على سبيل المثال ، الخدمات والأنشطة) عبر تطبيقات مثبت الحزمة (مثل تطبيق متجر Google Play) ، فإن استخدام نموذج مشابه لمكونات نظام التشغيل منخفضة المستوى له العيوب التالية:

  • لا يمكن استخدام الوحدات المستندة إلى APK في وقت مبكر من تسلسل التمهيد. مدير الحزم هو المستودع المركزي للمعلومات حول التطبيقات ولا يمكن تشغيله إلا من مدير النشاط ، والذي يصبح جاهزًا في مرحلة لاحقة من إجراء التمهيد.
  • تم تصميم تنسيق APK (خاصة البيان) لتطبيقات Android ولا تكون وحدات النظام مناسبة دائمًا.

تصميم

يصف هذا القسم التصميم عالي المستوى لتنسيق ملف APEX ومدير APEX ، وهي خدمة تدير ملفات APEX.

لمزيد من المعلومات حول سبب اختيار هذا التصميم لـ APEX ، راجع البدائل التي تم أخذها في الاعتبار عند تطوير APEX .

شكل APEX

هذا هو تنسيق ملف APEX.

تنسيق ملف APEX

الشكل 1. تنسيق ملف APEX

في المستوى الأعلى ، ملف APEX هو ملف مضغوط يتم فيه تخزين الملفات غير المضغوطة والموجودة في حدود 4 كيلوبايت.

الملفات الأربعة في ملف APEX هي:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

يحتوي ملف apex_manifest.json على اسم الحزمة وإصدارها ، اللذين يحددان ملف APEX.

يسمح ملف AndroidManifest.xml لملف APEX باستخدام الأدوات والبنية التحتية المتعلقة بـ APK مثل ADB و PackageManager وتطبيقات مثبت الحزم (مثل Play Store). على سبيل المثال ، يمكن لملف APEX استخدام أداة موجودة مثل aapt لفحص البيانات الوصفية الأساسية من الملف. يحتوي الملف على اسم الحزمة ومعلومات الإصدار. هذه المعلومات متاحة أيضًا بشكل عام في apex_manifest.json .

يوصى باستخدام apex_manifest.json على AndroidManifest.xml للحصول على كود وأنظمة جديدة تتعامل مع APEX. قد يحتوي AndroidManifest.xml على معلومات استهداف إضافية يمكن استخدامها بواسطة أدوات نشر التطبيق الحالية.

apex_payload.img هي صورة نظام ملفات ext4 مدعومة بـ dm-verity. يتم تثبيت الصورة في وقت التشغيل عبر جهاز استرجاع. على وجه التحديد ، يتم إنشاء شجرة التجزئة وكتلة البيانات الوصفية باستخدام مكتبة libavb . لم يتم تحليل حمولة نظام الملفات (لأن الصورة يجب أن تكون قابلة للتركيب في مكانها). يتم تضمين الملفات العادية داخل ملف apex_payload.img .

apex_pubkey هو المفتاح العام المستخدم لتوقيع صورة نظام الملفات. في وقت التشغيل ، يضمن هذا المفتاح أن يتم توقيع APEX الذي تم تنزيله بنفس الكيان الذي يوقع نفس APEX في الأقسام المضمنة.

مدير APEX

مدير APEX (أو apexd ) هو عملية أصلية قائمة بذاتها مسؤولة عن التحقق من ملفات APEX وتثبيتها وإلغاء تثبيتها. تم إطلاق هذه العملية وهي جاهزة في وقت مبكر من تسلسل التمهيد. عادةً ما يتم تثبيت ملفات APEX مسبقًا على الجهاز تحت /system/apex . يتم تعيين مدير APEX افتراضيًا لاستخدام هذه الحزم في حالة عدم توفر تحديثات.

يستخدم تسلسل التحديث الخاص بـ APEX فئة PackageManager وهو على النحو التالي.

  1. يتم تنزيل ملف APEX عبر تطبيق مثبت الحزمة أو ADB أو أي مصدر آخر.
  2. يبدأ مدير الحزم إجراء التثبيت. عند التعرف على أن الملف هو APEX ، يقوم مدير الحزم بنقل التحكم إلى مدير APEX.
  3. يتحقق مدير APEX من ملف APEX.
  4. إذا تم التحقق من ملف APEX ، يتم تحديث قاعدة البيانات الداخلية لمدير APEX لتعكس تنشيط ملف APEX عند التمهيد التالي.
  5. يتلقى طالب التثبيت بثًا عند التحقق من الحزمة بنجاح.
  6. لمتابعة التثبيت ، يجب إعادة تشغيل النظام.
  7. في التمهيد التالي ، يبدأ مدير APEX ، ويقرأ قاعدة البيانات الداخلية ، ويقوم بما يلي لكل ملف APEX مدرج:

    1. يتحقق من ملف APEX.
    2. ينشئ جهاز استرجاع من ملف APEX.
    3. ينشئ جهاز حظر مخطط الجهاز أعلى جهاز الاسترجاع.
    4. يقوم بتركيب جهاز حظر مخطط الجهاز على مسار فريد (على سبيل المثال ، /apex/ name @ ver ).

عندما يتم تحميل جميع ملفات APEX المدرجة في قاعدة البيانات الداخلية ، يوفر مدير APEX خدمة ربط لمكونات النظام الأخرى للاستعلام عن معلومات حول ملفات APEX المثبتة. على سبيل المثال ، يمكن لمكونات النظام الأخرى الاستعلام عن قائمة ملفات APEX المثبتة في الجهاز أو الاستعلام عن المسار الدقيق حيث يتم تثبيت APEX معين ، بحيث يمكن الوصول إلى الملفات.

ملفات APEX هي ملفات APK

ملفات APEX هي ملفات APK صالحة لأنها أرشيفات مضغوطة موقعة (باستخدام مخطط توقيع APK) تحتوي على ملف AndroidManifest.xml . يتيح ذلك لملفات APEX استخدام البنية الأساسية لملفات APK ، مثل تطبيق مثبت الحزمة ، وأداة التوقيع ، ومدير الحزم.

يكون ملف AndroidManifest.xml داخل ملف APEX في حده الأدنى ، ويتكون من name الحزمة ورمز الإصدار و versionCode الاختياري و targetSdkVersion و maxSdkVersion minSdkVersion الدقيق. تسمح هذه المعلومات بتسليم ملفات APEX عبر القنوات الحالية مثل تطبيقات مثبت الحزم و ADB.

أنواع الملفات المدعومة

يدعم تنسيق APEX أنواع الملفات التالية:

  • أصلية مشتركة libs
  • الملفات التنفيذية الأصلية
  • ملفات JAR
  • ملفات البيانات
  • ملفات التكوين

هذا لا يعني أنه يمكن لـ APEX تحديث جميع أنواع الملفات هذه. تعتمد إمكانية تحديث نوع الملف على النظام الأساسي ومدى استقرار تعريفات الواجهات لأنواع الملفات.

التوقيع

يتم توقيع ملفات APEX بطريقتين. أولاً ، يتم توقيع الملف apex_payload.img (على وجه التحديد ، واصف vbmeta الملحق apex_payload.img ) بمفتاح. بعد ذلك ، يتم توقيع APEX بالكامل باستخدام نظام توقيع APK v3 . يتم استخدام مفتاحين مختلفين في هذه العملية.

على جانب الجهاز ، يتم تثبيت مفتاح عام يتوافق مع المفتاح الخاص المستخدم لتوقيع واصف vbmeta. يستخدم مدير APEX المفتاح العام للتحقق من APEXes المطلوب تثبيتها. يجب توقيع كل APEX بمفاتيح مختلفة ويتم فرضها في وقت الإنشاء ووقت التشغيل.

APEX في أقسام مدمجة

يمكن أن توجد ملفات APEX في أقسام مدمجة مثل /system . القسم بالفعل فوق dm-verity ، لذلك يتم تحميل ملفات APEX مباشرة فوق جهاز الاسترجاع.

إذا كان APEX موجودًا في قسم مضمن ، فيمكن تحديث APEX من خلال توفير حزمة APEX بنفس اسم الحزمة وأكبر من رمز الإصدار أو مساوٍ له. يتم تخزين APEX الجديد في /data ، وعلى غرار ملفات APK ، يقوم الإصدار المثبت حديثًا بتظليل الإصدار الموجود بالفعل في القسم المدمج. ولكن على عكس ملفات APK ، لا يتم تنشيط الإصدار المثبت حديثًا من APEX إلا ​​بعد إعادة التشغيل.

متطلبات Kernel

لدعم وحدات APEX mainline على جهاز Android ، فإن ميزات Linux kernel التالية مطلوبة: برنامج تشغيل الاسترجاع و dm-verity. يقوم برنامج تشغيل الاسترجاع بتثبيت صورة نظام الملفات في وحدة APEX ويتحقق dm-verity من وحدة APEX.

يعد أداء برنامج تشغيل الاسترجاع و dm-verity مهمين في تحقيق أداء جيد للنظام عند استخدام وحدات APEX.

إصدارات kernel المدعومة

يتم دعم وحدات APEX الرئيسية على الأجهزة التي تستخدم إصدارات kernel 4.4 أو أعلى. يجب أن تستخدم الأجهزة الجديدة التي تعمل بنظام Android 10 أو أعلى إصدار kernel 4.9 أو أعلى لدعم وحدات APEX.

تصحيحات النواة المطلوبة

يتم تضمين تصحيحات kernel المطلوبة لدعم وحدات APEX في شجرة Android الشائعة. للحصول على التصحيحات لدعم APEX ، استخدم أحدث إصدار من شجرة Android الشائعة.

إصدار Kernel 4.4.2

هذا الإصدار مدعوم فقط للأجهزة التي تمت ترقيتها من Android 9 إلى Android 10 وتريد دعم وحدات APEX. للحصول على التصحيحات المطلوبة ، يوصى بشدة بإجراء دمج لأسفل من فرع android-4.4 . فيما يلي قائمة بالتصحيحات الفردية المطلوبة للإصدار 4.4 من kernel.

  • UPSTREAM: حلقة: إضافة ioctl لتغيير حجم الكتلة المنطقية ( 4.4 )
  • BACKPORT: كتلة / حلقة: ضبط hw_sectors ( 4.4 )
  • UPSTREAM: حلقة: إضافة LOOP_SET_BLOCK_SIZE في التوافق ioctl ( 4.4 )
  • ANDROID: mnt: إصلاح next_descendent ( 4.4 )
  • ANDROID: mnt: يجب أن ينتشر remount على عبيد العبيد ( 4.4 )
  • ANDROID: mnt: نشر إعادة التحميل بشكل صحيح ( 4.4 )
  • العودة إلى "ANDROID: dm verity: إضافة الحد الأدنى لحجم الجلب المسبق" ( 4.4 )
  • UPSTREAM: حلقة: إسقاط ذاكرة التخزين المؤقت إذا تم تغيير الإزاحة أو block_size ( 4.4 )

إصدارات Kernel 4.9 / 4.14 / 4.19

للحصول على التصحيحات المطلوبة لإصدارات kernel 4.9 / 4.14 / 4.19 ، قم بإجراء دمج لأسفل من فرع android-common .

خيارات تكوين النواة المطلوبة

توضح القائمة التالية متطلبات التكوين الأساسية لدعم وحدات APEX التي تم تقديمها في Android 10. العناصر التي تحمل علامة النجمة (*) هي متطلبات حالية من Android 9 والإصدارات الأقدم.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

متطلبات معلمة سطر أوامر Kernel

لدعم APEX ، تأكد من أن معلمات سطر أوامر kernel تفي بالمتطلبات التالية:

  • يجب عدم تعيين loop.max_loop
  • يجب أن تكون loop.max_part <= 8

بناء APEX

يصف هذا القسم كيفية إنشاء APEX باستخدام نظام إنشاء Android. فيما يلي مثال على Android.bp لـ APEX المسمى apex.test .

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

مثال على apex_manifest.json :

{
  "name": "com.android.example.apex",
  "version": 1
}

مثال file_contexts :

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

أنواع الملفات والمواقع في APEX

نوع الملف الموقع في APEX
مكتبات مشتركة /lib و /lib64 ( /lib/arm لـ arm في x86)
الملفات القابلة للتنفيذ /bin
مكتبات جافا /javalib
التجهيز المسبق /etc

التبعيات المتعدية

تتضمن ملفات APEX تلقائيًا تبعيات متعدية من libs أو الملفات التنفيذية المشتركة الأصلية. على سبيل المثال ، إذا كان libFoo يعتمد على libBar ، فسيتم تضمين libFoo عند إدراج libFoo فقط في الخاصية native_shared_libs .

التعامل مع العديد من ABIs

قم بتثبيت خاصية native_shared_libs لكل من واجهات التطبيق الثنائية (ABI) الأولية والثانوية للجهاز. إذا كان APEX يستهدف أجهزة بها ABI واحد (أي 32 بت فقط أو 64 بت فقط) ، يتم تثبيت المكتبات التي تحتوي على ABI المقابل فقط.

قم بتثبيت خاصية binaries فقط لـ ABI الأساسي للجهاز كما هو موضح أدناه:

  • إذا كان الجهاز 32 بت فقط ، يتم تثبيت متغير 32 بت فقط من الثنائي.
  • إذا كان الجهاز 64 بت فقط ، فسيتم تثبيت الإصدار 64 بت فقط من البرنامج الثنائي.

لإضافة تحكم دقيق في ABI للمكتبات والثنائيات الأصلية ، استخدم multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] .

  • first : يطابق ABI الأساسي للجهاز. هذا هو الإعداد الافتراضي للثنائيات.
  • lib32 : يطابق 32 بت ABI للجهاز ، إذا كان مدعومًا.
  • lib64 : يطابق 64 بت ABI للجهاز ، وهو مدعوم.
  • prefer32 : يطابق 32 بت ABI للجهاز ، إذا كان مدعومًا. إذا كان 32 بت ABI غير مدعوم ، يتطابق مع 64 بت ABI.
  • both : يطابق كلا من ABIs. هذا هو الإعداد الافتراضي native_shared_libraries .

تعتبر خصائص java و libraries و prebuilts لـ ABI.

هذا المثال لجهاز يدعم 32/64 ولا يفضل 32:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

توقيع vbmeta

قم بتوقيع كل APEX بمفاتيح مختلفة. عندما يكون مفتاح جديد مطلوبًا ، قم بإنشاء زوج مفاتيح عام-خاص وإنشاء وحدة apex_key . استخدم خاصية key للتوقيع على APEX باستخدام المفتاح. يتم تضمين المفتاح العام تلقائيًا في APEX باسم avb_pubkey .

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

في المثال أعلاه ، يصبح اسم المفتاح العمومي ( foo ) هو معرف المفتاح. يتم كتابة معرف المفتاح المستخدم لتوقيع APEX في APEX. في وقت التشغيل ، يتحقق apexd من APEX باستخدام مفتاح عام له نفس المعرف في الجهاز.

توقيع مضغوط

قم بالتوقيع على APEXes بنفس طريقة توقيعك على ملفات APK. توقيع APEXes مرتين ؛ مرة واحدة لنظام الملفات المصغرة (ملف apex_payload.img ) ومرة ​​واحدة للملف بأكمله.

لتوقيع APEX على مستوى الملف ، قم بتعيين خاصية certificate بإحدى هذه الطرق الثلاث:

  • لم يتم التعيين: إذا لم يتم تعيين أي قيمة ، فسيتم توقيع APEX بالشهادة الموجودة في PRODUCT_DEFAULT_DEV_CERTIFICATE . إذا لم يتم تعيين علامة ، فسيتم تعيين المسار افتراضيًا على build/target/product/security/testkey .
  • <name> : تم توقيع APEX بشهادة <name> في نفس الدليل مثل PRODUCT_DEFAULT_DEV_CERTIFICATE .
  • :<name> : يتم توقيع APEX بالشهادة التي تم تحديدها بواسطة وحدة Soong المسماة <name> . يمكن تعريف وحدة الشهادة على النحو التالي.
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

تثبيت APEX

لتثبيت APEX ، استخدم ADB.

adb install apex_file_name
adb reboot

باستخدام APEX

بعد إعادة التشغيل ، يتم تحميل APEX في الدليل /apex/<apex_name>@<version> . يمكن تركيب إصدارات متعددة من نفس APEX في نفس الوقت. من بين مسارات التحميل ، المسار الذي يتوافق مع أحدث إصدار مُثبت بالربط في /apex/<apex_name> .

يمكن للعملاء استخدام مسار الربط لقراءة أو تنفيذ الملفات من APEX.

يتم استخدام APEXes عادةً على النحو التالي:

  1. يقوم OEM أو ODM بالتحميل المسبق لـ APEX ضمن /system/apex عند شحن الجهاز.
  2. يتم الوصول إلى الملفات الموجودة في APEX عبر المسار /apex/<apex_name>/ .
  3. عند تثبيت إصدار محدث من APEX في /data/apex ، يشير المسار إلى APEX الجديد بعد إعادة التشغيل.

تحديث الخدمة مع APEX

لتحديث خدمة باستخدام APEX:

  1. ضع علامة على الخدمة في قسم النظام على أنها قابلة للتحديث. أضف الخيار updatable إلى تعريف الخدمة.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. قم بإنشاء ملف .rc جديد للخدمة المحدثة. استخدم خيار override لإعادة تعريف الخدمة الحالية.

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

يمكن تعريف تعريفات الخدمة فقط في ملف .rc الخاص بـ APEX. مشغلات الإجراءات غير مدعومة في APEXes.

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

تكوين النظام لدعم تحديثات APEX

اضبط خاصية النظام التالية على true لدعم تحديثات ملف APEX.

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

أو فقط

<device.mk>:

$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)

بالارض APEX

بالنسبة للأجهزة القديمة ، في بعض الأحيان يكون من المستحيل أو غير المجدي تحديث النواة القديمة لدعم APEX بشكل كامل. على سبيل المثال ، ربما تم بناء النواة بدون CONFIG_BLK_DEV_LOOP=Y ، وهو أمر بالغ الأهمية لتركيب صورة نظام الملفات داخل APEX.

APEX المسطح عبارة عن APEX مبني خصيصًا ويمكن تنشيطه على الأجهزة ذات النواة القديمة. يتم تثبيت الملفات الموجودة في APEX المسطح مباشرة إلى دليل أسفل القسم المدمج. على سبيل المثال ، lib/libFoo.so في APEX المسطح مثبت my.apex على /system/apex/my.apex/lib/libFoo.so .

لا يتضمن تنشيط APEX المسطح جهاز الحلقة. يتم ربط الدليل بالكامل /system/apex/my.apex مباشرة بـ /apex/name@ver .

لا يمكن تحديث واجهات APEX المسطحة عن طريق تنزيل إصدارات محدثة من APEXes من الشبكة لأنه لا يمكن تسوية APEXes التي تم تنزيلها. لا يمكن تحديث أجهزة APEX المسطحة إلا عبر OTA العادي.

APEX المسطح هو التكوين الافتراضي. هذا يعني أن جميع أجهزة APEX يتم تسويتها افتراضيًا إلا إذا قمت بتكوين جهازك بشكل صريح لإنشاء واجهات APEX غير مسطحة لدعم تحديثات APEX (كما هو موضح أعلاه).

لا يتم دعم الخلط بين أجهزة APEX المسطحة وغير المسطحة في الجهاز. يجب أن تكون أجهزة APEX في الجهاز إما غير مسطحة أو كلها مسطحة. هذا مهم بشكل خاص عند شحن أعمدة APEX مسبقة التوقيع لمشاريع مثل Mainline. يجب أيضًا أن تكون APEX التي لم يتم تعيينها مسبقًا (أي التي تم إنشاؤها من المصدر) غير مسطحة وموقعة بالمفاتيح المناسبة. يجب أن يرث الجهاز من updatable_apex.mk كما هو موضح في تحديث الخدمة باستخدام APEX .

أبكس مضغوط

يتميز نظام Android 12 والإصدارات الأحدث بضغط APEX لتقليل تأثير التخزين لحزم APEX القابلة للتحديث. بعد تثبيت تحديث لـ APEX ، على الرغم من عدم استخدام نسخته المثبتة مسبقًا ، إلا أنها لا تزال تشغل نفس القدر من المساحة. تلك المساحة المشغولة لا تزال غير متوفرة.

يقلل ضغط APEX من تأثير التخزين هذا باستخدام مجموعة مضغوطة للغاية من ملفات APEX على أقسام للقراءة فقط (مثل قسم /system ). يستخدم Android 12 والإصدارات الأحدث خوارزمية ضغط DEFLATE.

لا يوفر الضغط تحسينًا لما يلي:

  • Bootstrap APEXes المطلوب تركيبها في وقت مبكر جدًا في تسلسل التمهيد.

  • APEXes غير قابلة للتحديث. يكون الضغط مفيدًا فقط إذا تم تثبيت إصدار محدث من APEX على قسم /data . تتوفر قائمة كاملة بأجهزة APEX القابلة للتحديث في صفحة مكونات النظام المعيارية .

  • ديناميكية libs المشتركة APEXes. نظرًا لأن apexd دائمًا بتنشيط كلا الإصدارين من APEXes (مثبتة مسبقًا ومُحدَّثة) ، فإن ضغطهما لا يضيف قيمة.

تنسيق ملف APEX المضغوط

هذا هو تنسيق ملف APEX المضغوط.

Diagram shows the format of a compressed APEX file

الشكل 2. تنسيق ملف APEX المضغوط

في المستوى الأعلى ، ملف APEX المضغوط هو ملف مضغوط يحتوي على ملف القمة الأصلي في شكل مفرغ من الهواء بمستوى ضغط 9 ، ومع ملفات أخرى مخزنة غير مضغوطة.

أربعة ملفات تشكل ملف APEX:

  • original_apex : مفرغ من الهواء بمستوى ضغط 9 هذا هو ملف APEX الأصلي غير المضغوط.
  • apex_manifest.pb : مخزن فقط
  • AndroidManifest.xml : مخزن فقط
  • apex_pubkey : مخزن فقط

apex_manifest.pb و AndroidManifest.xml و apex_pubkey هي نسخ من الملفات المقابلة لها في original_apex .

بناء مضغوط APEX

يمكن إنشاء APEX المضغوط باستخدام أداة apex_compression_tool.py الموجودة في system/apex/tools .

تتوفر العديد من المعلمات المتعلقة بضغط APEX في نظام الإنشاء.

في Android.bp ، يتم التحكم في ما إذا كان ملف APEX قابلاً للضغط بواسطة الخاصية compressible :

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

تتحكم علامة منتج PRODUCT_COMPRESSED_APEX في ما إذا كان يجب أن تحتوي صورة النظام التي تم إنشاؤها من المصدر على ملفات APEX مضغوطة.

بالنسبة للتجارب المحلية ، يمكنك إجبار التصميم على ضغط APEXes عن طريق تعيين OVERRIDE_PRODUCT_COMPRESSED_APEX= إلى true .

تحتوي ملفات APEX المضغوطة التي تم إنشاؤها بواسطة نظام الإنشاء على الامتداد .capex . يسهل الامتداد التمييز بين الإصدارات المضغوطة وغير المضغوطة لملف APEX.

خوارزميات الضغط المدعومة

يدعم Android 12 فقط ضغط الانكماش المضغوط.

تفعيل ملف APEX مضغوط أثناء الإقلاع

قبل أن يتم تنشيط APEX المضغوط ، يتم فك ضغط ملف original_apex الموجود بداخله في الدليل /data/apex/decompressed . ملف APEX الناتج الذي تم فك ضغطه مرتبط بشدة بالدليل /data/apex/active .

ضع في اعتبارك المثال التالي كتوضيح للعملية الموضحة أعلاه.

ضع في اعتبارك /system/apex/com.android.foo.capex باعتباره APEX مضغوطًا قيد التنشيط ، مع كود الإصدار 37.

  1. يتم فك ضغط ملف original_apex الموجود داخل /system/apex/com.android.foo.capex إلى /data/apex/decompressed/com.android.foo@37.apex .
  2. يتم تنفيذ restorecon /data/apex/decompressed/com.android.foo@37.apex للتحقق من أنه يحتوي على ملصق SELinux صحيح.
  3. يتم إجراء فحوصات التحقق على /data/apex/decompressed/com.android.foo@37.apex للتأكد من صلاحيتها: يتحقق apexd من المفتاح العام المجمّع في /data/apex/decompressed/com.android.foo@37.apex إلى تحقق من أنه يساوي الحزمة المجمعة في /system/apex/com.android.foo.capex .
  4. الملف /data/apex/decompressed/com.android.foo@37.apex مرتبط /data/apex/active/com.android.foo@37.apex .
  5. يتم تنفيذ منطق التنشيط العادي لملفات APEX غير المضغوطة على /data/apex/active/com.android.foo@37.apex .

التفاعل مع OTA

ملفات APEX المضغوطة لها آثار على تسليم وتطبيق OTA. نظرًا لأن تحديث OTA قد يحتوي على ملف APEX مضغوط بمستوى إصدار أعلى مما هو نشط على الجهاز ، يجب حجز قدر معين من المساحة الحرة قبل إعادة تشغيل الجهاز لتطبيق تحديث OTA.

لدعم نظام OTA ، تكشف apexd هاتين واجهتي API الموثقين:

  • calculateSizeForCompressedApex - حساب الحجم المطلوب لفك ضغط ملفات APEX في حزمة OTA. يمكن استخدام هذا للتحقق من أن الجهاز به مساحة كافية قبل تنزيل OTA.
  • reserveSpaceForCompressedApex - يحتفظ بمساحة على القرص للاستخدام المستقبلي بواسطة apexd لفك ضغط ملفات APEX المضغوطة داخل حزمة OTA.

في حالة تحديث A / B OTA ، يحاول apexd فك الضغط في الخلفية كجزء من روتين OTA بعد التثبيت. في حالة فشل إلغاء الضغط ، يقوم apexd الضغط أثناء التمهيد الذي يطبق تحديث OTA.

البدائل التي تم أخذها في الاعتبار عند تطوير APEX

فيما يلي بعض الخيارات التي أخذتها AOSP في الاعتبار عند تصميم تنسيق ملف APEX ، ولماذا تم تضمينها أو استبعادها.

أنظمة إدارة الحزم العادية

تحتوي توزيعات Linux على أنظمة إدارة الحزم مثل dpkg و rpm ، وهي قوية وناضجة وقوية. ومع ذلك ، لم يتم اعتمادها لـ APEX لأنها لا تستطيع حماية الحزم بعد التثبيت. يتم التحقق فقط عندما يتم تثبيت الحزم. يمكن للمهاجمين كسر تكامل الحزم المثبتة دون أن يلاحظها أحد. هذا انحدار لنظام Android حيث تم تخزين جميع مكونات النظام في أنظمة ملفات للقراءة فقط والتي يتم حماية سلامتها بواسطة dm-verity لكل إدخال / إخراج. يجب إما حظر أي تلاعب في مكونات النظام ، أو يمكن اكتشافه بحيث يمكن للجهاز رفض التمهيد إذا تم اختراقه.

dm-crypt من أجل النزاهة

الملفات الموجودة في حاوية APEX هي من أقسام مدمجة (على سبيل المثال ، قسم /system ) محمية بواسطة dm-verity ، حيث يُحظر أي تعديل على الملفات حتى بعد تثبيت الأقسام. لتوفير نفس مستوى الأمان للملفات ، يتم تخزين جميع الملفات الموجودة في APEX في صورة نظام ملفات مقترنة بشجرة تجزئة وموصف vbmeta. بدون dm-verity ، يكون APEX الموجود في قسم /data عرضة للتعديلات غير المقصودة التي يتم إجراؤها بعد التحقق من صحة الجهاز وتثبيته.

في الواقع ، قسم /data محمي أيضًا بطبقات تشفير مثل dm-crypt. على الرغم من أن هذا يوفر مستوى معينًا من الحماية ضد العبث ، إلا أن الغرض الأساسي منه هو الخصوصية وليس النزاهة. عندما يحصل مهاجم على حق الوصول إلى قسم /data ، فلا يمكن أن يكون هناك مزيد من الحماية ، وهذا مرة أخرى يعد تراجعًا مقارنة بكل مكون نظام موجود في قسم /system . توفر شجرة التجزئة داخل ملف APEX جنبًا إلى جنب مع dm-verity نفس مستوى حماية المحتوى.

إعادة توجيه المسارات من / النظام إلى / قمة

يمكن الوصول إلى ملفات مكونات النظام التي تم حزمها في APEX عبر مسارات جديدة مثل /apex/<name>/lib/libfoo.so . عندما كانت الملفات جزءًا من قسم /system ، كان يمكن الوصول إليها عبر مسارات مثل /system/lib/libfoo.so . يجب أن يستخدم عميل ملف APEX (ملفات APEX الأخرى أو النظام الأساسي) المسارات الجديدة. قد تحتاج إلى تحديث التعليمات البرمجية الموجودة كنتيجة لتغيير المسار.

على الرغم من أن إحدى الطرق لتجنب تغيير المسار تتمثل في تراكب محتويات الملف في ملف APEX على قسم /system ، فقد قرر فريق Android عدم تراكب الملفات على قسم /system لأن هذا قد يؤثر على الأداء نظرًا لأن عدد الملفات التي يتم تراكبها ( ربما مكدسة واحدة تلو الأخرى).

كان هناك خيار آخر يتمثل في اختطاف وظائف الوصول إلى الملفات مثل open و stat و readlink ، بحيث تتم إعادة توجيه المسارات التي تبدأ بـ /system إلى المسارات المقابلة لها ضمن /apex . تجاهل فريق Android هذا الخيار لأنه من غير الممكن تغيير جميع الوظائف التي تقبل المسارات. على سبيل المثال ، تربط بعض التطبيقات Bionic بشكل ثابت ، والتي تقوم بتنفيذ الوظائف. في مثل هذه الحالات ، لا تتم إعادة توجيه هذه التطبيقات.