Triển khai A/B ảo

Để triển khai A/B ảo trên một thiết bị mới hoặc trang bị thêm cho một thiết bị đã ra mắt, bạn phải thực hiện các thay đổi đối với mã dành riêng cho thiết bị.

Xây dựng cờ

Các thiết bị sử dụng A/B ảo phải được định cấu hình là thiết bị A/B và phải khởi chạy bằng phân vùng động .

Đối với các thiết bị khởi chạy bằng A/B ảo, hãy đặt chúng kế thừa cấu hình cơ sở của thiết bị A/B ảo:

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

Các thiết bị khởi chạy với A/B ảo chỉ cần một nửa kích thước bảng cho BOARD_SUPER_PARTITION_SIZE vì các khe B không còn ở dạng siêu. Nghĩa là, BOARD_SUPER_PARTITION_SIZE phải lớn hơn hoặc bằng sum(size of updategroups) + overhead , do đó, phải lớn hơn hoặc bằng sum(size of phân vùng) + overhead .

Đối với Android 13 trở lên, để bật ảnh chụp nhanh được nén bằng Virtual A/B, hãy kế thừa cấu hình cơ bản sau:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/android_t_baseline.mk)

Điều này cho phép chụp nhanh không gian người dùng bằng Virtual A/B trong khi sử dụng phương pháp nén không hoạt động. Sau đó, bạn có thể định cấu hình phương thức nén thành một trong các phương thức được hỗ trợ, gz , zstdlz4 .

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

Đối với Android 12, để bật ảnh chụp nhanh được nén bằng Virtual A/B, hãy kế thừa cấu hình cơ bản sau:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

nén XOR

Đối với các thiết bị nâng cấp lên Android 13 trở lên, tính năng nén XOR không được bật theo mặc định. Để bật tính năng nén XOR, hãy thêm phần sau vào tệp .mk của thiết bị.

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

Tính năng nén XOR được bật theo mặc định cho các thiết bị kế thừa từ android_t_baseline.mk .

Hợp nhất không gian người dùng

Đối với các thiết bị nâng cấp lên Android 13 trở lên, quy trình hợp nhất không gian người dùng như được mô tả trong Phân lớp trình ánh xạ thiết bị không được bật theo mặc định. Để bật hợp nhất vùng người dùng, hãy thêm dòng sau vào tệp .mk của thiết bị:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

Hợp nhất không gian người dùng được bật theo mặc định trên các thiết bị chạy phiên bản 13 trở lên.

Kiểm soát khởi động HAL

Kiểm soát khởi động HAL cung cấp giao diện cho các máy khách OTA để kiểm soát các khe khởi động. A/B ảo yêu cầu nâng cấp phiên bản nhỏ của HAL kiểm soát khởi động vì cần có các API bổ sung để đảm bảo bộ nạp khởi động được bảo vệ trong quá trình flash/khôi phục cài đặt gốc. Xem IBootControl.haltype.hal để biết phiên bản mới nhất của định nghĩa HAL.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

thay đổi Fstab

Tính toàn vẹn của phân vùng siêu dữ liệu là điều cần thiết cho quá trình khởi động, đặc biệt là ngay sau khi áp dụng bản cập nhật OTA. Vì vậy, phân vùng siêu dữ liệu phải được kiểm tra trước khi first_stage_init gắn kết nó. Để đảm bảo điều này xảy ra, hãy thêm cờ check fs_mgr vào mục nhập /metadata . Sau đây cung cấp một ví dụ:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

Yêu cầu hạt nhân

Để bật tính năng chụp nhanh, hãy đặt CONFIG_DM_SNAPSHOT thành true .

Đối với các thiết bị sử dụng F2FS, hãy bao gồm cờ f2fs: xuất FS_NOCOW_FL sang bản vá kernel của người dùng để sửa lỗi ghim tệp. Bao gồm f2fs: cũng hỗ trợ bản vá hạt nhân tệp được ghim được căn chỉnh .

A/B ảo dựa vào các tính năng được thêm vào trong kernel phiên bản 4.3: bit trạng thái tràn trong mục tiêu snapshotsnapshot-merge . Tất cả các thiết bị chạy Android 9 trở lên đều phải có phiên bản kernel 4.4 trở lên.

Để bật ảnh chụp nhanh nén, phiên bản kernel được hỗ trợ tối thiểu là 4.19. Đặt CONFIG_DM_USER=m hoặc CONFIG_DM_USER=y . Nếu sử dụng mô-đun trước đây (một mô-đun), mô-đun phải được tải vào đĩa RAM giai đoạn đầu. Điều này có thể đạt được bằng cách thêm dòng sau vào Makefile của thiết bị:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Trang bị thêm trên các thiết bị nâng cấp lên Android 11

Khi nâng cấp lên Android 11, các thiết bị khởi chạy với phân vùng động có thể tùy chọn trang bị thêm A/B ảo. Quá trình cập nhật hầu hết giống như đối với các thiết bị khởi chạy bằng A/B ảo, với một số khác biệt nhỏ:

  • Vị trí của tệp COW - Đối với các thiết bị khởi chạy, máy khách OTA sử dụng tất cả không gian trống có sẵn trong siêu phân vùng trước khi sử dụng không gian trong /data . Đối với các thiết bị trang bị thêm, siêu phân vùng luôn có đủ dung lượng để tệp COW không bao giờ được tạo trên /data .

  • Cờ tính năng tại thời điểm xây dựng — Đối với các thiết bị trang bị thêm A/B ảo, cả PRODUCT_VIRTUAL_AB_OTAPRODUCT_VIRTUAL_AB_OTA_RETROFIT đều được đặt thành true , như hiển thị bên dưới:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Kích thước siêu phân vùng — Các thiết bị khởi chạy bằng A/B ảo có thể cắt BOARD_SUPER_PARTITION_SIZE làm đôi vì các khe B không có trong siêu phân vùng. Các thiết bị trang bị thêm A/B ảo giữ nguyên kích thước siêu phân vùng cũ nên BOARD_SUPER_PARTITION_SIZE lớn hơn hoặc bằng 2 * sum(kích thước của nhóm cập nhật) + overhead , lần lượt lớn hơn hoặc bằng 2 * sum(kích thước của phân vùng) + trên cao .

Thay đổi bộ nạp khởi động

Trong bước hợp nhất của bản cập nhật, /data giữ toàn bộ phiên bản duy nhất của hệ điều hành Android. Sau khi quá trình di chuyển bắt đầu, các phân vùng system gốc, vendorproduct sẽ không hoàn chỉnh cho đến khi quá trình sao chép kết thúc. Nếu thiết bị được khôi phục cài đặt gốc trong quá trình này, bằng cách khôi phục hoặc thông qua hộp thoại Cài đặt hệ thống thì thiết bị sẽ không thể khởi động được.

Trước khi xóa /data , hãy hoàn tất việc hợp nhất trong recovery hoặc rollback tùy thuộc vào trạng thái thiết bị:

  • Nếu bản dựng mới đã khởi động thành công trước đó, hãy hoàn tất quá trình di chuyển.
  • Nếu không, hãy quay lại vị trí cũ:
    • Đối với phân vùng động, quay lại trạng thái trước đó.
    • Đối với các phân vùng tĩnh, đặt vị trí hoạt động thành vị trí cũ.

Cả bootloader và fastbootd đều có thể xóa phân vùng /data nếu thiết bị được mở khóa. Mặc dù fastbootd có thể buộc quá trình di chuyển hoàn tất nhưng bộ nạp khởi động lại không thể. Bộ tải khởi động không biết liệu quá trình hợp nhất có đang diễn ra hay không hoặc khối nào trong /data cấu thành các phân vùng hệ điều hành. Thiết bị phải ngăn người dùng vô tình làm cho thiết bị không thể hoạt động (gạch) bằng cách thực hiện như sau:

  1. Triển khai điều khiển khởi động HAL để bộ nạp khởi động có thể đọc giá trị được đặt theo phương thức setSnapshotMergeStatus() .
  2. Nếu trạng thái hợp nhất là MERGING hoặc nếu trạng thái hợp nhất là SNAPSHOTTED và vị trí đã thay đổi thành vị trí mới được cập nhật thì yêu cầu xóa userdata , metadata hoặc phân vùng lưu trữ trạng thái hợp nhất phải bị từ chối trong bộ tải khởi động.
  3. Thực hiện lệnh fastboot snapshot-update cancel để người dùng có thể báo hiệu cho bootloader rằng họ muốn bỏ qua cơ chế bảo vệ này.
  4. Sửa đổi các công cụ hoặc tập lệnh flash tùy chỉnh để fastboot snapshot-update cancel khi flash toàn bộ thiết bị. Vấn đề này an toàn vì việc flash toàn bộ thiết bị sẽ loại bỏ OTA. Công cụ có thể phát hiện lệnh này trong thời gian chạy bằng cách triển khai fastboot getvar snapshot-update-status . Lệnh này giúp phân biệt giữa các điều kiện lỗi.

Ví dụ

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Thay đổi công cụ Fastboot

Android 11 thực hiện những thay đổi sau đối với giao thức fastboot:

  • getvar snapshot-update-status - Trả về giá trị mà điều khiển khởi động HAL đã truyền cho bộ nạp khởi động:
    • Nếu trạng thái là MERGING , bộ nạp khởi động phải trả về merging .
    • Nếu trạng thái là SNAPSHOTTED , bộ nạp khởi động phải trả về snapshotted .
    • Nếu không, bộ nạp khởi động phải trả về none .
  • snapshot-update merge - Hoàn thành thao tác hợp nhất, khởi động vào recovery/fastbootd nếu cần. Lệnh này chỉ hợp lệ nếu snapshot-update-status đang merging và chỉ được hỗ trợ trong fastbootd.
  • snapshot-update cancel — Đặt trạng thái hợp nhất của HAL điều khiển khởi động thành CANCELLED . Lệnh này không hợp lệ khi thiết bị bị khóa.
  • erase hoặc wipe — Việc erase hoặc wipe metadata , userdata hoặc phân vùng giữ trạng thái hợp nhất cho điều khiển khởi động HAL sẽ kiểm tra trạng thái hợp nhất ảnh chụp nhanh. Nếu trạng thái là MERGING hoặc SNAPSHOTTED , thiết bị sẽ hủy thao tác.
  • set_active - Lệnh set_active thay đổi vị trí hoạt động sẽ kiểm tra trạng thái hợp nhất ảnh chụp nhanh. Nếu trạng thái là MERGING , thiết bị sẽ hủy thao tác. Khe cắm có thể được thay đổi một cách an toàn ở trạng thái SNAPSHOTTED .

Những thay đổi này được thiết kế để ngăn chặn việc vô tình làm cho thiết bị không thể khởi động được nhưng chúng có thể gây gián đoạn cho công cụ tự động. Khi các lệnh được sử dụng như một thành phần để flash tất cả các phân vùng, chẳng hạn như chạy fastboot flashall , bạn nên sử dụng quy trình sau:

  1. Truy vấn getvar snapshot-update-status .
  2. Nếu merging hoặc snapshotted , hãy đưa ra snapshot-update cancel .
  3. Tiến hành với các bước nhấp nháy.

Giảm yêu cầu lưu trữ

Các thiết bị không có bộ nhớ A/B đầy đủ được phân bổ trong super và dự kiến ​​sử dụng /data khi cần thiết, chúng tôi đặc biệt khuyên bạn nên sử dụng công cụ ánh xạ khối. Công cụ ánh xạ khối giữ cho việc phân bổ khối nhất quán giữa các bản dựng, giảm việc ghi không cần thiết vào ảnh chụp nhanh. Điều này được ghi lại trong phần Giảm kích thước OTA .

Phương pháp nén OTA

Các gói OTA có thể được điều chỉnh cho các số liệu hiệu suất khác nhau. Android cung cấp một số phương pháp nén được hỗ trợ ( gz , lz4 , zstdnone ) có sự cân bằng giữa thời gian cài đặt, mức sử dụng dung lượng COW, thời gian khởi động và thời gian hợp nhất ảnh chụp nhanh. Tùy chọn mặc định được bật cho ab ảo có nén là gz compression method . (Lưu ý: hiệu suất tương đối giữa các phương pháp nén khác nhau tùy thuộc vào tốc độ CPU và thông lượng lưu trữ có thể thay đổi tùy theo thiết bị. Tất cả các gói OTA được tạo bên dưới đều bị tắt PostInstall, điều này sẽ làm chậm thời gian khởi động một chút. Tổng kích thước phân vùng động của một ota đầy đủ không nén là 4,81 GB ).

OTA gia tăng trên Pixel 6 Pro

Thời gian cài đặt không có giai đoạn sau cài đặt Sử dụng không gian BÒ Đăng thời gian khởi động OTA Thời gian hợp nhất ảnh chụp nhanh
gz 24 phút 1,18GB 40,2 giây 45,5 giây
lz4 13 phút 1,49GB 37,4 giây 37,1 giây
không có 13 phút 2,90GB 37,6 giây 40,7 giây

OTA đầy đủ trên Pixel 6 Pro

Thời gian cài đặt không có giai đoạn sau cài đặt Sử dụng không gian BÒ Đăng thời gian khởi động OTA Thời gian hợp nhất ảnh chụp nhanh
gz 23 phút 2,79 GB 24,9 giây 41,7 giây
lz4 12 phút 3,46 GB 20,0 giây 25,3 giây
không có 10 phút 4,85 GB 20,6 giây 29,8 giây