تنفيذ الأقسام الديناميكية

يتم تنفيذ التقسيم الديناميكي باستخدام وحدة dm-linear device-mapper في نواة Linux. يحتوي قسم super على بيانات وصفية تسرد أسماء نطاقات الكتل لكل قسم ديناميكي ضمن super. خلال المرحلة الأولى init، تتم معالجة هذه العناصر الوصفية والتحقّق منها، ويتم إنشاء أجهزة تخزين افتراضية بالكتل لتمثل كل قسم ديناميكي.

عند تطبيق تحديث OTA، يتم إنشاء الأقسام الديناميكية تلقائيًا أو تغيير حجمها أو حذفها حسب الحاجة. بالنسبة إلى الأجهزة التي تستخدم اختبار أ/ب، تتوفّر نسختان من البيانات الوصفية، ولا يتم تطبيق التغييرات إلا على النسخة التي تمثّل الخانة المستهدَفة.

بما أنّ الأقسام الديناميكية يتم تنفيذها في مساحة المستخدم، لا يمكن جعل الأقسام التي يحتاج إليها bootloader ديناميكية. على سبيل المثال، يقرأ برنامج الإقلاع boot وdtbo وvbmeta، وبالتالي يجب أن تبقى هذه الأقسام كأقسام فعلية.

يمكن أن ينتمي كل قسم ديناميكي إلى مجموعة تعديل. تضع هذه المجموعات حدًا أقصى للمساحة التي يمكن أن تستهلكها الأقسام في تلك المجموعة. على سبيل المثال، يمكن أن ينتمي system وvendor إلى مجموعة تحدّ من الحجم الإجمالي لهماsystem vendor.

تنفيذ التقسيمات الديناميكية على الأجهزة الجديدة

يوضّح هذا القسم بالتفصيل كيفية تنفيذ الأقسام الديناميكية على الأجهزة الجديدة التي تعمل بالإصدار 10 من نظام التشغيل Android والإصدارات الأحدث. لتحديث الأجهزة الحالية، راجِع ترقية أجهزة Android.

تغييرات التقسيم

بالنسبة إلى الأجهزة التي تعمل بنظام التشغيل Android 10، أنشئ قسمًا باسم super. يعالج القسم super خانات A/B داخليًا، لذلك لا تحتاج أجهزة A/B إلى أقسام super_a وsuper_b منفصلة. يجب أن تكون جميع أقسام AOSP للقراءة فقط التي لا يستخدمها مشغّل الإقلاع ديناميكية ويجب إزالتها من جدول تقسيم GUID (GPT). لا يجب أن تكون الأقسام الخاصة بالمورّد ديناميكية، ويمكن وضعها في GPT.

لتقدير حجم super، أضِف أحجام ال partitions التي يتم حذفها من GPT. بالنسبة إلى الأجهزة التي تتضمّن علامتَي A/B، يجب أن يشمل ذلك حجم كلتا الفتحتَين. يعرض الشكل 1 مثالاً على جدول أقسام قبل وبعد تحويله إلى أقسام ديناميكية.

تنسيق جدول الأقسام
الشكل 1. تنسيق جديد لجدول التقسيم الأساسي عند التحويل إلى أقسام ديناميكية

التقسيمات الديناميكية المتوافقة هي:

  • النظام
  • المورّد
  • المنتَج
  • ملحقات النظام
  • ODM

بالنسبة إلى الأجهزة التي تعمل بنظام التشغيل Android 10، يجب أن يكون خيار سطر الأوامر لنظام التشغيل androidboot.super_partition فارغًا حتى يكون الأمر sysprop ro.boot.super_partition فارغًا.

محاذاة الأقسام

قد تعمل وحدة "محاكي الجهاز" بكفاءة أقل في حال عدم محاذاة القسم super بشكل صحيح. يجب محاذاة قسم super مع الحد الأدنى لحجم طلب الإدخال/الإخراج كما هو محدد في طبقة الحظر. يفترض نظام الإنشاء (من خلال lpmake الذي ينشئ super صورة القسم) تلقائيًا أنّ محاذاة 1 ميغابايت كافية لكل قسم ديناميكي. وفي المقابل، على المورّدين التأكّد من توافق قسم 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
  • بالنسبة إلى أجهزة إطلاق ميزة "التجربة المتوفّرة على الأجهزة الافتراضية"، يجب ألا يتجاوز مجموع الحد الأقصى لحجم كل المجموعات:
    BOARD_SUPER_PARTITION_SIZE - الحد الأقصى لحجم المساحة المتوفّرة
    راجِع مقالة تنفيذ ميزة "التجربة المتوفّرة على الأجهزة الافتراضية".
  • بالنسبة إلى أجهزة إطلاق اختبار أ/ب، يجب أن يكون مجموع الحد الأقصى لحجم جميع المجموعات هو:
    BOARD_SUPER_PARTITION_SIZE / 2 - النفقات العامة
  • بالنسبة إلى الأجهزة غير المزوّدة بميزة A/B والأجهزة المزوّدة بميزة A/B التي تم تركيبها لاحقًا، يجب أن يكون مجموع الحد الأقصى لحجم جميع المجموعات على النحو التالي:
    BOARD_SUPER_PARTITION_SIZE - النفقات العامة
  • في وقت الإنشاء، يجب ألا يتجاوز مجموع أحجام صور كل قسم في مجموعة التحديث الحد الأقصى لحجم المجموعة.
  • يجب تضمين الوقت المستغرَق في العمليات غير الأساسية في عملية الحساب لمراعاة البيانات الوصفية، والمواضع، وما إلى ذلك. إنّ الحدّ الأدنى المعقول للمساحة المخصّصة للعمليات غير الأساسية هو 4 ميغابايت، ولكن يمكنك اختيار مساحة أكبر حسب الحاجة.

حجم الأقسام الديناميكية

قبل استخدام الأقسام الديناميكية، كان يتم تخصيص أحجام الأقسام بشكل زائد لضمان توفُّر مساحة كافية لإجراء التحديثات المستقبلية. تم أخذ الحجم الفعلي كما هو، وكان لدى معظم الأقسام المخصّصة للقراءة فقط قدر من المساحة الفارغة في نظام الملفات. في الأقسام الديناميكية، تكون هذه المساحة الفارغة غير قابلة للاستخدام ويمكن استخدامها لتوسيع الأقسام أثناء عملية تحديث البرامج من خلال الهواء. من المهم التأكّد من أنّ الأقسام لا تهدر مساحة وأن يتم تخصيصها إلى أدنى حجم ممكن.

بالنسبة إلى صور ext4 للقراءة فقط، يخصّص نظام الإصدار تلقائيًا الحد الأدنى للحجم في حال عدم تحديد حجم قسم ثابت. يُعدّ نظام الإنشاء الصورة بحيث لا يتضمّن نظام الملفات سوى أقل مساحة غير مستخدَمة ممكنة. ويضمن ذلك عدم إهدار الجهاز للمساحة التي يمكن استخدامها لتحديثات البرامج التلقائية.

بالإضافة إلى ذلك، يمكن ضغط صور ext4 بشكل أكبر من خلال تفعيل ميزة إزالة تكرار المحتوى على مستوى الوحدات. لتفعيل هذا الخيار، استخدِم الإعدادات التالية:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

إذا لم تكن عملية تخصيص الحد الأدنى لحجم القسم تلقائية، هناك طريقتان للتحكّم في حجم القسم. يمكنك تحديد الحد الأدنى للمساحة الفارغة باستخدام BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE، أو يمكنك تحديد BOARD_partitionIMAGE_PARTITION_SIZE لفرض حجم معيّن على الأقسام الديناميكية. لا يُنصح باستخدام أي من هذين الخيارَين إلا عند الضرورة.

مثلاً:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

يؤدي ذلك إلى فرض مساحة غير مستخدَمة تبلغ 50 ميغابايت على نظام الملفات في product.img.

التغييرات في وضع "النظام بصفتها الجذر"

يجب ألا تستخدم الأجهزة التي تعمل بالإصدار 10 من نظام التشغيل Android إذن الوصول إلى الجذر.

يجب ألا تستخدم الأجهزة التي تتضمّن أقسامًا ديناميكية (سواء كانت تعمل باستخدام أقسام ديناميكية أو تم تركيبها بعد بدء التشغيل) ميزة "النظام بصفتها الجذر". لا يمكن لنظام التشغيل Linux تفسير قسم super، وبالتالي لا يمكنه تركيب system نفسه. يتم الآن تثبيت system من خلال المرحلة الأولى من نظام التشغيل init، والتي يتم وضعها في الهرم.

لا تضبط BOARD_BUILD_SYSTEM_ROOT_IMAGE. في الإصدار 10 من Android، لا تُستخدَم العلامة BOARD_BUILD_SYSTEM_ROOT_IMAGE إلا للتفريق بين ما إذا كان النظام قد تم تثبيته بواسطة النواة أو المرحلة الأولى من init في ذاكرة التخزين المؤقت.

يؤدي ضبط BOARD_BUILD_SYSTEM_ROOT_IMAGE على true إلى حدوث خطأ في الإصدار عندما يكون PRODUCT_USE_DYNAMIC_PARTITIONS هو true أيضًا.

عند ضبط BOARD_USES_RECOVERY_AS_BOOT على true، يتم إنشاء صورة الاسترداد كملف boot.img يحتوي على ملف ramdisk الخاص بعملية الاسترداد. في السابق، كان برنامج الإقلاع يستخدم مَعلمة سطر الأوامر kernel skip_initramfs لتحديد الوضع الذي تريد بدء تشغيله. بالنسبة إلى أجهزة Android 10، يجب ألا ينقل مشغّل الإقلاع skip_initramfs إلى سطر أوامر النواة. بدلاً من ذلك، يجب أن يمر bootloader باختبار androidboot.force_normal_boot=1 لتخطّي وضع الاسترداد وتشغيل نظام Android العادي. يجب أن تستخدم الأجهزة التي تعمل بالإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث bootconfig لاجتياز androidboot.force_normal_boot=1.

تغييرات إعدادات AVB

عند استخدام الإصدار 2.0 من Android تم التحقق منه، لا يلزم إجراء أي تغيير إذا كان الجهاز لا يستخدم أدوات وصف الأقسام المتسلسلة. في حال استخدام أقسام متسلسلة وكان أحد الأقسام التي تم إثبات ملكيتها ديناميكيًا، تكون التغييرات ضرورية.

في ما يلي مثال على الإعداد لجهاز يربط vbmeta للقسمَين system و vendor.

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

باستخدام هذا الإعداد، يتوقّع مشغّل الإقلاع العثور على vbmeta تذييل في نهاية قسمَي system و vendor. بما أنّ هذه الأقسام لم تعُد مرئية لبرنامج التمهيد (فهي موجودة في 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 blobs في بداية التقسيم".

التغييرات على سطر أوامر النواة

يجب إضافة مَعلمة جديدة، androidboot.boot_devices، إلى سطر أوامر kernel. يستخدم init هذا الاختصار لتفعيل الروابط الرمزية /dev/block/by-name. يجب أن يكون مكوّن مسار الجهاز إلى الرابط الرمزي الأساسي بالاسم الذي أنشأه ueventd، أي /dev/block/platform/device-path/by-name/partition-name. يجب أن تستخدم الأجهزة التي تعمل بالإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث bootconfig لتمرير androidboot.boot_devices إلى init.

على سبيل المثال، إذا كان الرابط الرمزي للقسم الفائق بالاسم هو /dev/block/platform/soc/100000.ufshc/by-name/super، يمكنك إضافة مَعلمة سطر الأوامر في ملف BoardConfig.mk على النحو التالي:

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
يمكنك إضافة مَعلمة bootconfig في ملف BoardConfig.mk على النحو التالي:
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

تغييرات fstab

يجب ألا تحتوي شجرة الجهاز وطبقات شجرة الجهاز على إدخالات fstab. استخدم ملف fstab الذي سيكون جزءًا من ramdisk.

يجب إجراء التغييرات على ملف fstab للأقسام المنطقية:

  • ويجب أن يشتمل حقل العلامات fs_mgr على العلامة logical وعلامة 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 إلى ذاكرة الوصول العشوائي (RAM) في المرحلة الأولى.

تغييرات 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

لا يفهم مشغّل الإقلاع (أو أي أداة فلاش غير مخصّصة لمساحة المستخدم) الأقسام الديناميكية، لذا لا يمكنه فلاشها. لحلّ هذه المشكلة، يجب أن تستخدم الأجهزة تنفيذًا لبروتوكول fastboot في مساحة المستخدم يُسمى fastbootd.

لمزيد من المعلومات عن كيفية تنفيذ fastbootd، يُرجى الاطّلاع على مقالة نقل Fastboot إلى مساحة المستخدم.

adb remount

بالنسبة إلى المطوّرين الذين يستخدمون إصدارات eng أو userdebug، يكون adb remount مفيدًا للغاية لإجراء عمليات تكرار سريعة. تشكل الأقسام الديناميكية مشكلة لجهاز adb remount لأنّه لم تعُد هناك مساحة فارغة في كل نظام ملفات. لحلّ هذه المشكلة، يمكن للأجهزة تفعيل overlayfs. ما دامت هناك مساحة خالية في القسم الفائق، adb remount ينشئ تلقائيًا قسمًا مؤقتًا ديناميكيًا ويستخدم overlayfs للعمليات الكتابية. يتم تسمية القسم المؤقت باسم scratch، لذا لا تستخدِم هذا الاسم للأقسام الأخرى.

لمزيد من المعلومات حول كيفية تفعيل overlayfs، يُرجى الاطّلاع على overlayfs README في AOSP.

ترقية أجهزة 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_partitionIMAGE_PARTITION_SIZE الحالية لجميع الأقسام في BOARD_SUPER_PARTITION_BLOCK_DEVICES.
  • اضبط 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 التي لا تحتوي على أقسام ديناميكية.

صور المصنع

في حال تشغيل جهاز متوافق مع الأقسام الديناميكية، تجنَّب استخدام userspace Fastboot لتثقيف الصور الأصلية، لأنّ التشغيل على مساحة المستخدم أبطأ من الطرق الأخرى الوامضة.

لحلّ هذه المشكلة، ينشئ make dist الآن صورة super.img إضافية يمكن إرفاقها مباشرةً في القسم الفائق. ويجمع القسم تلقائيًا محتويات القسمين المنطقيَين، ما يعني أنّه يحتوي على system.img vendor.img وما إلى ذلك، بالإضافة إلى البيانات الوصفية للقسم super. يمكن إعادة تحميل هذه الصورة مباشرةً على القسم super بدون أي أدوات إضافية أو باستخدام fastbootd. بعد الإنشاء، يتم وضع super.img في ${ANDROID_PRODUCT_OUT}.

بالنسبة إلى أجهزة A/B التي يتم تشغيلها باستخدام أقسام ديناميكية، super.img يحتوي على صور في خانة A. بعد فلاش الصورة الفائقة مباشرةً، ضَع علامة على الفتحة "أ" كمكان قابل للتشغيل قبل إعادة تشغيل الجهاز.

بالنسبة إلى الأجهزة التي تم تركيبها لاحقًا، ينشئ make dist مجموعة من super_*.img الصور التي يمكن إعادة تحميلها مباشرةً إلى الأقسام المادية المقابلة. على سبيل المثال، make dist ينشئ super_system.img وsuper_vendor.img عندما يكون BOARD_SUPER_PARTITION_BLOCK_DEVICES هو مورِّد النظام. يتم وضع هذه الصور في مجلد OTA في target_files.zip.

ضبط مساحة تخزين جهاز "أداة ربط الأجهزة"

تتيح عملية التقسيم الديناميكي استخدام عدد من عناصر أداة ربط الأجهزة غير الحتمية. قد لا يتم إنشاء جميع هذه العناصر على النحو المتوقّع، لذا عليك تتبُّع جميع عمليات التثبيت وتعديل سمات 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 في kernel كافيًا إلى أن يتم استبداله من خلال النصوص البرمجية 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}