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

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

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

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

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

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

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

पार्टीशन में बदलाव

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

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

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

इस्तेमाल किए जा सकने वाले डाइनैमिक पार्टीशन हैं:

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

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

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

अगर super पार्टीशन को सही तरीके से अलाइन नहीं किया गया है, तो हो सकता है कि डिवाइस-मैपर मॉड्यूल कम असरदार तरीके से काम करे. super partition को कम से कम I/O अनुरोध के साइज़ के हिसाब से अलाइन करना ज़रूरी है. यह साइज़, ब्लॉक लेयर तय करती है. डिफ़ॉल्ट रूप से, बिल्ड सिस्टम (lpmake के ज़रिए, जो super पार्टिशन इमेज जनरेट करता है) को यह मानता है कि हर डाइनैमिक पार्टीशन के लिए एक एमआईबी अलाइनमेंट काफ़ी होगा. हालांकि, वेंडर को यह पक्का करना चाहिए कि 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 का है, लेकिन डिवाइस के हिसाब से आप इससे बड़ा ओवरहेड चुन सकते हैं.

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

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

रीड-ओनली 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 एमबी का खाली स्टोरेज स्पेस होना ज़रूरी हो जाता है.

रूट के मुताबिक सिस्टम में होने वाले बदलाव

Android 10 के साथ लॉन्च होने वाले डिवाइसों को, system-as-root का इस्तेमाल नहीं करना चाहिए.

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

BOARD_BUILD_SYSTEM_ROOT_IMAGE को सेट न करें. Android 10 में, BOARD_BUILD_SYSTEM_ROOT_IMAGE फ़्लैग का इस्तेमाल सिर्फ़ यह पता लगाने के लिए किया जाता है कि सिस्टम को, कर्नल ने माउंट किया है या रामडिस्क में पहले चरण के 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 को kernel command-line पर पास नहीं करना चाहिए. इसके बजाय, रिकवरी को छोड़ने और सामान्य Android को बूट करने के लिए, बूटलोडर को androidboot.force_normal_boot=1 पास करना चाहिए. Android 12 या उसके बाद के वर्शन वाले डिवाइसों को androidboot.force_normal_boot=1 पास करने के लिए, bootconfig का इस्तेमाल करना होगा.

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

अगर 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 फ़ुटर मिलना चाहिए. ये पार्टीशन, अब bootloader को नहीं दिखते (ये 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."

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

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

उदाहरण के लिए, अगर नाम के हिसाब से सुपर पार्टीशन का लिंक /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 फ़ाइल का इस्तेमाल करें जो रैमडиск का हिस्सा होगी.

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

  • fs_mgr flags फ़ील्ड में 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

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

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

adb remount

eng या userdebug बिल्ड का इस्तेमाल करने वाले डेवलपर के लिए, adb remount तेज़ी से बदलाव करने के लिए काफ़ी मददगार है. डाइनैमिक पार्टीशन, adb remount के लिए एक समस्या है, क्योंकि अब हर फ़ाइल सिस्टम में खाली जगह नहीं है. इसे ठीक करने के लिए, डिवाइस ओवरलेफ़ को चालू कर सकते हैं. जब तक सुपर पार्टीशन में खाली जगह है, तब तक 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 डिवाइसों के लिए ओटीए देखें.

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

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

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

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

पहले से मौजूद डिवाइसों के लिए, make dist super_*.img इमेज का एक सेट बनाता है. इन्हें सीधे तौर पर, संबंधित फ़िज़िकल पार्टीशन में फ़्लैश किया जा सकता है. उदाहरण के लिए, जब BOARD_SUPER_PARTITION_BLOCK_DEVICES सिस्टम वेंडर है, तो make dist, 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 को मैनेज करने के लिए, उन्हें बूट के शुरुआती चरणों में इस्तेमाल नहीं किया जा सकता. जब तक init.rc स्क्रिप्ट early-fs में बदलाव नहीं कर सकतीं, तब तक आपको उम्मीद करनी चाहिए कि कोर के डिफ़ॉल्ट read_ahead_kb काफ़ी होंगे. early-fs में बदलाव तब होता है, जब अलग-अलग डेमन और सुविधाएं शुरू होती हैं. इसलिए, Google का सुझाव है कि आप कार्रवाइयों की सही अवधि तय करने और रेस से जुड़ी स्थितियों को रोकने के लिए, sys.read_ahead_kb जैसी init.rc कंट्रोल वाली प्रॉपर्टी के साथ-साथ on property की सुविधा का इस्तेमाल करें, जैसा कि यहां दिए गए उदाहरण में बताया गया है:

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}