Tổng quan về A/B ảo

Android có hai cơ chế cập nhật: cập nhật A/B (liền mạch) và cập nhật không phải A/B. Để giảm độ phức tạp của mã và nâng cao quá trình cập nhật, trong Android 11, hai cơ chế này được hợp nhất thông qua A/B ảo để mang đến các bản cập nhật liền mạch cho tất cả các thiết bị với chi phí lưu trữ được giảm thiểu. Android 12 cung cấp tùy chọn nén A/B ảo để nén các phân vùng được chụp nhanh. Trong cả Android 11 và Android 12, những điều sau đều được áp dụng:

  • Cập nhật A/B ảo diễn ra liền mạch như cập nhật A/B. Cập nhật A/B ảo giảm thiểu thời gian thiết bị ngoại tuyến và không sử dụng được.
  • Cập nhật A/B ảo có thể được khôi phục . Nếu hệ điều hành mới không khởi động được, thiết bị sẽ tự động quay lại phiên bản trước.
  • Các bản cập nhật A/B ảo sử dụng ít không gian bổ sung nhất bằng cách chỉ sao chép các phân vùng được bộ tải khởi động sử dụng. Các phân vùng có thể cập nhật khác được chụp nhanh .

Bối cảnh và thuật ngữ

Phần này xác định thuật ngữ và mô tả công nghệ hỗ trợ A/B ảo.

Trình ánh xạ thiết bị

Trình ánh xạ thiết bị là lớp khối ảo Linux được sử dụng thường xuyên trong Android. Với phân vùng động , các phân vùng như /system là một tập hợp các thiết bị phân lớp:

  • Ở cuối ngăn xếp là siêu phân vùng vật lý (ví dụ: /dev/block/by-name/super ).
  • Ở giữa là thiết bị dm-linear , chỉ định các khối trong siêu phân vùng tạo thành phân vùng đã cho. Điều này xuất hiện dưới dạng /dev/block/mapper/system_[a|b] trên thiết bị A/B hoặc /dev/block/mapper/system trên thiết bị không phải A/B.
  • Ở trên cùng là thiết bị dm-verity , được tạo cho các phân vùng đã được xác minh. Thiết bị này xác minh rằng các khối trên thiết bị dm-linear được ký chính xác. Nó xuất hiện dưới dạng /dev/block/mapper/system-verity và là nguồn của điểm gắn kết /system .

Hình 1 cho thấy ngăn xếp bên dưới điểm gắn /system trông như thế nào.

Partition stacking underneath system

Hình 1. Xếp chồng dưới điểm gắn kết /system

ảnh chụp nhanh dm

A/B ảo dựa trên dm-snapshot , một mô-đun ánh xạ thiết bị để chụp nhanh trạng thái của thiết bị lưu trữ. Khi sử dụng dm-snapshot , có bốn thiết bị đang hoạt động:

  • Thiết bị cơ sở là thiết bị được chụp nhanh. Trên trang này, thiết bị cơ sở luôn là một phân vùng động, chẳng hạn như hệ thống hoặc nhà cung cấp.
  • Thiết bị sao chép khi ghi (COW), để ghi nhật ký các thay đổi đối với thiết bị cơ sở. Nó có thể có kích thước bất kỳ nhưng phải đủ lớn để đáp ứng mọi thay đổi đối với thiết bị cơ bản.
  • Thiết bị chụp nhanh được tạo bằng cách sử dụng mục tiêu snapshot . Việc ghi vào thiết bị chụp nhanh được ghi vào thiết bị COW. Đọc từ thiết bị chụp nhanh được đọc từ thiết bị cơ sở hoặc thiết bị COW, tùy thuộc vào việc dữ liệu đang được truy cập có bị thay đổi bởi ảnh chụp nhanh hay không.
  • Thiết bị gốc được tạo bằng cách sử dụng mục tiêu snapshot-origin . Đọc vào thiết bị gốc đọc trực tiếp từ thiết bị cơ sở. Ghi vào thiết bị gốc ghi trực tiếp vào thiết bị cơ sở, nhưng dữ liệu gốc được sao lưu bằng cách ghi vào thiết bị COW.

Device mapping for dm-snapshot

Hình 2. Ánh xạ thiết bị cho dm-snapshot

Ảnh chụp nhanh nén

Trong Android 12 trở lên, do yêu cầu về dung lượng trên phân vùng /data có thể cao nên bạn có thể bật ảnh chụp nhanh được nén trong bản dựng của mình để giải quyết các yêu cầu về dung lượng cao hơn của phân vùng /data .

Ảnh chụp nhanh nén A/B ảo được xây dựng dựa trên các thành phần sau có sẵn trong Android 12 trở lên:

  • dm-user , một mô-đun hạt nhân tương tự FUSE cho phép không gian người dùng triển khai các thiết bị khối.
  • snapuserd , một daemon không gian người dùng để triển khai định dạng ảnh chụp nhanh mới.

Các thành phần này cho phép nén. Những thay đổi cần thiết khác được thực hiện để triển khai khả năng chụp nhanh nén được đưa ra trong các phần tiếp theo: định dạng COW cho ảnh chụp nhanh nén , dm-userSnapuserd .

Định dạng COW cho ảnh chụp nhanh được nén

Trong Android 12 trở lên, ảnh chụp nhanh được nén sử dụng định dạng COW. Tương tự như định dạng tích hợp của kernel được sử dụng cho các ảnh chụp nhanh không nén, định dạng COW cho các ảnh chụp nhanh được nén có các phần siêu dữ liệu và dữ liệu xen kẽ. Siêu dữ liệu của định dạng ban đầu chỉ được phép thực hiện các thao tác thay thế : Thay thế khối X trong ảnh cơ sở bằng nội dung của khối Y trong ảnh chụp nhanh. Định dạng ảnh chụp nhanh COW được nén có tính biểu cảm cao hơn và hỗ trợ các hoạt động sau:

  • Sao chép : Khối X trong thiết bị cơ sở nên được thay thế bằng khối Y trong thiết bị cơ sở.
  • Thay thế : Khối X trong thiết bị cơ sở phải được thay thế bằng nội dung của khối Y trong ảnh chụp nhanh. Mỗi khối này được nén gz.
  • Số 0 : Khối X trong thiết bị cơ sở phải được thay thế bằng tất cả các số 0.
  • XOR : Thiết bị COW lưu trữ các byte nén XOR giữa khối X và khối Y. (Có sẵn trong Android 13 trở lên.)

Các bản cập nhật OTA đầy đủ chỉ bao gồm các hoạt động thay thếkhông . Các bản cập nhật OTA gia tăng cũng có thể có các hoạt động sao chép .

người dùng dm trong Android 12

Mô-đun hạt nhân dm-user cho phép userspace triển khai các thiết bị khối ánh xạ thiết bị. Mục nhập bảng dm-user tạo một thiết bị linh tinh trong /dev/dm-user/<control-name> . Một quy trình userspace có thể thăm dò thiết bị để nhận các yêu cầu đọc và ghi từ kernel. Mỗi yêu cầu có một bộ đệm liên quan để không gian người dùng được điền (để đọc) hoặc truyền (để ghi).

Mô-đun hạt nhân dm-user cung cấp một giao diện mới mà người dùng có thể nhìn thấy cho hạt nhân mà không phải là một phần của cơ sở mã kernel.org ngược dòng. Cho đến khi điều đó xảy ra, Google có quyền sửa đổi giao diện dm-user trong Android.

snapuserd

Thành phần không gian người dùng snapuserd cho dm-user thực hiện nén A/B ảo.

Trong phiên bản Virtual A/B không nén, (trong Android 11 trở xuống hoặc trong Android 12 không có tùy chọn ảnh chụp nhanh được nén), thiết bị COW là một tệp thô. Khi tính năng nén được bật, COW hoạt động như một thiết bị dm-user , được kết nối với một phiên bản của daemon snapuserd .

Hạt nhân không sử dụng định dạng COW mới. Vì vậy, thành phần snapuserd dịch các yêu cầu giữa định dạng COW của Android và định dạng tích hợp của kernel:

Snapuserd component translating requests between Android COW format and kernel built-in format

Hình 3. Sơ đồ luồng của snapuserd làm trình dịch giữa định dạng Android và Kernel COW

Quá trình dịch và giải nén này không bao giờ xảy ra trên đĩa. Thành phần snapuserd chặn hoạt động đọc và ghi COW xảy ra trong kernel và triển khai chúng bằng định dạng COW của Android.

nén XOR

Đối với các thiết bị chạy Android 13 trở lên, tính năng nén XOR, được bật theo mặc định, cho phép ảnh chụp nhanh trong không gian người dùng lưu trữ byte nén XOR giữa các khối cũ và khối mới. Khi chỉ một vài byte trong một khối được thay đổi trong bản cập nhật A/B ảo, sơ đồ lưu trữ nén XOR sử dụng ít dung lượng hơn sơ đồ lưu trữ mặc định vì ảnh chụp nhanh không lưu trữ toàn bộ 4K byte. Việc giảm kích thước ảnh chụp nhanh này là có thể thực hiện được vì dữ liệu XOR chứa nhiều số 0 và dễ nén hơn dữ liệu khối thô. Trên thiết bị Pixel, tính năng nén XOR giúp giảm kích thước ảnh chụp nhanh từ 25% đến 40%.

Đối với các thiết bị nâng cấp lên Android 13 trở lên, phải bật tính năng nén XOR. Để biết chi tiết, xem nén XOR .

Quá trình nén A/B ảo

Phần này cung cấp thông tin chi tiết về quy trình nén A/B ảo được sử dụng trong Android 13 và Android 12.

Đọc siêu dữ liệu (Android 12)

Siêu dữ liệu được xây dựng bởi daemon snapuserd . Siêu dữ liệu chủ yếu là ánh xạ của hai ID, mỗi ID 8 byte, đại diện cho các khu vực được hợp nhất. Trong dm-snapshot nó được gọi disk_exception .

struct disk_exception {
    uint64_t old_chunk;
    uint64_t new_chunk;
};

Ngoại lệ đĩa được sử dụng khi một đoạn dữ liệu cũ được thay thế bằng một đoạn dữ liệu mới.

Trình nền snapuserd đọc tệp COW nội bộ thông qua thư viện COW và xây dựng siêu dữ liệu cho từng hoạt động COW có trong tệp COW.

Việc đọc siêu dữ liệu được bắt đầu từ dm-snapshot trong kernel khi thiết bị dm- snapshot được tạo.

Hình bên dưới cung cấp sơ đồ trình tự cho đường dẫn IO để xây dựng siêu dữ liệu.

Sequence diagram, IO path for metadata construction

Hình 4. Luồng trình tự cho đường dẫn IO trong xây dựng siêu dữ liệu

Hợp nhất (Android 12)

Sau khi quá trình khởi động hoàn tất, công cụ cập nhật đánh dấu vị trí là khởi động thành công và bắt đầu hợp nhất bằng cách chuyển mục tiêu dm-snapshot sang mục tiêu dm-snapshot-merge .

dm-snapshot duyệt qua siêu dữ liệu và bắt đầu IO hợp nhất cho từng ngoại lệ đĩa. Tổng quan cấp cao về đường dẫn IO hợp nhất được hiển thị bên dưới.

Merge IO path

Hình 5. Tổng quan về đường dẫn IO hợp nhất

Nếu thiết bị được khởi động lại trong quá trình hợp nhất, quá trình hợp nhất sẽ tiếp tục vào lần khởi động lại tiếp theo và quá trình hợp nhất hoàn tất.

Phân lớp trình ánh xạ thiết bị

Đối với các thiết bị chạy Android 13 trở lên, quy trình hợp nhất ảnh chụp nhanh và ảnh chụp nhanh trong nén A/B ảo được thực hiện bởi thành phần không gian người dùng snapuserd . Đối với các thiết bị nâng cấp lên Android 13 trở lên, tính năng này phải được bật. Để biết chi tiết, hãy xem Hợp nhất không gian người dùng .

Phần sau đây mô tả quy trình nén A/B ảo:

  1. Khung này gắn kết phân vùng /system khỏi thiết bị dm-verity , được xếp chồng lên trên thiết bị dm-user . Điều này có nghĩa là mọi I/O từ hệ thống tệp gốc đều được định tuyến tới dm-user .
  2. dm-user định tuyến I/O tới daemon snapuserd của không gian người dùng, nơi xử lý yêu cầu I/O.
  3. Khi thao tác hợp nhất hoàn tất, khung sẽ thu gọn dm-verity lên trên dm-linear ( system_base ) và xóa dm-user .

Quá trình nén A/B ảo

Hình 6. Quá trình nén A/B ảo

Quá trình hợp nhất ảnh chụp nhanh có thể bị gián đoạn. Nếu thiết bị được khởi động lại trong quá trình hợp nhất, quá trình hợp nhất sẽ tiếp tục sau khi khởi động lại.

Chuyển tiếp ban đầu

Khi khởi động bằng ảnh chụp nhanh được nén, init giai đoạn đầu tiên phải khởi động snapuserd để gắn kết các phân vùng. Điều này đặt ra một vấn đề: Khi tải và thực thi sepolicy biệt, snapuserd bị đặt sai ngữ cảnh và các yêu cầu đọc của nó không thành công, dẫn đến việc từ chối selinux.

Để giải quyết vấn đề này, snapuserd chuyển tiếp theo bước khóa với init , như sau:

  1. init giai đoạn đầu khởi chạy snapuserd từ ramdisk và lưu bộ mô tả tệp đang mở vào nó trong một biến môi trường.
  2. init giai đoạn đầu chuyển hệ thống tập tin gốc sang phân vùng hệ thống, sau đó thực thi bản sao hệ thống của init .
  3. Bản sao hệ thống của init đọc chính sách kết hợp thành một chuỗi.
  4. Init gọi mlock() trên tất cả các trang được hỗ trợ bởi ext4. Sau đó, nó sẽ hủy kích hoạt tất cả các bảng ánh xạ thiết bị cho các thiết bị chụp nhanh và dừng snapuserd . Sau đó, việc đọc từ các phân vùng bị cấm vì làm như vậy sẽ gây ra bế tắc.
  5. Bằng cách sử dụng bộ mô tả mở cho bản sao ramdisk của snapuserd , init sẽ khởi chạy lại daemon với ngữ cảnh selinux chính xác. Bảng ánh xạ thiết bị cho các thiết bị chụp nhanh được kích hoạt lại.
  6. Ban đầu gọi munlockall() - việc thực hiện lại IO là an toàn.

Sử dụng không gian

Bảng sau đây cung cấp thông tin so sánh về mức sử dụng dung lượng của các cơ chế OTA khác nhau sử dụng kích thước hệ điều hành và OTA của Pixel.

Tác động kích thước không phải A/B A/B A/B ảo A/B ảo (đã nén)
Hình ảnh nhà máy gốc Siêu 4,5 GB (hình ảnh 3,8G + dự trữ 700M) 1 Super 9GB (dành riêng 3,8G + 700M, cho hai khe cắm) Siêu 4,5 GB (hình ảnh 3,8G + dự trữ 700M) Siêu 4,5 GB (hình ảnh 3,8G + dự trữ 700M)
Các phân vùng tĩnh khác /bộ đệm Không có Không có Không có
Dung lượng bổ sung trong OTA (dung lượng được trả lại sau khi áp dụng OTA) 1,4GB trên /dữ liệu 0 3,8GB 2 trên/dữ liệu 2.1GB 2 trên/dữ liệu
Tổng dung lượng cần thiết để áp dụng OTA 5,9GB 3 (siêu và dữ liệu) 9GB (siêu) 8.3GB 3 (siêu và dữ liệu) 6.6GB 3 (siêu và dữ liệu)

1 Cho biết bố cục giả định dựa trên ánh xạ Pixel.

2 Giả sử hình ảnh hệ thống mới có cùng kích thước với hình ảnh gốc.

3 Yêu cầu về dung lượng là tạm thời cho đến khi khởi động lại.

Để triển khai A/B ảo hoặc sử dụng khả năng chụp nhanh được nén, hãy xem Triển khai A/B ảo