গতিশীল পার্টিশন বাস্তবায়ন

লিনাক্স কার্নেলে dm-linear ডিভাইস-ম্যাপার মডিউল ব্যবহার করে ডাইনামিক পার্টিশনিং বাস্তবায়ন করা হয়। super পার্টিশনে মেটাডেটা থাকে, যেখানে super অন্তর্ভুক্ত প্রতিটি ডাইনামিক পার্টিশনের নাম এবং ব্লক রেঞ্জের তালিকা দেওয়া থাকে। প্রথম পর্যায়ের init চলাকালীন, এই মেটাডেটা পার্স ও ভ্যালিডেট করা হয় এবং প্রতিটি ডাইনামিক পার্টিশনকে প্রতিনিধিত্ব করার জন্য ভার্চুয়াল ব্লক ডিভাইস তৈরি করা হয়।

OTA প্রয়োগ করার সময়, প্রয়োজন অনুযায়ী ডায়নামিক পার্টিশনগুলি স্বয়ংক্রিয়ভাবে তৈরি, আকার পরিবর্তন বা মুছে ফেলা হয়। A/B ডিভাইসগুলির ক্ষেত্রে, মেটাডেটার দুটি কপি থাকে এবং পরিবর্তনগুলি শুধুমাত্র টার্গেট স্লটকে প্রতিনিধিত্বকারী কপিটিতেই প্রয়োগ করা হয়।

যেহেতু ডাইনামিক পার্টিশনগুলো ইউজারস্পেসে প্রয়োগ করা হয়, তাই বুটলোডারের জন্য প্রয়োজনীয় পার্টিশনগুলোকে ডাইনামিক করা যায় না। উদাহরণস্বরূপ, boot , dtbo , এবং vbmeta বুটলোডার দ্বারা পঠিত হয়, এবং তাই এগুলোকে ফিজিক্যাল পার্টিশন হিসেবেই রাখতে হবে।

প্রতিটি ডাইনামিক পার্টিশন একটি আপডেট গ্রুপের অন্তর্ভুক্ত হতে পারে। এই গ্রুপগুলো সেই গ্রুপের পার্টিশনগুলোর সর্বোচ্চ ব্যবহারযোগ্য স্থান সীমিত করে। উদাহরণস্বরূপ, system এবং vendor এমন একটি গ্রুপের অন্তর্ভুক্ত হতে পারে যা system এবং vendor এর মোট আকার সীমাবদ্ধ করে।

নতুন ডিভাইসগুলিতে ডায়নামিক পার্টিশন প্রয়োগ করুন

এই বিভাগে অ্যান্ড্রয়েড ১০ এবং তার পরবর্তী সংস্করণসহ লঞ্চ হওয়া নতুন ডিভাইসগুলিতে কীভাবে ডাইনামিক পার্টিশন প্রয়োগ করতে হয়, তার বিস্তারিত বিবরণ দেওয়া হয়েছে। বিদ্যমান ডিভাইসগুলি আপডেট করতে, অ্যান্ড্রয়েড ডিভাইস আপগ্রেড করা দেখুন।

পার্টিশন পরিবর্তন

অ্যান্ড্রয়েড ১০ সহ লঞ্চ হওয়া ডিভাইসগুলির জন্য, super নামে একটি পার্টিশন তৈরি করুন। super পার্টিশনটি অভ্যন্তরীণভাবে A/B স্লটগুলি পরিচালনা করে, তাই A/B ডিভাইসগুলির জন্য আলাদা super_a এবং super_b পার্টিশনের প্রয়োজন হয় না। বুটলোডার দ্বারা ব্যবহৃত হয় না এমন সমস্ত রিড-অনলি AOSP পার্টিশন অবশ্যই ডাইনামিক হতে হবে এবং GUID পার্টিশন টেবিল (GPT) থেকে মুছে ফেলতে হবে। ভেন্ডর-নির্দিষ্ট পার্টিশনগুলি ডাইনামিক হওয়ার প্রয়োজন নেই এবং সেগুলি GPT-তে রাখা যেতে পারে।

super এর আকার অনুমান করার জন্য, GPT থেকে মুছে ফেলা পার্টিশনগুলোর আকার যোগ করুন। A/B ডিভাইসের ক্ষেত্রে, এর মধ্যে উভয় স্লটের আকার অন্তর্ভুক্ত থাকা উচিত। চিত্র ১-এ ডাইনামিক পার্টিশনে রূপান্তরের আগে ও পরের একটি উদাহরণ পার্টিশন টেবিল দেখানো হয়েছে।

পার্টিশন টেবিল লেআউট
চিত্র ১. ডাইনামিক পার্টিশনে রূপান্তরের পর নতুন ফিজিক্যাল পার্টিশন টেবিলের বিন্যাস

সমর্থিত ডাইনামিক পার্টিশনগুলো হলো:

  • সিস্টেম
  • বিক্রেতা
  • পণ্য
  • সিস্টেম এক্সট
  • ওডিএম

যেসব ডিভাইস অ্যান্ড্রয়েড ১০ দিয়ে চালু হচ্ছে, সেগুলোর ক্ষেত্রে কার্নেল কমান্ড লাইন অপশন androidboot.super_partition অবশ্যই খালি রাখতে হবে, যাতে sysprop ro.boot.super_partition কমান্ডটি খালি থাকে।

পার্টিশন অ্যালাইনমেন্ট

super পার্টিশন সঠিকভাবে অ্যালাইন করা না থাকলে ডিভাইস-ম্যাপার মডিউলটি কম দক্ষতার সাথে কাজ করতে পারে। ব্লক লেয়ার দ্বারা নির্ধারিত সর্বনিম্ন I/O রিকোয়েস্ট সাইজের সাথে super পার্টিশনকে অবশ্যই অ্যালাইন করতে হবে। ডিফল্টরূপে, বিল্ড সিস্টেম ( lpmake এর মাধ্যমে, যা super পার্টিশন ইমেজ তৈরি করে) ধরে নেয় যে প্রতিটি ডাইনামিক পার্টিশনের জন্য ১ 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

অ্যালাইনমেন্ট অফসেট অবশ্যই ০ হতে হবে।

ডিভাইস কনফিগারেশন পরিবর্তন

ডাইনামিক পার্টিশনিং সক্রিয় করতে, 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 , productodm 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
  • ভার্চুয়াল এ/বি লঞ্চ ডিভাইসগুলোর ক্ষেত্রে, সকল গ্রুপের সর্বোচ্চ আকারের যোগফল অবশ্যই সর্বাধিক নিম্নরূপ হতে হবে:
    BOARD_SUPER_PARTITION_SIZE - ওভারহেড
    ভার্চুয়াল এ/বি বাস্তবায়ন দেখুন।
  • A/B লঞ্চ ডিভাইসের ক্ষেত্রে, সকল গ্রুপের সর্বোচ্চ আকারের যোগফল অবশ্যই নিম্নরূপ হতে হবে:
    BOARD_SUPER_PARTITION_SIZE / 2 - ওভারহেড
  • নন-এ/বি ডিভাইস এবং রেট্রোফিট এ/বি ডিভাইসের ক্ষেত্রে, সকল গ্রুপের সর্বোচ্চ আকারের যোগফল অবশ্যই নিম্নরূপ হতে হবে:
    BOARD_SUPER_PARTITION_SIZE - ওভারহেড
  • বিল্ড করার সময়, একটি আপডেট গ্রুপের প্রতিটি পার্টিশনের ইমেজগুলোর আকারের যোগফল অবশ্যই গ্রুপটির সর্বোচ্চ আকার অতিক্রম করবে না।
  • মেটাডেটা, অ্যালাইনমেন্ট ইত্যাদির হিসাব রাখার জন্য গণনায় ওভারহেড প্রয়োজন হয়। একটি যুক্তিসঙ্গত ওভারহেড হলো ৪ MiB, কিন্তু ডিভাইসের প্রয়োজন অনুযায়ী আপনি আরও বেশি ওভারহেড বেছে নিতে পারেন।

আকার ডায়নামিক পার্টিশন

ডাইনামিক পার্টিশন আসার আগে, ভবিষ্যতের আপডেটের জন্য পর্যাপ্ত জায়গা নিশ্চিত করতে পার্টিশনের আকার প্রয়োজনের চেয়ে বেশি রাখা হতো। প্রকৃত আকার যেমন ছিল তেমনই ধরা হতো এবং বেশিরভাগ রিড-অনলি পার্টিশনের ফাইল সিস্টেমে কিছু পরিমাণ ফাঁকা জায়গা থাকত। ডাইনামিক পার্টিশনে, সেই ফাঁকা জায়গা অব্যবহারযোগ্য এবং OTA আপডেটের সময় পার্টিশনের আকার বাড়াতে ব্যবহৃত হতে পারে। এটা নিশ্চিত করা অত্যন্ত জরুরি যে পার্টিশনগুলো যেন জায়গার অপচয় না করে এবং সেগুলোকে সর্বনিম্ন সম্ভাব্য আকারে বরাদ্দ করা হয়।

রিড-অনলি ext4 ইমেজের ক্ষেত্রে, যদি কোনো হার্ডকোডেড পার্টিশন সাইজ নির্দিষ্ট করা না থাকে, তাহলে বিল্ড সিস্টেম স্বয়ংক্রিয়ভাবে সর্বনিম্ন সাইজ বরাদ্দ করে। বিল্ড সিস্টেম ইমেজটিকে এমনভাবে বিন্যস্ত করে যাতে ফাইল সিস্টেমে যতটা সম্ভব কম অব্যবহৃত স্থান থাকে। এটি নিশ্চিত করে যে ডিভাইসটি এমন কোনো স্থান নষ্ট না করে যা OTA-এর জন্য ব্যবহার করা যেতে পারে।

এছাড়াও, ব্লক-লেভেল ডিডুপ্লিকেশন সক্রিয় করার মাধ্যমে ext4 ইমেজকে আরও সংকুচিত করা যায়। এটি সক্রিয় করতে, নিম্নলিখিত কনফিগারেশনটি ব্যবহার করুন:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

যদি পার্টিশনের ন্যূনতম আকারের স্বয়ংক্রিয় বরাদ্দ অনাকাঙ্ক্ষিত হয়, তবে পার্টিশনের আকার নিয়ন্ত্রণ করার দুটি উপায় আছে। আপনি BOARD_ partition IMAGE_PARTITION_RESERVED_SIZE ব্যবহার করে ন্যূনতম পরিমাণ খালি জায়গা নির্দিষ্ট করতে পারেন, অথবা ডাইনামিক পার্টিশনগুলোকে একটি নির্দিষ্ট আকারে বাধ্য করার জন্য BOARD_ partition IMAGE_PARTITION_SIZE নির্দিষ্ট করতে পারেন। প্রয়োজন না হলে এর কোনোটিই সুপারিশ করা হয় না।

উদাহরণস্বরূপ:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

এর ফলে product.img ফাইল সিস্টেমে ৫০ MiB অব্যবহৃত জায়গা থাকে।

সিস্টেম-মূল পরিবর্তন

অ্যান্ড্রয়েড ১০ সহ চালু হওয়া ডিভাইসগুলিতে সিস্টেম-অ্যাজ-রুট ব্যবহার করা যাবে না।

ডাইনামিক পার্টিশনযুক্ত ডিভাইসগুলিতে (সেটি চালু হওয়ার সময় থেকেই ডাইনামিক পার্টিশন থাকুক বা পরে যোগ করা হোক) সিস্টেম-অ্যাজ-রুট ব্যবহার করা উচিত নয়। লিনাক্স কার্নেল super পার্টিশনটি বুঝতে পারে না এবং তাই নিজে system মাউন্ট করতে পারে না। system এখন প্রথম-পর্যায়ের init দ্বারা মাউন্ট করা হয়, যা র‍্যামডিস্কে থাকে।

BOARD_BUILD_SYSTEM_ROOT_IMAGE সেট করবেন না। Android 10-এ, BOARD_BUILD_SYSTEM_ROOT_IMAGE ফ্ল্যাগটি শুধুমাত্র এটি আলাদা করার জন্য ব্যবহৃত হয় যে সিস্টেমটি কার্নেল দ্বারা মাউন্ট করা হয়েছে নাকি র‍্যামডিস্কে প্রথম-পর্যায়ের init দ্বারা।

যখন PRODUCT_USE_DYNAMIC_PARTITIONStrue থাকে, তখন BOARD_BUILD_SYSTEM_ROOT_IMAGE true সেট করলে একটি বিল্ড এরর দেখা দেয়।

যখন BOARD_USES_RECOVERY_AS_BOOT 'true' সেট করা হয়, তখন রিকভারি ইমেজটি boot.img হিসেবে তৈরি হয়, যাতে রিকভারির র‍্যামডিস্ক থাকে। পূর্বে, বুটলোডার কোন মোডে বুট করবে তা নির্ধারণ করতে skip_initramfs কার্নেল কমান্ড লাইন প্যারামিটার ব্যবহার করত। অ্যান্ড্রয়েড ১০ ডিভাইসগুলির জন্য, বুটলোডার কার্নেল কমান্ড-লাইনে skip_initramfs পাস করবে না। এর পরিবর্তে, রিকভারি এড়িয়ে সাধারণ অ্যান্ড্রয়েড বুট করার জন্য বুটলোডারকে androidboot.force_normal_boot=1 পাস করতে হবে। অ্যান্ড্রয়েড ১২ বা তার পরবর্তী সংস্করণ দিয়ে চালু হওয়া ডিভাইসগুলিকে অবশ্যই bootconfig ব্যবহার করে androidboot.force_normal_boot=1 পাস করতে হবে।

AVB কনফিগারেশন পরিবর্তন

অ্যান্ড্রয়েড ভেরিফাইড বুট ২.০ ব্যবহার করার সময়, যদি ডিভাইসটি চেইনড পার্টিশন ডেসক্রিপ্টর ব্যবহার না করে, তাহলে কোনো পরিবর্তনের প্রয়োজন নেই। তবে, যদি চেইনড পার্টিশন ব্যবহার করা হয় এবং ভেরিফাইড পার্টিশনগুলোর মধ্যে একটি ডাইনামিক হয়, তাহলে পরিবর্তন করা আবশ্যক।

এখানে এমন একটি ডিভাইসের কনফিগারেশনের উদাহরণ দেওয়া হলো, যা 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

একটি ডিভাইস এই পার্টিশনগুলোর একটি, উভয়টি, বা কোনোটিই ব্যবহার করতে পারে। শুধুমাত্র একটি লজিক্যাল পার্টিশনের সাথে চেইন করার সময়ই পরিবর্তনের প্রয়োজন হয়।

AVB বুটলোডার পরিবর্তন

যদি বুটলোডারে এমবেড করা libavb থাকে, তাহলে নিম্নলিখিত প্যাচগুলি অন্তর্ভুক্ত করুন:

চেইনড পার্টিশন ব্যবহার করলে, একটি অতিরিক্ত প্যাচ অন্তর্ভুক্ত করুন:

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: পার্টিশনের শুরুতে vbmeta ব্লব সমর্থন করা।"

কার্নেল কমান্ড লাইন পরিবর্তন

কার্নেল কমান্ড লাইনে androidboot.boot_devices নামে একটি নতুন প্যারামিটার যোগ করতে হবে। /dev/block/by-name সিমলিঙ্ক সক্রিয় করার জন্য init এটি ব্যবহার করে। এটি ueventd দ্বারা তৈরি অন্তর্নিহিত by-name সিমলিঙ্কের ডিভাইস পাথ অংশ হওয়া উচিত, অর্থাৎ, /dev/block/platform/ device-path /by-name/ partition-name । Android 12 বা তার পরবর্তী সংস্করণ দিয়ে চালু হওয়া ডিভাইসগুলোকে অবশ্যই bootconfig ব্যবহার করে initandroidboot.boot_devices পাস করতে হবে।

উদাহরণস্বরূপ, যদি সুপার পার্টিশনের বাই-নেম সিমলিঙ্কটি /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 ফ্ল্যাগ অন্তর্ভুক্ত থাকতে হবে, যা নির্দেশ করে যে একটি পার্টিশন প্রথম ধাপে মাউন্ট করা হবে।
  • একটি পার্টিশন fs_mgr ফ্ল্যাগ হিসেবে avb= vbmeta partition name নির্দিষ্ট করতে পারে এবং সেক্ষেত্রে যেকোনো ডিভাইস মাউন্ট করার চেষ্টার আগে প্রথম ধাপের init দ্বারা নির্দিষ্ট vbmeta পার্টিশনটি ইনিশিয়ালাইজ করা হয়।
  • 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 কীভাবে প্রয়োগ করতে হয় সে সম্পর্কে আরও তথ্যের জন্য, "Moving Fastboot to User Space" দেখুন।

adb রিমউন্ট

যেসব ডেভেলপার eng বা userdebug বিল্ড ব্যবহার করেন, তাদের জন্য দ্রুত পুনরাবৃত্তির জন্য adb remount অত্যন্ত দরকারি। ডাইনামিক পার্টিশনগুলো adb remount জন্য একটি সমস্যা তৈরি করে, কারণ প্রতিটি ফাইল সিস্টেমের মধ্যে আর কোনো খালি জায়গা থাকে না। এর সমাধান করতে, ডিভাইসগুলো overlayfs সক্রিয় করতে পারে। যতক্ষণ সুপার পার্টিশনের মধ্যে খালি জায়গা থাকে, adb remount স্বয়ংক্রিয়ভাবে একটি অস্থায়ী ডাইনামিক পার্টিশন তৈরি করে এবং লেখার জন্য overlayfs ব্যবহার করে। এই অস্থায়ী পার্টিশনটির নাম scratch রাখা হয়, তাই অন্য পার্টিশনের জন্য এই নামটি ব্যবহার করবেন না।

overlayfs কীভাবে সক্রিয় করতে হয় সে সম্পর্কে আরও তথ্যের জন্য, AOSP-তে থাকা overlayfs README দেখুন।

অ্যান্ড্রয়েড ডিভাইস আপগ্রেড করুন

আপনি যদি কোনো ডিভাইসকে অ্যান্ড্রয়েড ১০-এ আপগ্রেড করেন এবং OTA আপডেটের মাধ্যমে ডাইনামিক পার্টিশন সাপোর্ট অন্তর্ভুক্ত করতে চান, তাহলে বিল্ট-ইন পার্টিশন টেবিল পরিবর্তন করার প্রয়োজন নেই। এর জন্য কিছু অতিরিক্ত কনফিগারেশন প্রয়োজন হবে।

ডিভাইস কনফিগারেশন পরিবর্তন

ডাইনামিক পার্টিশনিং রেট্রোফিট করতে, device.mk ফাইলে নিম্নলিখিত ফ্ল্যাগগুলি যোগ করুন:

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

বোর্ড কনফিগারেশন পরিবর্তন

আপনাকে নিম্নলিখিত বোর্ড ভেরিয়েবলগুলো সেট করতে হবে:

  • ডাইনামিক পার্টিশনের এক্সটেন্টগুলো সংরক্ষণ করতে ব্যবহৃত ব্লক ডিভাইসগুলোর তালিকায় BOARD_SUPER_PARTITION_BLOCK_DEVICES সেট করুন। এটি হলো ডিভাইসটিতে বিদ্যমান ফিজিক্যাল পার্টিশনগুলোর নামের তালিকা।
  • BOARD_SUPER_PARTITION_BLOCK_DEVICES এ থাকা প্রতিটি ব্লক ডিভাইসের সাইজ অনুযায়ী BOARD_SUPER_PARTITION_ partition _DEVICE_SIZE সেট করুন। এটি হলো ডিভাইসে বিদ্যমান ফিজিক্যাল পার্টিশনগুলোর সাইজের তালিকা। বিদ্যমান বোর্ড কনফিগারেশনে এটি সাধারণত BOARD_ partition IMAGE_PARTITION_SIZE হয়ে থাকে।
  • BOARD_SUPER_PARTITION_BLOCK_DEVICES এর অন্তর্ভুক্ত সমস্ত পার্টিশনের জন্য বিদ্যমান BOARD_ partition IMAGE_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 দেখুন।

কারখানার ছবি

ডাইনামিক পার্টিশন সাপোর্টসহ লঞ্চ হওয়া ডিভাইসের ক্ষেত্রে ফ্যাক্টরি ইমেজ ফ্ল্যাশ করতে ইউজারস্পেস ফাস্টবুট ব্যবহার করা এড়িয়ে চলুন, কারণ ইউজারস্পেসে বুট করা অন্যান্য ফ্ল্যাশিং পদ্ধতির চেয়ে ধীরগতির।

এই সমস্যার সমাধান করতে, make dist এখন একটি অতিরিক্ত super.img ইমেজ তৈরি করে যা সরাসরি সুপার পার্টিশনে ফ্ল্যাশ করা যায়। এটি স্বয়ংক্রিয়ভাবে লজিক্যাল পার্টিশনগুলোর বিষয়বস্তু একত্রিত করে, অর্থাৎ super পার্টিশনের মেটাডেটার পাশাপাশি এতে system.img , vendor.img ইত্যাদি থাকে। এই ইমেজটি কোনো অতিরিক্ত টুলিং বা `fastbootd` ব্যবহার ছাড়াই সরাসরি super পার্টিশনে ফ্ল্যাশ করা যায়। বিল্ডের পরে, super.img ফাইলটি ${ANDROID_PRODUCT_OUT} ফোল্ডারে রাখা হয়।

যেসব A/B ডিভাইস ডাইনামিক পার্টিশন সহ চালু হয়, সেগুলোর A স্লটের ইমেজ super.img ফাইলে থাকে। সরাসরি super ইমেজ ফ্ল্যাশ করার পর, ডিভাইসটি রিবুট করার আগে A স্লটকে বুটেবল হিসেবে চিহ্নিত করুন।

রেট্রোফিট ডিভাইসগুলির জন্য, make dist এক সেট ` super_*.img ইমেজ তৈরি করে যা সরাসরি সংশ্লিষ্ট ফিজিক্যাল পার্টিশনগুলিতে ফ্ল্যাশ করা যায়। উদাহরণস্বরূপ, যখন BOARD_SUPER_PARTITION_BLOCK_DEVICES সিস্টেম ভেন্ডর হয়, তখন make dist super_system.img এবং super_vendor.img তৈরি করে। এই ইমেজগুলি target_files.zip ফাইলের `OTA` ফোল্ডারে রাখা হয়।

ডিভাইস ম্যাপার স্টোরেজ-ডিভাইস টিউনিং

ডাইনামিক পার্টিশনিং বেশ কিছু অনির্দিষ্ট ডিভাইস-ম্যাপার অবজেক্টকে সমর্থন করে। এগুলোর সবগুলো প্রত্যাশা অনুযায়ী ইনস্ট্যানশিয়েট নাও হতে পারে, তাই আপনাকে অবশ্যই সমস্ত মাউন্ট ট্র্যাক করতে হবে এবং সংশ্লিষ্ট সমস্ত পার্টিশনের অ্যান্ড্রয়েড প্রোপার্টিগুলোকে তাদের অন্তর্নিহিত স্টোরেজ ডিভাইস দিয়ে আপডেট করতে হবে।

init ভেতরের একটি মেকানিজম মাউন্টগুলোকে ট্র্যাক করে এবং অ্যাসিঙ্ক্রোনাসভাবে অ্যান্ড্রয়েড প্রপার্টিগুলো আপডেট করে। এই কাজটি সম্পন্ন হতে যে সময় লাগে, তা একটি নির্দিষ্ট সময়ের মধ্যে থাকবে এমন কোনো নিশ্চয়তা নেই, তাই সমস্ত 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 ল্যাঙ্গুয়েজটি রুলসের অংশ হিসেবে অ্যান্ড্রয়েড প্রোপার্টিগুলোকে সম্প্রসারিত করার সুযোগ দেয়, এবং এই ধরনের কমান্ডের মাধ্যমে প্রয়োজন অনুযায়ী প্ল্যাটফর্ম দ্বারা স্টোরেজ ডিভাইসগুলোকে টিউন করা যায়:

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}