تنفيذ تعديلات A/B

على المصنّعين الأصليين للأجهزة ومورّدي شرائح المعالجة المتقدّمة (SoC) الذين يريدون تنفيذ تحديثات نظام A/B التأكّد من أنّ أداة تحميل البرامج التمهيدية تنفِّذ واجهة برمجة التطبيقات boot_control HAL وتُرسِل المَعلمات الصحيحة إلى النواة.

تنفيذ HAL الخاص بعناصر التحكّم في بدء التشغيل

يجب أن تُنفِّذ مُحمِّلات بدء التشغيل المتوافقة مع ميزة A/B واجهة برمجة التطبيقات boot_control HAL في ‎ hardware/libhardware/include/hardware/boot_control.h. يمكنك اختبار عمليات التنفيذ باستخدام أداة system/extras/bootctl وsystem/extras/tests/bootloader/.

يجب أيضًا تنفيذ آلة الحالات الموضّحة أدناه:

الشكل 1. آلة حالة برنامج الإقلاع

إعداد النواة

لتنفيذ تحديثات نظام A/B:

  1. اختَر بعناية سلسلة تصحيحات النواة التالية (إذا لزم الأمر):
  2. تأكَّد من أنّ وسيطات سطر أوامر kernel تحتوي على الوسيطات الإضافية التالية:
    skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"
    ... حيث تكون قيمة <public-key-id> هي معرّف المفتاح العام المستخدَم للتحقّق من توقيع جدول التحقق (للاطّلاع على التفاصيل، يُرجى الاطّلاع على dm-verity).
  3. أضِف شهادة X509 .التي تحتوي على المفتاح العام إلى سلسلة مفاتيح النظام:
    1. انسخ شهادة X509 .بتنسيق .der إلى جذر الدليل kernel. إذا كان تنسيق شهادة X509 .هو ملف .pem، استخدِم الأمر openssl التالي للتحويل من تنسيق .pem إلى تنسيق .der:
      openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
    2. أنشئ zImage لتضمين الشهادة كجزء من سلسلة مفاتيح النظام. للتحقّق من ذلك، ضَع علامة في المربّع بجانب إدخال procfs (يتطلب ذلك تفعيل KEYS_CONFIG_DEBUG_PROC_KEYS):
      angler:/# cat /proc/keys
      
      1c8a217e I------     1 perm 1f010000     0     0 asymmetri
      Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f []
      2d454e3e I------     1 perm 1f030000     0     0 keyring
      .system_keyring: 1/4
      يشير تضمين شهادة ‎ .X509 بنجاح إلى توفّر المفتاح العام في سلسلة مفاتيح النظام (يشير التمييز إلى معرّف المفتاح العام).
    3. استبدِل المساحة بـ # وأدخِله على النحو التالي: <public-key-id> في سطر أوامر kernel. على سبيل المثال، أرسِل Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f بدلاً من <public-key-id>.

ضبط متغيّرات التصميم

يجب أن تستوفي أداة تحميل البرامج الثابتة المتوافقة مع ميزة A/B المعايير التالية لمتغيّر الإنشاء:

يجب تحديده لاستهداف أ/ب
  • AB_OTA_UPDATER := true
  • AB_OTA_PARTITIONS := \
      boot \
      system \
      vendor
    والأقسام الأخرى التي تم تعديلها من خلال update_engine (الراديو ومحمل الإقلاع وما إلى ذلك)
  • PRODUCT_PACKAGES += \
      update_engine \
      update_verifier
على سبيل المثال، يُرجى الرجوع إلى /device/google/marlin/+/android-7.1.0_r1/device-common.mk. يمكنك اختياريًا تنفيذ خطوة dex2oat الموضّحة في الترجمة بعد التثبيت (ولكن قبل إعادة التشغيل).
يُنصح بشدة باستخدامها لاستهداف أ/ب
  • تعريف TARGET_NO_RECOVERY := true
  • تعريف BOARD_USES_RECOVERY_AS_BOOT := true
  • لا تحدِّد BOARD_RECOVERYIMAGE_PARTITION_SIZE.
لا يمكن تحديد استهداف A/B
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
اختياري لإصدارات تصحيح الأخطاء PRODUCT_PACKAGES_DEBUG += update_engine_client

ضبط الأقسام (الخانات)

لا تحتاج أجهزة A/B إلى قسم استرداد أو قسم تخزين مؤقت لأنّ نظام التشغيل Android لم يعُد يستخدم هذين القسمَين. يتم الآن استخدام قسم البيانات لحزمة OTA التي تم تنزيلها، ويتوفر код صورة الاسترداد في قسم التمهيد. يجب تسمية جميع الأقسام التي تم تقسيمها إلى قسمَين اختباريَين على النحو التالي (يتم دائمًا تسمية الخانات a وb وما إلى ذلك): boot_a، boot_b، system_a، system_b، vendor_a، vendor_b.

ذاكرة التخزين المؤقت

بالنسبة إلى التحديثات غير المستندة إلى تقنية A/B، كان يتم استخدام قسم ذاكرة التخزين المؤقت لتخزين حِزم OTA التي تم تنزيلها و لتخزين الكتل مؤقتًا أثناء تطبيق التحديثات. لم تكن هناك طريقة جيدة لتحديد حجم قسم ملف التخزين المؤقت ، إذ كان حجمه يعتمد على التعديلات التي تريد تطبيقها. سيكون أسوأ حالة هي قسم ذاكرة التخزين المؤقت بحجم ملف صورة النظام. باستخدام تحديثات A/B، ليس من الضروري تخزين الكتل (لأنّك تكتب دائمًا في قسم غير مستخدَم حاليًا) و باستخدام ميزة A/B للبث، ليس من الضروري تنزيل حزمة OTA بالكامل قبل تطبيقها.

الاسترداد

يتم الآن تضمين قرص ذاكرة الوصول العشوائي (RAM) لميزة الاسترداد في ملف boot.img. عند الانتقال إلى وضع الاسترداد، لا يمكن لمسؤول التمهيد ضبط الخيار skip_initramfs على سطر أوامر kernel.

بالنسبة إلى التحديثات غير المُدارة من خلال ميزة "التحديث الثنائي"، يحتوي قسم الاسترداد على الرمز المُستخدَم لتطبيق التحديثات. يتم تطبيق تحديثات A/B من خلال تشغيل update_engine في صورة النظام العادية التي يتم تشغيلها. لا يزال هناك وضع الاسترداد الذي يُستخدَم لتنفيذ ميزة "إعادة الضبط على الإعدادات الأصلية" وتحميل حزم التحديثات من مصدر غير معروف (من هنا جاء اسم "وضع الاسترداد"). يتم تخزين التعليمات البرمجية والبيانات الخاصة بوضع الاسترداد في قسم التشغيل العادي في ذاكرة وصول عشوائي (RAM). لبدء التشغيل إلى صورة النظام، يطلب ملف التمهيد من النواة تخطّي ذاكرة الوصول العشوائي (RAM) (وإلا سيتم تشغيل الجهاز في وضع الاسترداد ). مساحة وضع الاسترداد صغيرة (وكان الكثير منها مضمّنًا في قسم التمهيد)، لذا لا يزداد حجم قسم التمهيد.

Fstab

يجب أن تكون الوسيطة slotselect في السطر الخاص بالشرائح التي تم إجراء اختبار أ/ب عليها. مثلاً:

<path-to-block-device>/vendor  /vendor  ext4  ro
wait,verify=<path-to-block-device>/metadata,slotselect

يجب عدم تسمية أي قسم باسم vendor. بدلاً من ذلك، سيتم اختيار القسم vendor_a أو vendor_b وتثبيته على نقطة الربط /vendor.

وسيطات خانات النواة

يجب تمرير اللاحقة الحالية للفتحة إما من خلال عقدة شجرة جهاز (DT) محدّدة (/firmware/android/slot_suffix) أو من خلال سطر الأوامر androidboot.slot_suffix أو وسيطة bootconfig في نواة التشغيل.

يُبرمِج Fastboot تلقائيًا الشريحة الحالية على جهاز A/B. إذا كانت حزمة التحديث تحتوي أيضًا على صور للفتحة الأخرى غير الحالية، ستعمل أداة fastboot على فلاش هذه الصور أيضًا. تشمل الخيارات المتاحة ما يلي:

  • --slot SLOT. يمكنك إلغاء السلوك التلقائي وطلب من fastboot فلاش الفتحة التي يتم تمريرها كأحد الوسيطات.
  • --set-active [SLOT]. اضبط الفتحة على أنّها نشطة. في حال عدم تحديد ملف اختياري ، يتم ضبط الفتحة الحالية على أنّها نشطة.
  • fastboot --help. الحصول على تفاصيل عن الطلبات

إذا كان مشغّل الإقلاع ينفِّذ وضع التشغيل السريع، يجب أن يكون متوافقًا مع الأمر set_active <slot> الذي يضبط الفتحة النشطة الحالية على الفتحة المحدّدة (يجب أن يؤدي ذلك أيضًا إلى محو علامة عدم قابلية التشغيل لهذه الفتحة وإعادة ضبط عدد عمليات إعادة المحاولة على القيم التلقائية). يجب أن يتيح أداة تحميل البرامج أيضًا المتغيّرات التالية:

  • has-slot:<partition-base-name-without-suffix>. تعرِض القيمة "نعم" إذا كان القسم المُعطى يتيح استخدام الفتحات، وتعرِض القيمة "لا" في حال عدم توفّر هذه الميزة.
  • current-slot. لعرض اللاحقة الخاصة بالفتحة التي سيتم تشغيل الجهاز منها بعد ذلك.
  • slot-count. لعرض عدد صحيح يمثّل عدد الفتحات المتاحة. يمكن حاليًا استخدام خانتَين، لذا تكون هذه القيمة هي 2.
  • slot-successful:<slot-suffix>. تعرِض هذه السمة القيمة "نعم" إذا تم وضع علامة على الفتحة المحدّدة على أنّها تم تشغيلها بنجاح، وتعرض القيمة "لا" في الحالات الأخرى.
  • slot-unbootable:<slot-suffix>. تعرِض هذه الدالة القيمة "نعم" إذا تم وضع علامة على الفتحة المحدّدة على أنّها لا يمكن تشغيلها، وتعرض القيمة "لا" في الحالات الأخرى.
  • slot-retry-count:<slot-suffix>. عدد عمليات إعادة المحاولة المتبقية لمحاولة تشغيل الفتحة المحدّدة

لعرض جميع المتغيّرات، نفِّذ سوى fastboot getvar all.

إنشاء حِزم عبر الهواء

تتبع أدوات حِزم OTA الأوامر نفسها المستخدَمة في ملف برمجي الأوامر للأجهزة غير المزوّدة بميزة A/B. يجب إنشاء ملف target_files.zip من خلال تحديد متغيّرات الإنشاء لاستهداف اختبار A/B. ترصد أدوات حِزم OTA تلقائيًا وتُنشئ الحِزم بتنسيق أداة تحديث A/B.

أمثلة:

  • لإنشاء تحديث OTA كامل:
    ./build/make/tools/releasetools/ota_from_target_files \
        dist_output/tardis-target_files.zip \
        ota_update.zip
    
  • لإنشاء تحديث OTA تدريجي:
    ./build/make/tools/releasetools/ota_from_target_files \
        -i PREVIOUS-tardis-target_files.zip \
        dist_output/tardis-target_files.zip \
        incremental_ota_update.zip
    

ضبط الأقسام

يمكن أن يعدّل update_engine أي زوج من أقسام A/B المحدّدة في القرص نفسه. يتضمّن زوج من الأقسام بادئة شائعة (مثل system أو boot) ولاحقة لكل خانة (مثل _a). يتم ضبط قائمة الأقسام التي يحدّد فيها مُنشئ الحمولة تعديلًا باستخدام المتغيّر AB_OTA_PARTITIONS make.

على سبيل المثال، إذا تم تضمين قسمَين bootloader_a و booloader_b (_a و_b هما لاحقتَان للفتحة)، يمكنك تعديل هذين القسمَين من خلال تحديد ما يلي في إعدادات المنتج أو اللوحة:

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

يجب ألا تعدِّل بقية مكونات النظام جميع الأقسام التي عدَّلها update_engine. أثناء عمليات التعديل المتزايدة أو التغيير، يتم استخدام البيانات الثنائية من الفتحة الحالية لإنشاء البيانات في الفتحة الجديدة. قد يؤدي أي تعديل إلى عدم اجتياز بيانات الفتحة الجديدة عملية التحقّق أثناء عملية التعديل، وبالتالي عدم إتمام عملية التعديل.

ضبط الإعدادات بعد التثبيت

يمكنك ضبط خطوة ما بعد التثبيت بشكلٍ مختلف لكل قسم تم تعديله باستخدام مجموعة من أزواج المفتاح/القيمة. لتشغيل برنامج في /system/usr/bin/postinst في ملف ‎ جديد، حدِّد المسار النسبي إلى جذر نظام الملفات في قسم النظام.

على سبيل المثال، usr/bin/postinst هو system/usr/bin/postinst (إذا لم يكن يتم استخدام قرص ذاكرة وصول عشوائي). بالإضافة إلى ذلك، حدِّد نوع نظام الملفات الذي سيتم تمريره إلى mount(2). أضِف ما يلي إلى ملفّات المنتج أو الجهاز .mk (إن وُجدت):

AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=usr/bin/postinst \
  FILESYSTEM_TYPE_system=ext4

تجميع التطبيقات

يمكن تجميع التطبيقات في الخلفية قبل إعادة التشغيل باستخدام صورة النظام الجديدة. لتجميع التطبيقات في الخلفية، أضِف ما يلي إلى إعدادات جهاز المنتج (فيملف device.mk الخاص بالمنتج):

  1. أدرِج المكوّنات الأصلية في عملية الإنشاء لضمان تجميع النص البرمجي للترجمة والملفّات الثنائية وتضمينها في صورة النظام.
      # A/B OTA dexopt package
      PRODUCT_PACKAGES += otapreopt_script
    
  2. اربط نص التحويل البرمجي بـ update_engine بحيث يتم تنفيذه كخطوة ما بعد التثبيت.
      # A/B OTA dexopt update_engine hookup
      AB_OTA_POSTINSTALL_CONFIG += \
        RUN_POSTINSTALL_system=true \
        POSTINSTALL_PATH_system=system/bin/otapreopt_script \
        FILESYSTEM_TYPE_system=ext4 \
        POSTINSTALL_OPTIONAL_system=true
    

للحصول على مساعدة بشأن تثبيت الملفات التي تم تحسينها مسبقًا في قسم النظام الثاني غير المستخدَم، يُرجى الرجوع إلى تثبيت ملفات DEX_PREOPT في عملية التشغيل الأولى.