به روز رسانی A/B را پیاده سازی کنید

OEM ها و فروشندگان 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. سری پچ های هسته زیر را Cherrypick کنید (در صورت نیاز):
  2. مطمئن شوید که آرگومان های خط فرمان هسته حاوی آرگومان های اضافی زیر هستند:
    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> در خط فرمان هسته ارسال کنید. برای مثال، Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f را به جای <public-key-id> ارسال کنید.

متغیرهای ساخت را تنظیم کنید

بوت لودرهای با قابلیت A/B باید معیارهای متغیر ساخت زیر را داشته باشند:

باید برای هدف 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 را پس از نصب (اما قبل از راه‌اندازی مجدد) که در Compiling توضیح داده شده است انجام دهید.
به شدت برای هدف A/B توصیه می شود
  • 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 نیازی به پارتیشن بازیابی یا کش ندارند زیرا اندروید دیگر از این پارتیشن ها استفاده نمی کند. اکنون پارتیشن داده برای بسته OTA دانلود شده استفاده می شود و کد تصویر بازیابی روی پارتیشن بوت است. همه پارتیشن هایی که A/B-ed هستند باید به صورت زیر نامگذاری شوند (اسلات ها همیشه a ، b و غیره نامگذاری می شوند): boot_a ، boot_b ، system_a ، system_b ، vendor_a ، vendor_b .

حافظه پنهان

برای به‌روزرسانی‌های غیر A/B، پارتیشن کش برای ذخیره بسته‌های OTA دانلود شده و ذخیره موقت بلوک‌ها در حین اعمال به‌روزرسانی‌ها استفاده می‌شود. هرگز راه خوبی برای اندازه‌گیری پارتیشن حافظه پنهان وجود نداشت: اینکه چقدر بزرگ باید به به‌روزرسانی‌هایی که می‌خواهید اعمال کنید بستگی دارد. بدترین حالت یک پارتیشن کش به بزرگی تصویر سیستم خواهد بود. با به‌روزرسانی‌های A/B، نیازی به ذخیره کردن بلوک‌ها نیست (زیرا همیشه در حال نوشتن روی پارتیشنی هستید که در حال حاضر استفاده نمی‌شود) و با پخش جریانی A/B، نیازی به دانلود کل بسته OTA قبل از اعمال آن نیست.

بازیابی

دیسک رم بازیابی اکنون در فایل boot.img موجود است. هنگام رفتن به ریکاوری، بوت لودر نمی تواند گزینه skip_initramfs را در خط فرمان هسته قرار دهد.

برای به‌روزرسانی‌های غیر A/B، پارتیشن بازیابی حاوی کدی است که برای اعمال به‌روزرسانی‌ها استفاده می‌شود. به روز رسانی A/B توسط update_engine در حال اجرا در تصویر سیستم بوت شده معمولی اعمال می شود. هنوز یک حالت بازیابی برای اجرای بازنشانی داده های کارخانه و بارگذاری جانبی بسته های به روز رسانی (که نام "بازیابی" از آنجا آمده است) وجود دارد. کد و اطلاعات برای حالت بازیابی در پارتیشن بوت معمولی در یک ramdisk ذخیره می شود. برای بوت شدن در تصویر سیستم، بوت لودر به هسته می‌گوید که ramdisk را رد کند (در غیر این صورت دستگاه به حالت بازیابی راه‌اندازی می‌شود. حالت بازیابی کوچک است (و بیشتر آن از قبل روی پارتیشن بوت بود)، بنابراین پارتیشن بوت افزایش نمی‌یابد. در اندازه

فستاب

آرگومان slotselect باید در خط پارتیشن های A/B-ed باشد. به عنوان مثال:

<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 ارسال شود.

به طور پیش‌فرض، فست‌بوت، اسلات فعلی دستگاه 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 تولید کنید

ابزارهای بسته 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 پیکربندی می‌شود.

به عنوان مثال، اگر یک جفت پارتیشن bootloader_a و booloader_b گنجانده شود ( _a و _b پسوندهای اسلات هستند)، می‌توانید این پارتیشن‌ها را با مشخص کردن موارد زیر در پیکربندی محصول یا برد به‌روزرسانی کنید:

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

تمام پارتیشن های به روز شده توسط update_engine نباید توسط بقیه سیستم اصلاح شود. در طول به روز رسانی افزایشی یا دلتا ، داده های باینری از شکاف فعلی برای تولید داده ها در شکاف جدید استفاده می شود. هر گونه تغییری ممکن است باعث شود که داده‌های اسلات جدید در طی فرآیند به‌روزرسانی تأیید نشوند و بنابراین به‌روزرسانی انجام نشود.

پیکربندی postinstallation

می توانید مرحله postinstall را برای هر پارتیشن به روز شده با استفاده از مجموعه ای از جفت های کلید-مقدار متفاوت پیکربندی کنید. برای اجرای برنامه ای که در /system/usr/bin/postinst در یک تصویر جدید قرار دارد، مسیر را نسبت به ریشه سیستم فایل در پارتیشن سیستم مشخص کنید.

برای مثال، usr/bin/postinst system/usr/bin/postinst است (اگر از دیسک RAM استفاده نمی‌کند). علاوه بر این، نوع فایل سیستم را برای ارسال به فراخوانی سیستم 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 مراجعه کنید.