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

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

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

A/B फ़ंक्शन वाले बूटलोडर को hardware/libhardware/include/hardware/boot_control.h पर boot_control HAL लागू करना होगा. 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>"
    ... जहां <public-key-id> वैल्यू, पुष्टि करने वाली टेबल के हस्ताक्षर की पुष्टि करने के लिए इस्तेमाल की जाने वाली सार्वजनिक कुंजी का आईडी है. ज़्यादा जानकारी के लिए, 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 मोड वाले बूटलोडर को, बिल्ड वैरिएबल से जुड़ी इन शर्तों को पूरा करना होगा:

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

रिकवरी

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

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

Fstab

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

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

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

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

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

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

  • --slot SLOT. डिफ़ॉल्ट तरीके को बदलें और उस स्लॉट को फ़्लैश करने के लिए fastboot को निर्देश दें जो आर्ग्युमेंट के तौर पर दिया गया है.
  • --set-active [SLOT]. स्लॉट को 'चालू है' के तौर पर सेट करें. अगर कोई वैकल्पिक आर्ग्युमेंट नहीं दिया गया है, तो मौजूदा स्लॉट को 'चालू है' के तौर पर सेट किया जाता है.
  • fastboot --help. निर्देशों के बारे में जानकारी पाएं.

अगर बूटलोडर में fastboot लागू है, तो यह 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 चलाएं.

ओटीए पैकेज जनरेट करना

ओटीए पैकेज टूल, उन ही कमांड का पालन करते हैं जो A/B डिवाइसों के लिए इस्तेमाल किए जाते हैं. 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 मेक वैरिएबल से कॉन्फ़िगर की जाती है.

उदाहरण के लिए, अगर एक जोड़ी सेक्शन bootloader_a और booloader_b शामिल हैं (_a और _b स्लॉट के सफ़िक्स हैं), तो प्रॉडक्ट या बोर्ड के कॉन्फ़िगरेशन में ये बताकर, इन सेक्शन को अपडेट किया जा सकता है:

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

update_engine से अपडेट किए गए सभी पार्टीशन में, बाकी सिस्टम से बदलाव नहीं किया जाना चाहिए. इंक्रीमेंटल या डेल्टा अपडेट के दौरान, मौजूदा स्लॉट के बाइनरी डेटा का इस्तेमाल, नए स्लॉट में डेटा जनरेट करने के लिए किया जाता है. किसी भी तरह के बदलाव की वजह से, अपडेट की प्रोसेस के दौरान नए स्लॉट डेटा की पुष्टि नहीं हो पाएगी. इसलिए, अपडेट नहीं हो पाएगा.

postinstallation को कॉन्फ़िगर करना

अपडेट किए गए हर पार्टीशन के लिए, पोस्ट-इंस्टॉल चरण को अलग तरीके से कॉन्फ़िगर किया जा सकता है. इसके लिए, की-वैल्यू पेयर के सेट का इस्तेमाल करें. किसी नई इमेज में /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 फ़ाइलों को पहले बूट के दौरान इंस्टॉल करना लेख पढ़ें.