A/B अपडेट लागू करना

जिन ओईएम और SoC वेंडर को A/B सिस्टम अपडेट लागू करने हैं उन्हें यह पक्का करना होगा कि उनका बूटलोडर, boot_control HAL को लागू करे और कर्नल को सही पैरामीटर भेजे.

बूट कंट्रोल HAL को लागू करना

A/B बूटलोडर के लिए, boot_control एचएएल को hardware/libhardware/include/hardware/boot_control.h पर लागू करना ज़रूरी है. system/extras/bootctl यूटिलिटी और system/extras/tests/bootloader/ का इस्तेमाल करके, लागू किए गए बदलावों को टेस्ट किया जा सकता है.

आपको यहां दिखाई गई स्टेट मशीन को भी लागू करना होगा:

पहली इमेज. बूटलोडर स्टेट मशीन

कर्नल सेट अप करना

A/B सिस्टम अपडेट लागू करने के लिए:

  1. अगर ज़रूरी हो, तो कर्नेल पैच की इन सीरीज़ को चेरीपिक करें:
  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>"
    ... where the <public-key-id> value is the ID of the public key used to verify the verity table signature (for details, see dm-verity).
  3. सार्वजनिक पासकोड वाले .X509 सर्टिफ़िकेट को सिस्टम कीरिंग में जोड़ें:
    1. .der फ़ॉर्मैट में फ़ॉर्मैट किए गए .X509 सर्टिफ़िकेट को kernel डायरेक्ट्री के रूट में कॉपी करें. अगर .X509 सर्टिफ़िकेट को .pem फ़ाइल के तौर पर फ़ॉर्मैट किया गया है, तो .pem से .der फ़ॉर्मैट में बदलने के लिए, यहां दिया गया openssl निर्देश इस्तेमाल करें:
      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> के तौर पर पास करें. उदाहरण के लिए, <public-key-id> के बजाय Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f पास करें.

बिल्ड वैरिएबल सेट करना

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 चरण को पूरा करने का विकल्प होता है. इसके बारे में कंपाइल करना लेख में बताया गया है.
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 डिवाइसों को रिकवरी पार्टीशन या कैश पार्टीशन की ज़रूरत नहीं होती, क्योंकि Android अब इन पार्टीशन का इस्तेमाल नहीं करता. अब डेटा पार्टीशन का इस्तेमाल, डाउनलोड किए गए ओटीए पैकेज के लिए किया जाता है. साथ ही, रिकवरी इमेज कोड, बूट पार्टीशन पर होता है. जिन सभी पार्टीशन पर A/B टेस्टिंग की जाती है उनका नाम इस तरह होना चाहिए (स्लॉट के नाम हमेशा a, b वगैरह होते हैं): boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.

कैश मेमोरी

A/B अपडेट के अलावा अन्य अपडेट के लिए, कैश मेमोरी पार्टिशन का इस्तेमाल डाउनलोड किए गए ओटीए पैकेज को सेव करने के लिए किया जाता था. साथ ही, अपडेट लागू करते समय ब्लॉक को कुछ समय के लिए सेव करने के लिए भी इसका इस्तेमाल किया जाता था. कैश मेमोरी के साइज़ को तय करने का कोई सही तरीका नहीं था. इसका साइज़ इस बात पर निर्भर करता था कि आपको कौनसे अपडेट लागू करने हैं. सबसे खराब स्थिति में, कैश मेमोरी का पार्टीशन सिस्टम इमेज जितना बड़ा हो सकता है. A/B अपडेट में, ब्लॉक को स्टैश करने की ज़रूरत नहीं होती. ऐसा इसलिए, क्योंकि हमेशा ऐसे पार्टीशन में लिखा जाता है जिसका इस्तेमाल फ़िलहाल नहीं किया जा रहा है. साथ ही, स्ट्रीमिंग A/B में, ओटीए पैकेज को लागू करने से पहले, उसे पूरा डाउनलोड करने की ज़रूरत नहीं होती.

रिकवरी

रिकवरी रैम डिस्क अब boot.img फ़ाइल में शामिल है. रिकवरी मोड में जाने पर, बूटलोडर कर्नेल कमांड लाइन पर skip_initramfs विकल्प नहीं डाल सकता.

A/B अपडेट के अलावा अन्य अपडेट के लिए, रिकवरी पार्टीशन में अपडेट लागू करने के लिए इस्तेमाल किया गया कोड होता है. A/B अपडेट, बूट किए गए सिस्टम की सामान्य इमेज में चल रहे update_engine की मदद से लागू किए जाते हैं. फ़ैक्ट्री डेटा रीसेट करने और अपडेट पैकेज को साइडलोड करने के लिए, अब भी रिकवरी मोड का इस्तेमाल किया जाता है. "रिकवरी" नाम यहीं से आया है. रिकवरी मोड का कोड और डेटा, रैमडिस्क में रेगुलर बूट पार्टीशन में सेव होता है. सिस्टम इमेज में बूट करने के लिए, बूटलोडर कर्नल को रैमडिस्क को स्किप करने के लिए कहता है. ऐसा न करने पर, डिवाइस रिकवरी मोड में बूट हो जाता है. रिकवरी मोड छोटा होता है और इसका ज़्यादातर हिस्सा पहले से ही बूट पार्टिशन पर होता है. इसलिए, बूट पार्टिशन का साइज़ नहीं बढ़ता.

Fstab

slotselect आर्ग्युमेंट, A/B टेस्ट किए गए पार्टिशन के लिए लाइन पर होना चाहिए. उदाहरण के लिए:

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

किसी भी पार्टिशन का नाम vendor नहीं होना चाहिए. इसके बजाय, vendor_a या vendor_b को चुना जाएगा और /vendor माउंट पॉइंट पर माउंट किया जाएगा.

कर्नेल स्लॉट के आर्ग्युमेंट

मौजूदा स्लॉट का प्रत्यय, किसी डिवाइस ट्री (डीटी) नोड (/firmware/android/slot_suffix) या androidboot.slot_suffix कर्नेल कमांड लाइन या बूटकॉन्फ़िग आर्ग्युमेंट के ज़रिए पास किया जाना चाहिए.

डिफ़ॉल्ट रूप से, fastboot, A/B डिवाइस पर मौजूदा स्लॉट को फ़्लैश करता है. अगर अपडेट पैकेज में, दूसरे स्लॉट के लिए भी इमेज शामिल हैं, तो फ़ास्टबूट उन इमेज को भी फ़्लैश करता है. आपके पास ये विकल्प उपलब्ध हैं:

  • --slot SLOT. डिफ़ॉल्ट तरीके को बदलें और फ़ास्टबूट को उस स्लॉट को फ़्लैश करने के लिए कहें जिसे आर्ग्युमेंट के तौर पर पास किया गया है.
  • --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 पैकेज टूल, नॉन-ए/बी डिवाइसों के लिए इस्तेमाल की जाने वाली कमांड का ही पालन करते हैं. target_files.zip फ़ाइल जनरेट करने के लिए, A/B टारगेट के लिए बिल्ड वैरिएबल तय करने होंगे. ओटीए पैकेज टूल, A/B अपडेटर के फ़ॉर्मैट में पैकेज की पहचान अपने-आप करते हैं और उन्हें जनरेट करते हैं.

उदाहरण:

  • पूरा ओटीए जनरेट करने के लिए:
    ./build/make/tools/releasetools/ota_from_target_files \
        dist_output/tardis-target_files.zip \
        ota_update.zip
    
  • इंक्रीमेंटल ओटीए जनरेट करने के लिए:
    ./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 है (अगर 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 फ़ाइलों को पहली बार बूट करने पर इंस्टॉल करना लेख पढ़ें.