डाइनैमिक पार्टीशन लागू करना

डाइनैमिक पार्टिशनिंग को Linux कर्नल में dm-linear डिवाइस-मैपर मॉड्यूल का इस्तेमाल करके लागू किया जाता है. super पार्टीशन में, super के अंदर मौजूद हर डाइनैमिक पार्टीशन के नाम और ब्लॉक रेंज की जानकारी देने वाला मेटाडेटा होता है. पहले चरण की init के दौरान, इस मेटाडेटा को पार्स और पुष्टि की जाती है. साथ ही, हर डाइनैमिक पार्टीशन को दिखाने के लिए वर्चुअल ब्लॉक डिवाइस बनाए जाते हैं.

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

डाइनैमिक पार्टिशन को यूज़रस्पेस में लागू किया जाता है. इसलिए, बूटलोडर के लिए ज़रूरी पार्टिशन को डाइनैमिक नहीं बनाया जा सकता. उदाहरण के लिए, boot, dtbo, और vbmeta को बूटलोडर पढ़ता है. इसलिए, इन्हें फ़िज़िकल पार्टीशन के तौर पर ही रहना चाहिए.

हर डाइनैमिक पार्टीशन, अपडेट ग्रुप से जुड़ा हो सकता है. ये ग्रुप, उस ग्रुप में मौजूद पार्टीशन के लिए ज़्यादा से ज़्यादा जगह तय करते हैं. उदाहरण के लिए, system और vendor, ऐसे ग्रुप से जुड़े हो सकते हैं जो system और vendor के कुल साइज़ को सीमित करता है.

नए डिवाइसों पर डाइनैमिक पार्टिशन लागू करना

इस सेक्शन में, Android 10 और इसके बाद के वर्शन के साथ लॉन्च होने वाले नए डिवाइसों पर डाइनैमिक पार्टिशन लागू करने के तरीके के बारे में बताया गया है. मौजूदा डिवाइसों को अपडेट करने के लिए, Android डिवाइसों को अपग्रेड करना लेख पढ़ें.

पार्टिशन में हुए बदलाव

Android 10 के साथ लॉन्च होने वाले डिवाइसों के लिए, super नाम का एक पार्टिशन बनाएं. super पार्टिशन, A/B स्लॉट को अंदरूनी तौर पर मैनेज करता है. इसलिए, A/B डिवाइसों को अलग-अलग super_a और super_b पार्टिशन की ज़रूरत नहीं होती. रीड-ओनली वाले सभी एओएसपी पार्टिशन, बूटलोडर के लिए इस्तेमाल नहीं किए जाते. इसलिए, इन्हें डाइनैमिक होना चाहिए. साथ ही, इन्हें GUID पार्टिशन टेबल (GPT) से हटा दिया जाना चाहिए. वेंडर के हिसाब से बनाए गए पार्टिशन का डाइनैमिक होना ज़रूरी नहीं है. इन्हें GPT में रखा जा सकता है.

super के साइज़ का अनुमान लगाने के लिए, GPT से मिटाए जा रहे पार्टिशन के साइज़ जोड़ें. A/B डिवाइसों के लिए, इसमें दोनों स्लॉट का साइज़ शामिल होना चाहिए. पहली इमेज में, डाइनैमिक पार्टीशन में बदलने से पहले और बाद में, पार्टीशन टेबल का उदाहरण दिखाया गया है.

सेगमेंट में बांटी गई टेबल का लेआउट
पहली इमेज. डाइनैमिक पार्टिशन में बदलने पर, फ़िज़िकल पार्टिशन टेबल का नया लेआउट

डाइनैमिक पार्टिशन के लिए, इन कॉलम का इस्तेमाल किया जा सकता है:

  • सिस्टम
  • वेंडर
  • प्रॉडक्ट
  • सिस्टम एक्सटेंशन
  • ओडीएम

Android 10 के साथ लॉन्च होने वाले डिवाइसों के लिए, कर्नेल कमांड लाइन विकल्प androidboot.super_partition खाली होना चाहिए, ताकि कमांड sysprop ro.boot.super_partition खाली हो.

सेगमेंट का अलाइनमेंट

अगर super पार्टीशन सही तरीके से अलाइन नहीं किया गया है, तो हो सकता है कि डिवाइस-मैपर मॉड्यूल ठीक से काम न करे. super पार्टीशन को ब्लॉक लेयर के हिसाब से तय किए गए कम से कम I/O अनुरोध के साइज़ के साथ अलाइन किया जाना चाहिए. डिफ़ॉल्ट रूप से, बिल्ड सिस्टम (lpmake के ज़रिए, जो super पार्टीशन इमेज जनरेट करता है) यह मानता है कि हर डाइनैमिक पार्टीशन के लिए 1 MiB अलाइनमेंट काफ़ी है. हालांकि, वेंडर को यह पक्का करना चाहिए कि super पार्टीशन सही तरीके से अलाइन किया गया हो.

sysfs की जांच करके, ब्लॉक डिवाइस के लिए अनुरोध किए जा सकने वाले कम से कम साइज़ का पता लगाया जा सकता है. उदाहरण के लिए:

# ls -l /dev/block/by-name/super
lrwxrwxrwx 1 root root 16 1970-04-05 01:41 /dev/block/by-name/super -> /dev/block/sda17
# cat /sys/block/sda/queue/minimum_io_size
786432

इसी तरह, super पार्टीशन के अलाइनमेंट की पुष्टि की जा सकती है:

# cat /sys/block/sda/sda17/alignment_offset

अलाइनमेंट ऑफ़सेट की वैल्यू 0 होनी चाहिए.

डिवाइस के कॉन्फ़िगरेशन में बदलाव

डाइनैमिक पार्टिशनिंग की सुविधा चालू करने के लिए, device.mk में यह फ़्लैग जोड़ें:

PRODUCT_USE_DYNAMIC_PARTITIONS := true

बोर्ड के कॉन्फ़िगरेशन में बदलाव

आपको super पार्टिशन का साइज़ सेट करना होगा:

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

A/B डिवाइसों पर, अगर डाइनैमिक पार्टीशन इमेज का कुल साइज़, super पार्टीशन के साइज़ के आधे से ज़्यादा है, तो बिल्ड सिस्टम एक गड़बड़ी दिखाता है.

डाइनैमिक पार्टीशन की सूची को इस तरह कॉन्फ़िगर किया जा सकता है. अपडेट ग्रुप का इस्तेमाल करने वाले डिवाइसों के लिए, BOARD_SUPER_PARTITION_GROUPS वैरिएबल में ग्रुप की सूची बनाएं. इसके बाद, हर ग्रुप के नाम में BOARD_group_SIZE और BOARD_group_PARTITION_LIST वैरिएबल होता है. A/B डिवाइसों के लिए, ग्रुप का ज़्यादा से ज़्यादा साइज़ सिर्फ़ एक स्लॉट का होना चाहिए. ऐसा इसलिए, क्योंकि ग्रुप के नामों में स्लॉट का सफ़िक्स अंदरूनी तौर पर जोड़ा जाता है.

यहां एक ऐसे डिवाइस का उदाहरण दिया गया है जो सभी पार्टीशन को example_dynamic_partitions नाम के ग्रुप में रखता है:

BOARD_SUPER_PARTITION_GROUPS := example_dynamic_partitions
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_SIZE := 6442450944
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product

यहां एक ऐसे डिवाइस का उदाहरण दिया गया है जो सिस्टम और प्रॉडक्ट सेवाओं को group_foo और vendor, product, और odm को group_bar में रखता है:

BOARD_SUPER_PARTITION_GROUPS := group_foo group_bar
BOARD_GROUP_FOO_SIZE := 4831838208
BOARD_GROUP_FOO_PARTITION_LIST := system product_services
BOARD_GROUP_BAR_SIZE := 1610612736
BOARD_GROUP_BAR_PARTITION_LIST := vendor product odm
  • वर्चुअल A/B लॉन्च करने वाले डिवाइसों के लिए, सभी ग्रुप के ज़्यादा से ज़्यादा साइज़ का योग, ज़्यादा से ज़्यादा इतना होना चाहिए:
    BOARD_SUPER_PARTITION_SIZE - ओवरहेड
    वर्चुअल A/B लागू करना लेख पढ़ें.
  • A/B लॉन्च डिवाइसों के लिए, सभी ग्रुप के ज़्यादा से ज़्यादा साइज़ का योग यह होना चाहिए:
    BOARD_SUPER_PARTITION_SIZE / 2 - ओवरहेड
  • नॉन-A/B डिवाइसों और रेट्रोफ़िट A/B डिवाइसों के लिए, सभी ग्रुप के ज़्यादा से ज़्यादा साइज़ का योग यह होना चाहिए:
    BOARD_SUPER_PARTITION_SIZE - ओवरहेड
  • बिल्ड टाइम पर, अपडेट ग्रुप में मौजूद हर पार्टीशन की इमेज के साइज़ का योग, ग्रुप के ज़्यादा से ज़्यादा साइज़ से ज़्यादा नहीं होना चाहिए.
  • मेटाडेटा, अलाइनमेंट वगैरह का हिसाब लगाने के लिए, कैलकुलेशन में ओवरहेड की ज़रूरत होती है. 4 MiB का ओवरहेड सही होता है. हालांकि, डिवाइस की ज़रूरत के हिसाब से इससे ज़्यादा ओवरहेड चुना जा सकता है.

डाइनैमिक पार्टिशन का साइज़

डाइनैमिक पार्टिशन से पहले, पार्टिशन के साइज़ को ज़्यादा जगह दी जाती थी, ताकि आने वाले समय में अपडेट के लिए उनके पास काफ़ी जगह हो. असल साइज़ को वैसे ही लिया गया था और ज़्यादातर रीड-ओनली पार्टीशन के फ़ाइल सिस्टम में कुछ जगह खाली थी. डाइनैमिक पार्टिशन में, उस खाली जगह का इस्तेमाल नहीं किया जा सकता. हालांकि, इसका इस्तेमाल ओटीए के दौरान पार्टिशन को बढ़ाने के लिए किया जा सकता है. यह पक्का करना ज़रूरी है कि पार्टीशन से जगह बर्बाद न हो और उन्हें कम से कम जगह में बांटा गया हो.

सिर्फ़ पढ़ने के लिए उपलब्ध ext4 इमेज के लिए, बिल्ड सिस्टम अपने-आप कम से कम साइज़ असाइन करता है. ऐसा तब होता है, जब हार्डकोड किए गए पार्टिशन का साइज़ नहीं दिया जाता. बिल्ड सिस्टम, इमेज को इस तरह से फ़िट करता है कि फ़ाइल सिस्टम में कम से कम जगह खाली रहे. इससे यह पक्का होता है कि डिवाइस, ऐसी जगह को बर्बाद न करे जिसका इस्तेमाल ओटीए के लिए किया जा सकता है.

इसके अलावा, ब्लॉक-लेवल डिडुप्लीकेशन की सुविधा चालू करके, ext4 इमेज को और कंप्रेस किया जा सकता है. इसे चालू करने के लिए, इस कॉन्फ़िगरेशन का इस्तेमाल करें:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

अगर आपको पार्टीशन के कम से कम साइज़ को अपने-आप असाइन होने से रोकना है, तो पार्टीशन के साइज़ को कंट्रोल करने के दो तरीके हैं. BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE एट्रिब्यूट का इस्तेमाल करके, कम से कम खाली जगह की जानकारी दी जा सकती है. इसके अलावा, BOARD_partitionIMAGE_PARTITION_SIZE एट्रिब्यूट का इस्तेमाल करके, डाइनैमिक पार्टीशन को किसी खास साइज़ में फ़ोर्स किया जा सकता है. हम इनमें से किसी भी तरीके का सुझाव तब तक नहीं देते, जब तक कि ऐसा करना ज़रूरी न हो.

उदाहरण के लिए:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

इससे product.img में फ़ाइल सिस्टम को 50 MiB का इस्तेमाल न किया गया स्पेस उपलब्ध कराने के लिए मजबूर किया जाता है.

सिस्टम-ऐज़-रूट में हुए बदलाव

Android 10 के साथ लॉन्च होने वाले डिवाइसों में, सिस्टम-ऐज़-रूट का इस्तेमाल नहीं किया जाना चाहिए.

डाइनैमिक पार्टिशन वाले डिवाइसों को सिस्टम-ऐज़-रूट का इस्तेमाल नहीं करना चाहिए. भले ही, डिवाइस डाइनैमिक पार्टिशन के साथ लॉन्च हुआ हो या उसमें डाइनैमिक पार्टिशन बाद में जोड़ा गया हो. Linux कर्नल, super पार्टीशन को नहीं समझ सकता. इसलिए, वह super को माउंट नहीं कर सकता.system system अब पहले चरण के init से माउंट किया गया है. यह रैमडिस्क में मौजूद होता है.

BOARD_BUILD_SYSTEM_ROOT_IMAGE को सेट न करें. Android 10 में, BOARD_BUILD_SYSTEM_ROOT_IMAGE फ़्लैग का इस्तेमाल सिर्फ़ यह पता लगाने के लिए किया जाता है कि सिस्टम को कर्नल ने माउंट किया है या ramdisk में मौजूद पहले चरण के init ने.

BOARD_BUILD_SYSTEM_ROOT_IMAGE को true पर सेट करने से, बिल्ड से जुड़ी गड़बड़ी होती है. ऐसा तब होता है, जब PRODUCT_USE_DYNAMIC_PARTITIONS भी true पर सेट हो.

BOARD_USES_RECOVERY_AS_BOOT को सही पर सेट करने पर, रिकवरी इमेज को boot.img के तौर पर बनाया जाता है. इसमें रिकवरी का रैमडिस्क शामिल होता है. इससे पहले, बूटलोडर skip_initramfs kernel कमांड लाइन पैरामीटर का इस्तेमाल करके यह तय करता था कि किस मोड में बूट करना है. Android 10 वाले डिवाइसों के लिए, बूटलोडर को कर्नेल कमांड-लाइन में skip_initramfs पास नहीं करना चाहिए. इसके बजाय, बूटलोडर को androidboot.force_normal_boot=1 पास करना चाहिए, ताकि रिकवरी को स्किप किया जा सके और सामान्य Android बूट हो सके. Android 12 या इसके बाद के वर्शन के साथ लॉन्च किए गए डिवाइसों को androidboot.force_normal_boot=1 पास करने के लिए, bootconfig का इस्तेमाल करना होगा.

AVB कॉन्फ़िगरेशन में बदलाव

Android Verified Boot 2.0 का इस्तेमाल करते समय, अगर डिवाइस चेन किए गए पार्टीशन डिस्क्रिप्टर का इस्तेमाल नहीं कर रहा है, तो कोई बदलाव करने की ज़रूरत नहीं है. हालांकि, अगर चेन किए गए पार्टीशन का इस्तेमाल किया जा रहा है और पुष्टि किए गए पार्टीशन में से कोई एक डाइनैमिक है, तो बदलाव करना ज़रूरी है.

यहां एक ऐसे डिवाइस के लिए कॉन्फ़िगरेशन का उदाहरण दिया गया है जो system और vendor पार्टीशन के लिए, vbmeta को चेन करता है.

BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048
BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1

BOARD_AVB_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_VENDOR_ALGORITHM := SHA256_RSA2048
BOARD_AVB_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION := 1

इस कॉन्फ़िगरेशन के साथ, बूटलोडर को system और vendor पार्टीशन के आखिर में vbmeta फ़ुटर मिलने की उम्मीद होती है. ये पार्टिशन अब बूटलोडर को नहीं दिखते (ये super में मौजूद हैं). इसलिए, दो बदलाव करने होंगे.

  • डिवाइस की पार्टीशन टेबल में vbmeta_system और vbmeta_vendor पार्टिशन जोड़ें. A/B डिवाइसों के लिए, vbmeta_system_a, vbmeta_system_b, vbmeta_vendor_a, और vbmeta_vendor_b जोड़ें. अगर इनमें से एक या उससे ज़्यादा पार्टीशन जोड़े जाते हैं, तो उनका साइज़ vbmeta पार्टीशन के साइज़ के बराबर होना चाहिए.
  • कॉन्फ़िगरेशन फ़्लैग का नाम बदलें. इसके लिए, VBMETA_ जोड़ें. साथ ही, यह बताएं कि चेनिंग किन पार्टीशन तक फैली हुई है:
    BOARD_AVB_VBMETA_SYSTEM := system
    BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
    
    BOARD_AVB_VBMETA_VENDOR := vendor
    BOARD_AVB_VBMETA_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_VENDOR_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX_LOCATION := 1

कोई डिवाइस इनमें से एक, दोनों या किसी भी पार्टीशन का इस्तेमाल नहीं कर सकता. बदलाव सिर्फ़ तब ज़रूरी होते हैं, जब लॉजिकल पार्टीशन से चेन किया जा रहा हो.

एवीबी बूटलोडर में बदलाव

अगर बूटलोडर में libavb एम्बेड किया गया है, तो ये पैच शामिल करें:

चेन किए गए पार्टिशन का इस्तेमाल करने पर, एक और पैच शामिल करें:

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: Support vbmeta blobs in beginning of partition."

कर्नेल कमांड लाइन में बदलाव

कर्नेल कमांड लाइन में एक नया पैरामीटर, androidboot.boot_devices, जोड़ा जाना चाहिए. init इस कुकी का इस्तेमाल, /dev/block/by-name सिंबल लिंक चालू करने के लिए करता है. यह ueventd की ओर से बनाए गए, नाम के हिसाब से सिंबल वाले लिंक का डिवाइस पाथ कॉम्पोनेंट होना चाहिए. जैसे, /dev/block/platform/device-path/by-name/partition-name. Android 12 या इसके बाद के वर्शन के साथ लॉन्च किए गए डिवाइसों को, androidboot.boot_devices को init तक पहुंचाने के लिए, बूट कॉन्फ़िगरेशन का इस्तेमाल करना होगा.

उदाहरण के लिए, अगर सुपर पार्टीशन का नाम वाला सिंबॉलिक लिंक /dev/block/platform/soc/100000.ufshc/by-name/super है, तो BoardConfig.mk फ़ाइल में कमांड लाइन पैरामीटर को इस तरह जोड़ा जा सकता है:

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
BoardConfig.mk फ़ाइल में bootconfig पैरामीटर को इस तरह जोड़ा जा सकता है:
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

fstab में हुए बदलाव

डिवाइस ट्री और डिवाइस ट्री ओवरले में fstab की एंट्री नहीं होनी चाहिए. ऐसी fstab फ़ाइल का इस्तेमाल करें जो ramdisk का हिस्सा होगी.

लॉजिकल पार्टीशन के लिए, fstab फ़ाइल में ये बदलाव किए जाने चाहिए:

  • fs_mgr फ़्लैग फ़ील्ड में logical फ़्लैग और first_stage_mount फ़्लैग शामिल होना चाहिए. first_stage_mount फ़्लैग को Android 10 में पेश किया गया था. यह फ़्लैग बताता है कि किसी पार्टीशन को पहले चरण में माउंट किया जाना है.
  • कोई पार्टिशन, avb=vbmeta partition name को fs_mgr फ़्लैग के तौर पर तय कर सकता है. इसके बाद, तय किए गए vbmeta पार्टिशन को पहले चरण के init से शुरू किया जाता है. ऐसा किसी भी डिवाइस को माउंट करने से पहले किया जाता है.
  • dev फ़ील्ड, पार्टीशन का नाम होना चाहिए.

यहां दी गई fstab एंट्री, ऊपर दिए गए नियमों के मुताबिक सिस्टम, वेंडर, और प्रॉडक्ट को लॉजिकल पार्टिशन के तौर पर सेट करती हैं.

#<dev>  <mnt_point> <type>  <mnt_flags options> <fs_mgr_flags>
system   /system     ext4    ro,barrier=1        wait,slotselect,avb=vbmeta,logical,first_stage_mount
vendor   /vendor     ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount
product  /product    ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount

fstab फ़ाइल को पहले चरण के रैमडिस्क में कॉपी करें.

SELinux में किए गए बदलाव

सुपर पार्टीशन ब्लॉक डिवाइस को super_block_device लेबल के साथ मार्क किया जाना चाहिए. उदाहरण के लिए, अगर नाम के हिसाब से सुपर पार्टीशन का सिंबॉलिक लिंक यह है: /dev/block/platform/soc/100000.ufshc/by-name/super, तो file_contexts में यह लाइन जोड़ें:

/dev/block/platform/soc/10000\.ufshc/by-name/super   u:object_r:super_block_device:s0

fastbootd

बूटलोडर (या नॉन-यूज़रस्पेस फ़्लैशिंग टूल) को डाइनैमिक पार्टीशन के बारे में जानकारी नहीं होती. इसलिए, वह उन्हें फ़्लैश नहीं कर सकता. इस समस्या को हल करने के लिए, डिवाइसों को फ़ास्टबूट प्रोटोकॉल के उपयोगकर्ता-स्पेस वर्शन का इस्तेमाल करना होगा. इसे fastbootd कहा जाता है.

fastbootd को लागू करने के तरीके के बारे में ज़्यादा जानने के लिए, Fastboot को उपयोगकर्ता स्पेस में ले जाना लेख पढ़ें.

adb remount

eng या userdebug बिल्ड का इस्तेमाल करने वाले डेवलपर के लिए, adb remount तेज़ इटरेशन के लिए बेहद मददगार है. डाइनैमिक पार्टिशन की वजह से, adb remount को समस्या आ सकती है. ऐसा इसलिए, क्योंकि अब हर फ़ाइल सिस्टम में खाली जगह नहीं है. इस समस्या को ठीक करने के लिए, डिवाइसों पर overlayfs चालू किया जा सकता है. जब तक सुपर पार्टीशन में खाली जगह होती है, तब तक adb remount अपने-आप एक अस्थायी डाइनैमिक पार्टीशन बनाता है और लिखने के लिए overlayfs का इस्तेमाल करता है. अस्थायी पार्टीशन का नाम scratch है. इसलिए, इस नाम का इस्तेमाल अन्य पार्टीशन के लिए न करें.

overlayfs को चालू करने के तरीके के बारे में ज़्यादा जानने के लिए, AOSP में overlayfs README देखें.

Android डिवाइसों को अपग्रेड करना

अगर आपने किसी डिवाइस को Android 10 पर अपग्रेड किया है और आपको ओटीए में डाइनैमिक पार्टिशन की सुविधा शामिल करनी है, तो आपको पहले से मौजूद पार्टिशन टेबल में बदलाव करने की ज़रूरत नहीं है. इसके लिए, कुछ अतिरिक्त कॉन्फ़िगरेशन की ज़रूरत होती है.

डिवाइस के कॉन्फ़िगरेशन में बदलाव

डाइनैमिक पार्टिशनिंग को फिर से लागू करने के लिए, device.mk में ये फ़्लैग जोड़ें:

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

बोर्ड के कॉन्फ़िगरेशन में बदलाव

आपको बोर्ड के ये वैरिएबल सेट करने होंगे:

  • BOARD_SUPER_PARTITION_BLOCK_DEVICES को ब्लॉक किए गए उन डिवाइसों की सूची पर सेट करें जिनका इस्तेमाल, डाइनैमिक पार्टीशन के एक्सटेंट को सेव करने के लिए किया जाता है. यह डिवाइस पर मौजूद फ़िज़िकल पार्टीशन के नामों की सूची है.
  • BOARD_SUPER_PARTITION_partition_DEVICE_SIZE को BOARD_SUPER_PARTITION_BLOCK_DEVICES में मौजूद हर ब्लॉक डिवाइस के साइज़ के हिसाब से सेट करें. यह डिवाइस पर मौजूद फ़िज़िकल पार्टीशन के साइज़ की सूची है. आम तौर पर, यह मौजूदा बोर्ड कॉन्फ़िगरेशन में BOARD_partitionIMAGE_PARTITION_SIZE होता है.
  • BOARD_SUPER_PARTITION_BLOCK_DEVICES में मौजूद सभी पार्टीशन के लिए, मौजूदा BOARD_partitionIMAGE_PARTITION_SIZE को अनसेट करें.
  • BOARD_SUPER_PARTITION_SIZE को BOARD_SUPER_PARTITION_partition_DEVICE_SIZE के योग पर सेट करें.
  • BOARD_SUPER_PARTITION_METADATA_DEVICE को उस डिवाइस पर सेट करें जहां डाइनैमिक पार्टीशन का मेटाडेटा सेव किया जाता है. यह वैल्यू BOARD_SUPER_PARTITION_BLOCK_DEVICES में से कोई एक होनी चाहिए. आम तौर पर, यह system पर सेट होता है.
  • BOARD_SUPER_PARTITION_GROUPS, BOARD_group_SIZE, और BOARD_group_PARTITION_LIST को सेट करें. ज़्यादा जानकारी के लिए, नए डिवाइसों पर बोर्ड के कॉन्फ़िगरेशन में बदलाव लेख पढ़ें.

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

BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor
BOARD_SUPER_PARTITION_METADATA_DEVICE := system

# Rename BOARD_SYSTEMIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE.
BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := <size-in-bytes>

# Rename BOARD_VENDORIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := <size-in-bytes>

# This is BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE + BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

# Configuration for dynamic partitions. For example:
BOARD_SUPER_PARTITION_GROUPS := group_foo
BOARD_GROUP_FOO_SIZE := <size-in-bytes>
BOARD_GROUP_FOO_PARTITION_LIST := system vendor product

SELinux में किए गए बदलाव

सुपर पार्टीशन ब्लॉक डिवाइसों को super_block_device_type एट्रिब्यूट के साथ मार्क किया जाना चाहिए. उदाहरण के लिए, अगर डिवाइस में पहले से ही system और vendor पार्टीशन हैं, तो आपको उनका इस्तेमाल ब्लॉक डिवाइसों के तौर पर करना है, ताकि डाइनैमिक पार्टीशन के एक्सटेंट सेव किए जा सकें. साथ ही, उनके नाम के हिसाब से सिंबल लिंक को system_block_device के तौर पर मार्क किया गया है:

/dev/block/platform/soc/10000\.ufshc/by-name/system   u:object_r:system_block_device:s0
/dev/block/platform/soc/10000\.ufshc/by-name/vendor   u:object_r:system_block_device:s0

इसके बाद, device.te में यह लाइन जोड़ें:

typeattribute system_block_device super_block_device_type;

अन्य कॉन्फ़िगरेशन के लिए, नए डिवाइसों पर डाइनैमिक पार्टीशन लागू करना लेख पढ़ें.

रेट्रोफ़िट अपडेट के बारे में ज़्यादा जानने के लिए, डाइनैमिक पार्टीशन के बिना A/B डिवाइसों के लिए OTA देखें.

फ़ैक्ट्री इमेज

डाइनैमिक पार्टिशन की सुविधा के साथ लॉन्च होने वाले डिवाइस के लिए, फ़ैक्ट्री इमेज फ़्लैश करने के लिए userspace fastboot का इस्तेमाल न करें. ऐसा इसलिए, क्योंकि userspace में बूट करना, फ़्लैश करने के अन्य तरीकों की तुलना में धीमा होता है.

इस समस्या को हल करने के लिए, make dist अब एक अतिरिक्त super.img इमेज बनाता है. इसे सीधे तौर पर सुपर पार्टीशन में फ़्लैश किया जा सकता है. यह लॉजिकल पार्टीशन के कॉन्टेंट को अपने-आप बंडल कर देता है. इसका मतलब है कि इसमें system.img, vendor.img वगैरह के साथ-साथ super पार्टीशन का मेटाडेटा भी शामिल होता है. इस इमेज को सीधे super पार्टीशन में फ़्लैश किया जा सकता है. इसके लिए, किसी अन्य टूल की ज़रूरत नहीं होती. साथ ही, फ़ास्टबूटडी का इस्तेमाल भी नहीं करना पड़ता. बिल्ड के बाद, super.img को ${ANDROID_PRODUCT_OUT} में रखा जाता है.

डाइनैमिक पार्टिशन के साथ लॉन्च होने वाले A/B डिवाइसों के लिए, super.img में A स्लॉट में मौजूद इमेज होती हैं. सुपर इमेज को सीधे तौर पर फ़्लैश करने के बाद, डिवाइस को रीबूट करने से पहले स्लॉट A को बूट करने लायक के तौर पर मार्क करें.

रेट्रोफ़िट डिवाइसों के लिए, make dist, super_*.img इमेज का एक सेट बनाता है. इन्हें सीधे तौर पर, उनसे जुड़े फ़िज़िकल पार्टीशन में फ़्लैश किया जा सकता है. उदाहरण के लिए, make dist, BOARD_SUPER_PARTITION_BLOCK_DEVICES के सिस्टम वेंडर होने पर super_system.img और super_vendor.img बनाता है. ये इमेज, target_files.zip में मौजूद OTA फ़ोल्डर में रखी जाती हैं.

डिवाइस मैपर स्टोरेज-डिवाइस ट्यूनिंग

डाइनैमिक पार्टिशनिंग में, डिवाइस-मैपर के कई नॉनडिटरमिनिस्टिक ऑब्जेक्ट शामिल होते हैं. ऐसा हो सकता है कि ये सभी उम्मीद के मुताबिक इंस्टैंशिएट न हों. इसलिए, आपको सभी माउंट ट्रैक करने होंगे. साथ ही, उनसे जुड़ी सभी पार्टीशन की Android प्रॉपर्टी को उनके स्टोरेज डिवाइसों के साथ अपडेट करना होगा.

init में मौजूद एक सिस्टम, माउंट को ट्रैक करता है और Android प्रॉपर्टी को एसिंक्रोनस तरीके से अपडेट करता है. इस प्रोसेस में कितना समय लगेगा, इसकी कोई गारंटी नहीं है. इसलिए, आपको सभी on property ट्रिगर को काम करने के लिए ज़रूरी समय देना होगा. प्रॉपर्टी dev.mnt.blk.<partition> है, जहां <partition>, root, system, data या vendor है. उदाहरण के लिए. हर प्रॉपर्टी, स्टोरेज डिवाइस के नाम से जुड़ी होती है. जैसा कि इन उदाहरणों में दिखाया गया है:

taimen:/ % getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [sda]
[dev.mnt.blk.firmware]: [sde]
[dev.mnt.blk.metadata]: [sde]
[dev.mnt.blk.persist]: [sda]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.vendor]: [dm-1]

blueline:/ $ getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [dm-4]
[dev.mnt.blk.metadata]: [sda]
[dev.mnt.blk.mnt.scratch]: [sda]
[dev.mnt.blk.mnt.vendor.persist]: [sdf]
[dev.mnt.blk.product]: [dm-2]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.system_ext]: [dm-3]
[dev.mnt.blk.vendor]: [dm-1]
[dev.mnt.blk.vendor.firmware_mnt]: [sda]

init.rc भाषा की मदद से, Android प्रॉपर्टी को नियमों के तहत बढ़ाया जा सकता है. साथ ही, स्टोरेज डिवाइसों को प्लैटफ़ॉर्म से ज़रूरत के हिसाब से ट्यून किया जा सकता है. इसके लिए, इस तरह के निर्देश इस्तेमाल किए जा सकते हैं:

write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128
write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128

दूसरे चरण init में कमांड प्रोसेस होने के बाद, epoll loop चालू हो जाता है और वैल्यू अपडेट होने लगती हैं. हालांकि, प्रॉपर्टी ट्रिगर init के आखिर तक चालू नहीं होते. इसलिए, इनका इस्तेमाल बूटिंग के शुरुआती चरणों में root, system या vendor को मैनेज करने के लिए नहीं किया जा सकता. आपको लग सकता है कि कर्नल का डिफ़ॉल्ट read_ahead_kb तब तक काफ़ी है, जब तक कि init.rc स्क्रिप्ट early-fs में इसे बदल नहीं सकतीं. ऐसा तब होता है, जब अलग-अलग डेमॉन और सुविधाएं शुरू होती हैं. इसलिए, Google का सुझाव है कि आप on property सुविधा का इस्तेमाल करें. साथ ही, init.rc कंट्रोल की गई प्रॉपर्टी, जैसे कि sys.read_ahead_kb का इस्तेमाल करें. इससे आपको ऑपरेशन के समय को मैनेज करने और रेस की स्थितियों को रोकने में मदद मिलेगी. जैसे, इन उदाहरणों में दिखाया गया है:

on property:dev.mnt.blk.root=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.system=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.vendor=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.vendor}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.product=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system_ext}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.oem=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.oem}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.data=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on early-fs:
    setprop sys.read_ahead_kb ${ro.read_ahead_kb.boot:-2048}

on property:sys.boot_completed=1
   setprop sys.read_ahead_kb ${ro.read_ahead_kb.bootcomplete:-128}