تنفيذ Virtual A/B

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

بناء الأعلام

يجب تكوين الأجهزة التي تستخدم A/B الظاهري كجهاز A/B ويجب تشغيلها باستخدام أقسام ديناميكية .

بالنسبة للأجهزة التي يتم تشغيلها باستخدام A/B الظاهري، قم بتعيينها لترث التكوين الأساسي لجهاز A/B الظاهري:

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

تحتاج الأجهزة التي يتم تشغيلها باستخدام A/B افتراضي إلى نصف حجم اللوحة فقط لـ BOARD_SUPER_PARTITION_SIZE لأن فتحات B لم تعد في حالة ممتازة. وهذا يعني أن BOARD_SUPER_PARTITION_SIZE يجب أن يكون أكبر من أو يساوي مجموع (حجم مجموعات التحديث) + الحمل ، والذي بدوره يجب أن يكون أكبر من أو يساوي مجموع (حجم الأقسام) + الحمل .

بالنسبة لنظام التشغيل Android 13 والإصدارات الأحدث، لتمكين اللقطات المضغوطة باستخدام Virtual A/B، يمكنك الحصول على التكوين الأساسي التالي:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/android_t_baseline.mk)

يؤدي ذلك إلى تمكين لقطات مساحة المستخدم باستخدام Virtual A/B أثناء استخدام طريقة الضغط بدون تشغيل. يمكنك بعد ذلك ضبط طريقة الضغط على إحدى الطرق المدعومة، gz و zstd و lz4 .

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

بالنسبة لنظام التشغيل Android 12، لتمكين اللقطات المضغوطة باستخدام Virtual A/B، يمكنك الحصول على التكوين الأساسي التالي:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

ضغط XOR

بالنسبة للأجهزة التي تقوم بالترقية إلى Android 13 والإصدارات الأحدث، لا يتم تمكين ميزة ضغط XOR افتراضيًا. لتمكين ضغط XOR، قم بإضافة ما يلي إلى ملف .mk الخاص بالجهاز.

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

يتم تمكين ضغط XOR افتراضيًا للأجهزة التي ترث من android_t_baseline.mk .

دمج مساحة المستخدم

بالنسبة للأجهزة التي تقوم بالترقية إلى Android 13 والإصدارات الأحدث، لا يتم تمكين عملية دمج مساحة المستخدم كما هو موضح في طبقات مخطط الجهاز بشكل افتراضي. لتمكين دمج مساحة المستخدم، أضف السطر التالي إلى ملف .mk الخاص بالجهاز:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

يتم تمكين دمج مساحة المستخدم افتراضيًا على الأجهزة التي يتم تشغيلها بالإصدار 13 أو أعلى.

التحكم في التمهيد HAL

يوفر HAL للتحكم في التمهيد واجهة لعملاء OTA للتحكم في فتحات التمهيد. يتطلب Virtual A/B ترقية إصدار بسيط لـ HAL للتحكم في التمهيد نظرًا لأن هناك حاجة إلى واجهات برمجة تطبيقات إضافية لضمان حماية أداة تحميل التشغيل أثناء الوميض/إعادة ضبط المصنع. راجع IBootControl.hal و types.hal للحصول على أحدث إصدار من تعريف HAL.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

تغييرات فستاب

تعد سلامة قسم البيانات التعريفية أمرًا ضروريًا لعملية التمهيد، خاصة بعد تطبيق التحديث عبر الهواء مباشرة. لذلك، يجب التحقق من قسم البيانات التعريفية قبل أن يقوم first_stage_init بتحميله. للتأكد من حدوث ذلك، قم بإضافة علامة check fs_mgr إلى إدخال /metadata . فيما يلي مثال على ذلك:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

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

لتمكين التقاط الصور، قم بتعيين CONFIG_DM_SNAPSHOT على true .

بالنسبة للأجهزة التي تستخدم F2FS، قم بتضمين علامة f2fs: تصدير علامة FS_NOCOW_FL إلى تصحيح kernel الخاص بالمستخدم لإصلاح تثبيت الملف. قم بتضمين f2fs: دعم تصحيح kernel للملفات المثبتة أيضًا.

يعتمد Virtual A/B على الميزات المضافة في إصدار kernel 4.3: بت حالة التجاوز في أهداف snapshot snapshot-merge . يجب أن تحتوي جميع الأجهزة التي تعمل بنظام التشغيل Android 9 والإصدارات الأحدث على إصدار kernel 4.4 أو إصدار أحدث.

لتمكين اللقطات المضغوطة، الحد الأدنى لإصدار kernel المدعوم هو 4.19. اضبط CONFIG_DM_USER=m أو CONFIG_DM_USER=y . في حالة استخدام الوحدة السابقة (الوحدة النمطية)، يجب تحميل الوحدة في قرص ذاكرة الوصول العشوائي للمرحلة الأولى. يمكن تحقيق ذلك عن طريق إضافة السطر التالي إلى Makefile الخاص بالجهاز:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

التحديثية على الأجهزة التي تقوم بالترقية إلى Android 11

عند الترقية إلى Android 11، يمكن للأجهزة التي تم تشغيلها باستخدام أقسام ديناميكية تحديث A/B الافتراضي بشكل اختياري. عملية التحديث هي في الغالب نفس عملية التحديث بالنسبة للأجهزة التي يتم تشغيلها باستخدام A/B الظاهري، مع بعض الاختلافات البسيطة:

  • موقع ملفات COW - بالنسبة لأجهزة التشغيل، يستخدم عميل OTA كل المساحة الفارغة المتوفرة في القسم الفائق قبل استخدام المساحة في /data . بالنسبة للأجهزة التحديثية، توجد دائمًا مساحة كافية في القسم الفائق بحيث لا يتم إنشاء ملف COW أبدًا على /data .

  • علامات ميزات وقت البناء — بالنسبة للأجهزة التي تقوم بتعديل A/B الظاهري، يتم تعيين كل من PRODUCT_VIRTUAL_AB_OTA و PRODUCT_VIRTUAL_AB_OTA_RETROFIT على true ، كما هو موضح أدناه:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • حجم القسم الفائق — يمكن للأجهزة التي يتم تشغيلها باستخدام A/B افتراضي أن تقطع BOARD_SUPER_PARTITION_SIZE إلى النصف لأن فتحات B ليست في القسم الفائق. تحافظ الأجهزة التي تقوم بتعديل A/B الظاهري على حجم القسم الفائق القديم، لذا فإن BOARD_SUPER_PARTITION_SIZE أكبر من أو يساوي 2 * sum(حجم مجموعات التحديث) + الحمل ، والذي بدوره أكبر من أو يساوي 2 * sum(حجم الأقسام) + النفقات العامة .

تغييرات محمل الإقلاع

أثناء خطوة دمج التحديث، يحتفظ /data بالمثيل الكامل الوحيد لنظام التشغيل Android. بمجرد بدء الترحيل، تكون أقسام system الأصلي vendor product غير مكتملة حتى تنتهي النسخة. إذا تمت إعادة ضبط الجهاز على إعدادات المصنع أثناء هذه العملية، إما عن طريق الاسترداد أو من خلال مربع حوار إعدادات الأنظمة، فسيكون الجهاز غير قابل للتمهيد.

قبل محو /data ، قم بإنهاء الدمج في الاسترداد أو التراجع اعتمادًا على حالة الجهاز:

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

يمكن لكل من أداة تحميل التشغيل و fastbootd مسح قسم /data إذا كان الجهاز مفتوحًا. بينما يمكن fastbootd فرض عملية الترحيل لإكمالها، فإن أداة تحميل التشغيل لا يمكنها ذلك. لا يعرف برنامج تحميل التشغيل ما إذا كانت عملية الدمج قيد التقدم أم لا، أو ما هي الكتل الموجودة في /data التي تشكل أقسام نظام التشغيل. يجب أن تمنع الأجهزة المستخدم من جعل الجهاز غير صالح للعمل (القرصنة) دون علمه عن طريق القيام بما يلي:

  1. قم بتطبيق HAL للتحكم في التمهيد حتى يتمكن أداة تحميل التشغيل من قراءة القيمة التي تم تعيينها بواسطة طريقة setSnapshotMergeStatus() .
  2. إذا كانت حالة الدمج هي MERGING ، أو إذا كانت حالة الدمج SNAPSHOTTED وتغيرت الفتحة إلى الفتحة المحدثة حديثًا، فيجب رفض طلبات مسح userdata أو metadata أو القسم الذي يخزن حالة الدمج في أداة تحميل التشغيل.
  3. قم بتنفيذ أمر fastboot snapshot-update cancel حتى يتمكن المستخدمون من الإشارة إلى أداة تحميل التشغيل بأنهم يريدون تجاوز آلية الحماية هذه.
  4. قم بتعديل أدوات التفليش أو البرامج النصية المخصصة لإصدار fastboot snapshot-update cancel عند تفليش الجهاز بأكمله. يعد هذا أمرًا آمنًا لأن وميض الجهاز بأكمله يؤدي إلى إزالة OTA. يمكن للأدوات اكتشاف هذا الأمر في وقت التشغيل من خلال تطبيق fastboot getvar snapshot-update-status . يساعد هذا الأمر على التمييز بين حالات الخطأ.

مثال

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

تغييرات أدوات Fastboot

يُجري Android 11 التغييرات التالية على بروتوكول التشغيل السريع:

  • getvar snapshot-update-status — يُرجع القيمة التي أرسلها عنصر تحكم التمهيد HAL إلى أداة تحميل التشغيل:
    • إذا كانت الحالة MERGING ، فيجب على أداة تحميل التشغيل إعادة merging .
    • إذا كانت الحالة SNAPSHOTTED ، فيجب على أداة تحميل التشغيل إرجاع snapshotted .
    • وبخلاف ذلك، يجب على أداة تحميل التشغيل عدم إرجاع none .
  • snapshot-update merge - يكمل عملية الدمج، والتمهيد إلى الاسترداد/التشغيل السريع إذا لزم الأمر. يكون هذا الأمر صالحًا فقط في حالة merging snapshot-update-status ، وهو مدعوم فقط في fastbootd.
  • snapshot-update cancel — يضبط حالة دمج HAL للتحكم في التشغيل على CANCELLED . هذا الأمر غير صالح عندما يكون الجهاز مقفلاً.
  • erase أو wipe - erase أو wipe metadata أو userdata أو القسم الذي يحتفظ بحالة الدمج للتحكم في التمهيد HAL يجب أن يتحقق من حالة دمج اللقطة. إذا كانت الحالة MERGING أو SNAPSHOTTED ، فيجب على الجهاز إحباط العملية.
  • set_active — أمر set_active الذي يغير الفتحة النشطة يجب أن يتحقق من حالة دمج اللقطة. إذا كانت الحالة MERGING ، فيجب على الجهاز إحباط العملية. يمكن تغيير الفتحة بأمان في حالة SNAPSHOTTED .

تم تصميم هذه التغييرات لمنع جعل الجهاز غير قابل للتشغيل عن طريق الخطأ، ولكنها قد تؤدي إلى تعطيل الأدوات الآلية. عند استخدام الأوامر كمكون لتحديث كافة الأقسام، مثل تشغيل fastboot flashall ، فمن المستحسن استخدام التدفق التالي:

  1. الاستعلام عن getvar snapshot-update-status .
  2. في حالة merging أو snapshotted ، قم snapshot-update cancel .
  3. تابع الخطوات الوامضة.

تقليل متطلبات التخزين

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

طرق ضغط OTA

يمكن ضبط حزم OTA لمقاييس أداء مختلفة. يوفر Android العديد من طرق الضغط المدعومة ( gz و lz4 و zstd و none ) التي لها مفاضلات بين وقت التثبيت واستخدام مساحة COW ووقت التمهيد ووقت دمج اللقطات. الخيار الافتراضي الذي تم تمكينه لـ ab الظاهري مع الضغط هو gz compression method . (ملاحظة: يختلف الأداء النسبي بين طرق الضغط اعتمادًا على سرعة وحدة المعالجة المركزية وإنتاجية التخزين التي يمكن أن تتغير اعتمادًا على الجهاز. جميع حزم OTA التي تم إنشاؤها أدناه مع تعطيل PostInstall، مما سيؤدي إلى إبطاء وقت التمهيد قليلاً. إجمالي حجم القسم الديناميكي لـ OTA الكامل بدون ضغط 4.81 جيجابايت ).

OTA تزايدي على Pixel 6 Pro

وقت التثبيت بدون مرحلة ما بعد التثبيت استخدام مساحة البقرة وقت تشغيل ما بعد OTA وقت دمج اللقطة
gz 24 دقيقة 1.18 جيجابايت 40.2 ثانية 45.5 ثانية
lz4 13 دقيقة 1.49 جيجابايت 37.4 ثانية 37.1 ثانية
لا أحد 13 دقيقة 2.90 جيجابايت 37.6 ثانية 40.7 ثانية

OTA الكامل على Pixel 6 Pro

وقت التثبيت بدون مرحلة ما بعد التثبيت استخدام مساحة البقرة وقت تشغيل ما بعد OTA وقت دمج اللقطة
gz 23 دقيقة 2.79 جيجابايت 24.9 ثانية 41.7 ثانية
lz4 12 دقيقة 3.46 جيجابايت 20.0 ثانية 25.3 ثانية
لا أحد 10 دقائق 4.85 جيجابايت 20.6 ثانية 29.8 ثانية