تنسيق ملف APEX

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

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

خلفية

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

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

تصميم

يصف هذا القسم التصميم عالي المستوى لتنسيق ملف 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. هذا هو المخزن المؤقت لبروتوكول ApexManifest بتنسيق JSON.

يسمح ملف AndroidManifest.xml لملف APEX باستخدام الأدوات والبنية الأساسية المتعلقة بـ APK مثل ADB وPackageManager وتطبيقات تثبيت الحزم (مثل متجر Play). على سبيل المثال، يمكن لملف 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

للمساعدة في منع تعارض الأسماء بين APEXes الجديدة مع تقدم النظام الأساسي، استخدم إرشادات التسمية التالية:

  • com.android.*
    • محجوز لـ AOSP APEXes. ليست فريدة من نوعها لأي شركة أو جهاز.
  • com.<companyname>.*
    • محفوظة لشركة. من المحتمل أن يتم استخدامه بواسطة أجهزة متعددة من تلك الشركة.
  • com.<companyname>.<devicename>.*
    • محجوز لـ APEXes الفريدة لجهاز معين (أو مجموعة فرعية من الأجهزة).

مدير أبيكس

يعد مدير 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 الاختياري و minSdkVersion و maxSdkVersion للاستهداف الدقيق. تسمح هذه المعلومات بتسليم ملفات APEX عبر القنوات الموجودة مثل تطبيقات تثبيت الحزم وADB.

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

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

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

هذا لا يعني أن 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 فقط بعد إعادة التشغيل.

متطلبات النواة

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

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

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

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

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

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

إصدار النواة 4.4

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

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

إصدارات النواة 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 باستخدام نظام بناء 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

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

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

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

التعامل مع واجهات برمجة تطبيقات متعددة

قم بتثبيت خاصية native_shared_libs لكل من الواجهات الثنائية للتطبيقات الأساسية والثانوية (ABIs) الخاصة بالجهاز. إذا كان 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 : يطابق واجهة برمجة التطبيقات (ABI) 32 بت للجهاز، إذا كان مدعومًا.
  • lib64 : يطابق ABI 64 بت للجهاز، وهو مدعوم.
  • prefer32 : يطابق واجهة برمجة التطبيقات (ABI) 32 بت للجهاز، إذا كان مدعومًا. إذا لم يكن ABI 32 بت مدعومًا، فإنه يطابق 64 بت ABI.
  • both : يطابق كلاً من واجهات ABI. هذا هو الإعداد الافتراضي لـ 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_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، استخدم ADB.

adb install apex_file_name
adb reboot

إذا تم تعيين supportsRebootlessUpdate على true في apex_manifest.json وكان APEX المثبت حاليًا غير مستخدم (على سبيل المثال، تم إيقاف أي خدمات يحتوي عليها)، فيمكن تثبيت APEX جديد دون إعادة التشغيل باستخدام علامة --force-non-staged .

adb install --force-non-staged apex_file_name

استخدم أبيكس

بعد إعادة التشغيل، يتم تثبيت 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 بشكل كامل. على سبيل المثال، ربما تم إنشاء النواة بدون CONFIG_BLK_DEV_LOOP=Y ، وهو أمر بالغ الأهمية لتثبيت صورة نظام الملفات داخل APEX.

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

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

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

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

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

قمم مضغوطة

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

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

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

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

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

  • 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 عن هاتين الواجهتين APIs Binder:

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

في حالة تحديث A/B عبر الهواء، يحاول 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 نفس المستوى من حماية المحتوى.

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

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

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

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