پیاده سازی به روز رسانی 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 زیر برای تبدیل از فرمت .der .pem کنید:
      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 . تعداد تلاش های مجدد باقی مانده برای تلاش برای بوت شدن شکاف داده شده.

برای مشاهده همه متغیرها، 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 نباید توسط بقیه سیستم اصلاح شود. در طول به روز رسانی افزایشی یا دلتا ، داده های باینری از شکاف فعلی برای تولید داده ها در شکاف جدید استفاده می شود. هر گونه تغییری ممکن است باعث شود که داده‌های اسلات جدید در طی فرآیند به‌روزرسانی تأیید نشوند و بنابراین به‌روزرسانی انجام نشود.

پیکربندی پس از نصب

می‌توانید مرحله پس از نصب را برای هر پارتیشن به‌روزرسانی شده با استفاده از مجموعه‌ای از جفت‌های کلید-مقدار متفاوت پیکربندی کنید. برای اجرای برنامه ای که در /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

تدوین

به دلایل امنیتی، system_server نمی تواند از کامپایل به موقع (JIT) استفاده کند. این بدان معنی است که شما باید فایل های odex را برای system_server و وابستگی های آن حداقل پیش از موعد کامپایل کنید. هر چیز دیگری اختیاری است

برای کامپایل برنامه‌ها در پس‌زمینه، باید موارد زیر را به پیکربندی دستگاه محصول (در 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 مراجعه کنید.