Triển khai các phân vùng động

Phân vùng động được triển khai bằng mô-đun dm-linear device-mapper trong nhân Linux. Phân vùng super chứa siêu dữ liệu liệt kê tên và dải khối của từng phân vùng động trong super. Trong giai đoạn đầu tiên init, siêu dữ liệu này sẽ được phân tích cú pháp và xác thực, đồng thời các thiết bị khối ảo sẽ được tạo để biểu thị từng phân vùng động.

Khi áp dụng OTA, các phân vùng động sẽ tự động được tạo, đổi kích thước hoặc xoá khi cần. Đối với các thiết bị A/B, có 2 bản sao siêu dữ liệu và các thay đổi chỉ được áp dụng cho bản sao đại diện cho khe mục tiêu.

Vì các phân vùng động được triển khai trong không gian người dùng, nên các phân vùng mà trình tải khởi động cần không thể được tạo động. Ví dụ: boot, dtbovbmeta được trình tải khởi động đọc, vì vậy phải vẫn là các phân vùng thực.

Mỗi phân vùng động có thể thuộc về một nhóm cập nhật. Các nhóm này giới hạn dung lượng tối đa mà các phân vùng trong nhóm đó có thể sử dụng. Ví dụ: systemvendor có thể thuộc một nhóm hạn chế tổng kích thước của systemvendor.

Triển khai các phân vùng động trên thiết bị mới

Phần này trình bày chi tiết cách triển khai phân vùng động trên các thiết bị mới ra mắt chạy Android 10 trở lên. Để cập nhật các thiết bị hiện có, hãy xem phần Nâng cấp thiết bị Android.

Thay đổi về phân vùng

Đối với các thiết bị chạy Android 10, hãy tạo một phân vùng có tên là super. Phân vùng super xử lý các ngăn A/B nội bộ, vì vậy các thiết bị A/B không cần các phân vùng super_asuper_b riêng biệt. Tất cả các phân vùng AOSP chỉ đọc mà trình tải khởi động không sử dụng đều phải là phân vùng động và phải được xoá khỏi Bảng phân vùng GUID (GPT). Các phân vùng dành riêng cho nhà cung cấp không nhất thiết phải là phân vùng động và có thể được đặt trong GPT.

Để ước tính kích thước của super, hãy cộng kích thước của các phân vùng bị xoá khỏi GPT. Đối với các thiết bị A/B, điều này phải bao gồm kích thước của cả hai ngăn. Hình 1 cho thấy bảng phân vùng mẫu trước và sau khi chuyển đổi sang phân vùng động.

Bố cục bảng phân vùng
Hình 1. Bố cục bảng phân vùng thực mới khi chuyển đổi sang phân vùng động

Các phân vùng động được hỗ trợ là:

  • Hệ thống
  • Nhà cung cấp
  • Sản phẩm
  • System Ext
  • ODM

Đối với các thiết bị khởi chạy bằng Android 10, lựa chọn dòng lệnh của nhân androidboot.super_partition phải trống để lệnh sysprop ro.boot.super_partition trống.

Căn chỉnh phân vùng

Mô-đun device-mapper có thể hoạt động kém hiệu quả hơn nếu phân vùng super không được căn chỉnh đúng cách. Phân vùng super PHẢI được căn chỉnh theo kích thước yêu cầu I/O tối thiểu do lớp khối xác định. Theo mặc định, hệ thống xây dựng (thông qua lpmake, tạo ra hình ảnh phân vùng super) giả định rằng mức căn chỉnh 1 MiB là đủ cho mọi phân vùng động. Tuy nhiên, các nhà cung cấp phải đảm bảo rằng phân vùng super được căn chỉnh đúng cách.

Bạn có thể xác định kích thước yêu cầu tối thiểu của một thiết bị khối bằng cách kiểm tra sysfs. Ví dụ:

# 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

Bạn có thể xác minh cách căn chỉnh của phân vùng super theo cách tương tự:

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

Khoảng bù căn chỉnh PHẢI là 0.

Thay đổi cấu hình thiết bị

Để bật tính năng phân vùng động, hãy thêm cờ sau vào device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true

Thay đổi về cấu hình của Board

Bạn phải đặt kích thước cho phân vùng super:

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

Trên các thiết bị A/B, hệ thống bản dựng sẽ báo lỗi nếu tổng kích thước của hình ảnh phân vùng động lớn hơn một nửa kích thước phân vùng super.

Bạn có thể định cấu hình danh sách các phân vùng động như sau. Đối với các thiết bị sử dụng nhóm cập nhật, hãy liệt kê các nhóm trong biến BOARD_SUPER_PARTITION_GROUPS. Sau đó, mỗi tên nhóm sẽ có một biến BOARD_group_SIZEBOARD_group_PARTITION_LIST. Đối với các thiết bị A/B, kích thước tối đa của một nhóm chỉ được bao gồm một khe cắm, vì tên nhóm được gắn hậu tố khe cắm ở bên trong.

Sau đây là ví dụ về một thiết bị đặt tất cả các phân vùng vào một nhóm có tên là 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

Sau đây là ví dụ về một thiết bị đặt các dịch vụ hệ thống và sản phẩm vào group_foo, vendor, productodm vào 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
  • Đối với các thiết bị khởi chạy A/B ảo, tổng kích thước tối đa của tất cả các nhóm phải tối đa là:
    BOARD_SUPER_PARTITION_SIZE – overhead
    Xem phần Triển khai A/B ảo.
  • Đối với các thiết bị ra mắt A/B, tổng kích thước tối đa của tất cả các nhóm phải là:
    BOARD_SUPER_PARTITION_SIZE / 2 – overhead
  • Đối với các thiết bị không phải A/B và thiết bị A/B được trang bị thêm, tổng kích thước tối đa của tất cả các nhóm phải là:
    BOARD_SUPER_PARTITION_SIZE – overhead
  • Tại thời điểm tạo bản dựng, tổng kích thước của hình ảnh của mỗi phân vùng trong một nhóm cập nhật không được vượt quá kích thước tối đa của nhóm.
  • Chi phí chung là cần thiết trong quá trình tính toán để tính đến siêu dữ liệu, sự căn chỉnh, v.v. Mức hao tổn hợp lý là 4 MiB, nhưng bạn có thể chọn mức hao tổn lớn hơn nếu thiết bị cần.

Phân vùng động theo kích thước

Trước khi có các phân vùng động, kích thước phân vùng được phân bổ quá mức để đảm bảo rằng chúng có đủ dung lượng cho các bản cập nhật trong tương lai. Kích thước thực tế được lấy nguyên trạng và hầu hết các phân vùng chỉ đọc đều có một lượng dung lượng trống nhất định trong hệ thống tệp của chúng. Trong các phân vùng động, không gian trống đó không dùng được và có thể được dùng để tăng kích thước phân vùng trong quá trình cập nhật qua mạng (OTA). Điều quan trọng là phải đảm bảo rằng các phân vùng không lãng phí dung lượng và được phân bổ ở kích thước tối thiểu có thể.

Đối với hình ảnh ext4 chỉ đọc, hệ thống xây dựng sẽ tự động phân bổ kích thước tối thiểu nếu bạn không chỉ định kích thước phân vùng được mã hoá cứng. Hệ thống xây dựng sẽ điều chỉnh hình ảnh sao cho hệ thống tệp có ít dung lượng không dùng đến nhất có thể. Điều này đảm bảo rằng thiết bị không lãng phí dung lượng có thể dùng cho các bản cập nhật qua mạng.

Ngoài ra, bạn có thể nén thêm hình ảnh ext4 bằng cách bật tính năng loại bỏ dữ liệu trùng lặp ở cấp khối. Để bật tính năng này, hãy dùng cấu hình sau:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

Nếu bạn không muốn phân bổ tự động kích thước tối thiểu của phân vùng, thì có 2 cách để kiểm soát kích thước phân vùng. Bạn có thể chỉ định một lượng không gian trống tối thiểu bằng BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE hoặc bạn có thể chỉ định BOARD_partitionIMAGE_PARTITION_SIZE để buộc các phân vùng động có kích thước cụ thể. Bạn không nên sử dụng cả hai cách này, trừ phi cần thiết.

Ví dụ:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

Thao tác này buộc hệ thống tệp trong product.img phải có 50 MiB dung lượng chưa sử dụng.

Các thay đổi về hệ thống dưới dạng gốc

Các thiết bị ra mắt cùng với Android 10 không được sử dụng hệ thống dưới dạng gốc.

Các thiết bị có phân vùng động (cho dù thiết bị đó khởi chạy bằng phân vùng động hay trang bị thêm phân vùng động) đều không được sử dụng hệ thống dưới dạng gốc. Hạt nhân Linux không thể diễn giải phân vùng super và do đó không thể tự gắn system. system hiện được gắn bằng init giai đoạn đầu, nằm trong ramdisk.

Không đặt BOARD_BUILD_SYSTEM_ROOT_IMAGE. Trong Android 10, cờ BOARD_BUILD_SYSTEM_ROOT_IMAGE chỉ được dùng để phân biệt xem hệ thống được gắn kết bằng nhân hay bằng init giai đoạn đầu trong ramdisk.

Việc đặt BOARD_BUILD_SYSTEM_ROOT_IMAGE thành true sẽ gây ra lỗi bản dựng khi PRODUCT_USE_DYNAMIC_PARTITIONS cũng là true.

Khi BOARD_USES_RECOVERY_AS_BOOT được đặt thành true, hình ảnh khôi phục sẽ được tạo dưới dạng boot.img, chứa ổ đĩa RAM của quy trình khôi phục. Trước đây, trình tải khởi động đã dùng tham số dòng lệnh của nhân skip_initramfs để quyết định chế độ khởi động. Đối với các thiết bị Android 10, trình tải khởi động KHÔNG ĐƯỢC truyền skip_initramfs đến dòng lệnh của nhân. Thay vào đó, trình tải khởi động sẽ truyền androidboot.force_normal_boot=1 để bỏ qua chế độ khôi phục và khởi động Android bình thường. Những thiết bị khởi chạy bằng Android 12 trở lên phải sử dụng bootconfig để truyền androidboot.force_normal_boot=1.

Thay đổi về cấu hình AVB

Khi sử dụng Android Verified Boot 2.0, nếu thiết bị không sử dụng các bộ mô tả phân vùng được liên kết, thì bạn không cần thay đổi gì. Tuy nhiên, nếu sử dụng các phân vùng được liên kết và một trong các phân vùng được xác minh là động, thì bạn cần thực hiện các thay đổi.

Sau đây là ví dụ về cấu hình cho một thiết bị liên kết vbmeta cho các phân vùng systemvendor.

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

Với cấu hình này, trình tải khởi động dự kiến sẽ tìm thấy một chân trang vbmeta ở cuối các phân vùng systemvendor. Vì trình tải khởi động không còn nhìn thấy các phân vùng này (chúng nằm trong super), nên cần có 2 thay đổi.

  • Thêm các phân vùng vbmeta_systemvbmeta_vendor vào bảng phân vùng của thiết bị. Đối với các thiết bị A/B, hãy thêm vbmeta_system_a, vbmeta_system_b, vbmeta_vendor_avbmeta_vendor_b. Nếu bạn thêm một hoặc nhiều phân vùng trong số này, thì các phân vùng đó phải có cùng kích thước với phân vùng vbmeta.
  • Đổi tên cờ cấu hình bằng cách thêm VBMETA_ và chỉ định phân vùng mà chuỗi mở rộng đến:
    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

Một thiết bị có thể sử dụng một, cả hai hoặc không sử dụng phân vùng nào trong số này. Bạn chỉ cần thay đổi khi xâu chuỗi đến một phân vùng logic.

Các thay đổi đối với trình tải khởi động AVB

Nếu trình tải khởi động đã nhúng libavb, hãy thêm các bản vá sau:

Nếu sử dụng các phân vùng được liên kết, hãy thêm một bản vá bổ sung:

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: Support vbmeta blobs in beginning of partition." (libavb: Hỗ trợ các blob vbmeta ở đầu phân vùng.)

Thay đổi về dòng lệnh của kernel

Bạn phải thêm một tham số mới, androidboot.boot_devices, vào dòng lệnh của nhân. init dùng tính năng này để bật các đường liên kết tượng trưng /dev/block/by-name. Đây phải là thành phần đường dẫn thiết bị đến đường liên kết tượng trưng theo tên cơ bản do ueventd tạo, tức là /dev/block/platform/device-path/by-name/partition-name. Những thiết bị chạy Android 12 trở lên phải sử dụng bootconfig để truyền androidboot.boot_devices đến init.

Ví dụ: nếu siêu phân vùng theo tên symlink là /dev/block/platform/soc/100000.ufshc/by-name/super, bạn có thể thêm tham số dòng lệnh vào tệp BoardConfig.mk như sau:

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
Bạn có thể thêm tham số bootconfig vào tệp BoardConfig.mk như sau:
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

các thay đổi về fstab

Cây thiết bị và lớp phủ cây thiết bị không được chứa các mục fstab. Sử dụng tệp fstab sẽ nằm trong ramdisk.

Bạn phải thực hiện các thay đổi đối với tệp fstab cho các phân vùng logic:

  • Trường cờ fs_mgr phải có cờ logical và cờ first_stage_mount (ra mắt trong Android 10). Cờ này cho biết một phân vùng sẽ được gắn trong giai đoạn đầu tiên.
  • Một phân vùng có thể chỉ định avb=vbmeta partition name làm cờ fs_mgr, sau đó phân vùng vbmeta được chỉ định sẽ được khởi động bằng init giai đoạn đầu tiên trước khi cố gắng gắn bất kỳ thiết bị nào.
  • Trường dev phải là tên phân vùng.

Các mục fstab sau đây đặt hệ thống, nhà cung cấp và sản phẩm làm các phân vùng logic theo các quy tắc ở trên.

#<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

Sao chép tệp fstab vào ramdisk giai đoạn đầu tiên.

Thay đổi về SELinux

Thiết bị khối phân vùng siêu dữ liệu phải được đánh dấu bằng nhãn super_block_device. Ví dụ: nếu đường liên kết tượng trưng theo tên của phân vùng chính là /dev/block/platform/soc/100000.ufshc/by-name/super, hãy thêm dòng sau vào file_contexts:

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

fastbootd

Trình tải khởi động (hoặc bất kỳ công cụ nào không phải không gian người dùng để nhấp nháy) không hiểu các phân vùng động, vì vậy, trình tải khởi động không thể nhấp nháy các phân vùng đó. Để giải quyết vấn đề này, các thiết bị phải sử dụng một quy trình triển khai không gian người dùng của giao thức fastboot, được gọi là fastbootd.

Để biết thêm thông tin về cách triển khai fastbootd, hãy xem bài viết Chuyển Fastboot sang không gian người dùng.

adb remount

Đối với những nhà phát triển sử dụng bản dựng eng hoặc userdebug, adb remount cực kỳ hữu ích cho việc lặp lại nhanh. Phân vùng động gây ra vấn đề cho adb remount vì không còn dung lượng trống trong mỗi hệ thống tệp. Để giải quyết vấn đề này, các thiết bị có thể bật overlayfs. Miễn là phân vùng chính còn trống, adb remount sẽ tự động tạo một phân vùng động tạm thời và sử dụng overlayfs để ghi. Phân vùng tạm thời có tên là scratch, vì vậy, đừng dùng tên này cho các phân vùng khác.

Để biết thêm thông tin về cách bật overlayfs, hãy xem README của overlayfs trong AOSP.

Nâng cấp thiết bị Android

Nếu nâng cấp thiết bị lên Android 10 và muốn thêm tính năng hỗ trợ phân vùng động vào OTA, bạn không cần thay đổi bảng phân vùng tích hợp. Bạn cần phải thiết lập thêm một số thông tin.

Thay đổi cấu hình thiết bị

Để trang bị thêm tính năng phân vùng động, hãy thêm các cờ sau vào device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

Thay đổi về cấu hình của Board

Bạn phải đặt các biến bảng sau:

  • Đặt BOARD_SUPER_PARTITION_BLOCK_DEVICES thành danh sách các thiết bị chặn được dùng để lưu trữ các phạm vi của phân vùng động. Đây là danh sách tên của các phân vùng thực hiện có trên thiết bị.
  • Đặt BOARD_SUPER_PARTITION_partition_DEVICE_SIZE thành kích thước của từng thiết bị khối trong BOARD_SUPER_PARTITION_BLOCK_DEVICES, tương ứng. Đây là danh sách kích thước của các phân vùng thực hiện có trên thiết bị. Đây thường là BOARD_partitionIMAGE_PARTITION_SIZE trong các cấu hình bảng hiện có.
  • Huỷ đặt BOARD_partitionIMAGE_PARTITION_SIZE hiện có cho tất cả các phân vùng trong BOARD_SUPER_PARTITION_BLOCK_DEVICES.
  • Đặt BOARD_SUPER_PARTITION_SIZE thành tổng của BOARD_SUPER_PARTITION_partition_DEVICE_SIZE.
  • Đặt BOARD_SUPER_PARTITION_METADATA_DEVICE thành thiết bị khối nơi siêu dữ liệu phân vùng động được lưu trữ. Phải là một trong các giá trị BOARD_SUPER_PARTITION_BLOCK_DEVICES. Thông thường, giá trị này được đặt thành system.
  • Đặt lần lượt BOARD_SUPER_PARTITION_GROUPS, BOARD_group_SIZEBOARD_group_PARTITION_LIST. Hãy xem phần Các thay đổi về cấu hình bảng trên thiết bị mới để biết thông tin chi tiết.

Ví dụ: nếu thiết bị đã có các phân vùng hệ thống và nhà cung cấp, đồng thời bạn muốn chuyển đổi các phân vùng đó thành phân vùng động và thêm một phân vùng sản phẩm mới trong quá trình cập nhật, hãy thiết lập cấu hình bảng này:

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

Thay đổi về SELinux

Các thiết bị khối phân vùng chính phải được đánh dấu bằng thuộc tính super_block_device_type. Ví dụ: nếu thiết bị đã có các phân vùng systemvendor, bạn muốn sử dụng các phân vùng này làm thiết bị khối để lưu trữ các phạm vi của phân vùng động và các đường liên kết tượng trưng theo tên của chúng được đánh dấu là 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

Sau đó, hãy thêm dòng sau vào device.te:

typeattribute system_block_device super_block_device_type;

Đối với các cấu hình khác, hãy xem phần Triển khai các phân vùng động trên thiết bị mới.

Để biết thêm thông tin về bản cập nhật trang bị thêm, hãy xem phần OTA cho thiết bị A/B không có phân vùng động.

Hình ảnh gốc

Đối với thiết bị khởi chạy có hỗ trợ phân vùng động, hãy tránh sử dụng fastboot không gian người dùng để cài đặt ROM hình ảnh ban đầu, vì quá trình khởi động vào không gian người dùng chậm hơn các phương thức cài đặt ROM khác.

Để giải quyết vấn đề này, make dist hiện tạo thêm một hình ảnh super.img có thể được chuyển trực tiếp đến phân vùng siêu dữ liệu. Nó tự động kết hợp nội dung của các phân vùng logic, tức là chứa system.img, vendor.img, v.v., ngoài siêu dữ liệu phân vùng super. Bạn có thể nạp hình ảnh này trực tiếp vào phân vùng super mà không cần thêm công cụ hoặc sử dụng fastbootd. Sau khi tạo, super.img sẽ được đặt trong ${ANDROID_PRODUCT_OUT}.

Đối với các thiết bị A/B khởi động bằng phân vùng động, super.img chứa hình ảnh trong khe A. Sau khi nạp trực tiếp hình ảnh siêu dữ liệu, hãy đánh dấu khe A là có thể khởi động trước khi khởi động lại thiết bị.

Đối với các thiết bị trang bị thêm, make dist sẽ tạo một tập hợp hình ảnh super_*.img có thể được chuyển trực tiếp đến các phân vùng thực tương ứng. Ví dụ: make dist tạo super_system.imgsuper_vendor.img khi BOARD_SUPER_PARTITION_BLOCK_DEVICES là nhà cung cấp hệ thống. Các hình ảnh này được đặt trong thư mục OTA trong target_files.zip.

Điều chỉnh thiết bị lưu trữ bằng trình ánh xạ thiết bị

Phân vùng động có thể chứa một số đối tượng trình ánh xạ thiết bị không xác định. Những phân vùng này có thể không khởi tạo như mong đợi, vì vậy, bạn phải theo dõi tất cả các lượt gắn kết và cập nhật các thuộc tính Android của tất cả các phân vùng được liên kết bằng các thiết bị lưu trữ cơ bản của chúng.

Một cơ chế bên trong init sẽ theo dõi các thành phần và cập nhật các thuộc tính Android một cách không đồng bộ. Không có gì đảm bảo khoảng thời gian này sẽ nằm trong một khoảng thời gian cụ thể, vì vậy, bạn phải cung cấp đủ thời gian để tất cả các điều kiện kích hoạt on property phản ứng. Các thuộc tính là dev.mnt.blk.<partition>, trong đó <partition>root, system, data hoặc vendor, chẳng hạn. Mỗi thuộc tính được liên kết với tên thiết bị lưu trữ cơ bản, như minh hoạ trong các ví dụ sau:

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]

Ngôn ngữ init.rc cho phép các thuộc tính Android được mở rộng trong quy tắc và nền tảng có thể điều chỉnh các thiết bị lưu trữ khi cần bằng các lệnh như sau:

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

Sau khi quá trình xử lý lệnh bắt đầu ở giai đoạn thứ hai init, epoll loop sẽ hoạt động và các giá trị bắt đầu cập nhật. Tuy nhiên, vì các trình kích hoạt thuộc tính không hoạt động cho đến cuối init, nên chúng không thể được dùng trong các giai đoạn khởi động ban đầu để xử lý root, system hoặc vendor. Bạn có thể mong đợi read_ahead_kb mặc định của nhân là đủ cho đến khi các tập lệnh init.rc có thể ghi đè trong early-fs (khi nhiều trình nền và cơ sở bắt đầu). Do đó, bạn nên sử dụng tính năng on property, kết hợp với một thuộc tính do init.rc kiểm soát như sys.read_ahead_kb, để xử lý thời gian của các thao tác và ngăn chặn tình trạng xung đột, như trong các ví dụ sau:

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}