Bố cục phân vùng

Trong Android 10, hệ thống tệp gốc không còn nằm trong ramdisk.img nữa mà được hợp nhất vào system.img (tức là system.img luôn được tạo nếu BOARD_BUILD_SYSTEM_ROOT_IMAGE được đặt). Các thiết bị ra mắt cùng Android 10:

  • Sử dụng bố cục phân vùng hệ thống dưới dạng gốc (tự động được thực thi bởi bản dựng mà không có lựa chọn thay đổi hành vi).
  • Phải sử dụng ramdisk, đây là yêu cầu bắt buộc đối với dm-linear.
  • Bạn phải đặt BOARD_BUILD_SYSTEM_ROOT_IMAGE thành false. Chế độ cài đặt này chỉ được dùng để phân biệt giữa các thiết bị sử dụng ramdisk và các thiết bị không sử dụng ramdisk (thay vào đó, hãy gắn trực tiếp system.img).

Ý nghĩa của cấu hình hệ thống dưới dạng gốc khác nhau giữa Android 9 và Android 10. Trong cấu hình hệ thống dưới dạng gốc của Android 9, BOARD_BUILD_SYSTEM_ROOT_IMAGE được đặt thành true, buộc bản dựng hợp nhất hệ thống tệp gốc thành system.img, sau đó gắn system.img làm hệ thống tệp gốc (rootfs). Cấu hình này là bắt buộc đối với các thiết bị ra mắt cùng Android 9 nhưng là không bắt buộc đối với các thiết bị nâng cấp lên Android 9 và các thiết bị chạy phiên bản Android thấp hơn. Trong cấu hình hệ thống dưới dạng gốc của Android 10, bản dựng luôn hợp nhất $TARGET_SYSTEM_OUT$TARGET_ROOT_OUT thành system.img; cấu hình này là hành vi mặc định cho tất cả các thiết bị chạy Android 10.

Android 10 có những thay đổi khác để hỗ trợ phân vùng động, một hệ thống phân vùng không gian người dùng cho phép các bản cập nhật qua mạng (OTA) tạo, đổi kích thước hoặc xoá các phân vùng. Trong quá trình thay đổi này, nhân Linux không còn có thể gắn phân vùng hệ thống logic trên các thiết bị chạy Android 10 nữa, vì vậy, thao tác này sẽ do giai đoạn khởi động đầu tiên xử lý.

Các phần sau đây mô tả các yêu cầu về hệ thống dưới dạng gốc đối với các bản cập nhật qua mạng (OTA) chỉ dành cho hệ thống, đồng thời đưa ra hướng dẫn về cách cập nhật thiết bị để sử dụng hệ thống dưới dạng gốc (bao gồm cả các thay đổi về bố cục phân vùng và các yêu cầu về nhân dm-verity). Để biết thông tin chi tiết về các thay đổi đối với ramdisk, hãy xem Phân vùng Ramdisk.

Giới thiệu về OTA chỉ dành cho hệ thống

OTA chỉ dành cho hệ thống, cho phép các bản phát hành Android cập nhật system.imgproduct.img mà không thay đổi các phân vùng khác, yêu cầu bố cục phân vùng hệ thống dưới dạng gốc. Tất cả các thiết bị chạy Android 10 đều phải sử dụng bố cục phân vùng hệ thống dưới dạng gốc để bật các bản cập nhật qua mạng (OTA) chỉ dành cho hệ thống.

Để biết thông tin chi tiết về thiết bị A/B và thiết bị không phải A/B, hãy tham khảo bài viết Bản cập nhật hệ thống A/B (liền mạch).

Sử dụng lớp phủ của nhà cung cấp (<=AOSP 14)

Lớp phủ của nhà cung cấp cho phép bạn phủ các thay đổi lên phân vùng vendor tại thời điểm khởi động thiết bị. Lớp phủ của nhà cung cấp là một nhóm các mô-đun của nhà cung cấp trong phân vùng product được phủ lên phân vùng vendor khi thiết bị khởi động, thay thế và thêm vào các mô-đun hiện có.

Khi thiết bị khởi động, quy trình init sẽ hoàn tất quá trình gắn giai đoạn đầu tiên và đọc các thuộc tính mặc định. Sau đó, nó sẽ tìm kiếm /product/vendor_overlay/<target_vendor_version> và gắn từng thư mục con vào thư mục phân vùng vendor tương ứng, nếu đáp ứng các điều kiện sau:

  • /vendor/<overlay_dir> tồn tại.
  • /product/vendor_overlay/<target_vendor_version>/<overlay_dir> có ngữ cảnh tệp giống như /vendor/<overlay_dir>.
  • init được phép gắn vào ngữ cảnh tệp của /vendor/<overlay_dir>.

Triển khai lớp phủ của nhà cung cấp

Cài đặt các tệp lớp phủ của nhà cung cấp trong /product/vendor_overlay/<target_vendor_version>. Những tệp đó sẽ phủ lên phân vùng vendor khi thiết bị khởi động, thay thế các tệp có cùng tên và thêm mọi tệp mới. Lớp phủ của nhà cung cấp không thể xoá các tệp khỏi phân vùng vendor.

Các tệp lớp phủ của nhà cung cấp phải có cùng ngữ cảnh tệp với các tệp đích mà chúng thay thế trong phân vùng vendor. Theo mặc định, các tệp trong thư mục /product/vendor_overlay/<target_vendor_version> có ngữ cảnh vendor_file. Nếu có sự không khớp về ngữ cảnh tệp giữa các tệp lớp phủ của nhà cung cấp và các tệp mà chúng thay thế, hãy chỉ định điều đó trong sepolicy dành riêng cho thiết bị. Ngữ cảnh tệp được đặt ở cấp thư mục. Nếu ngữ cảnh tệp của một thư mục lớp phủ của nhà cung cấp không khớp với thư mục đích và ngữ cảnh tệp chính xác không được chỉ định trong sepolicy dành riêng cho thiết bị, thì thư mục lớp phủ của nhà cung cấp đó sẽ không được phủ lên thư mục đích.

Để sử dụng lớp phủ của nhà cung cấp, nhân phải bật OverlayFS bằng cách đặt CONFIG_OVERLAY_FS=y. Ngoài ra, bạn phải hợp nhất nhân từ nhân chung 4.4 trở lên hoặc vá bằng "overlayfs: override_creds=off option bypass creator_cred".

Ví dụ về cách triển khai lớp phủ của nhà cung cấp

Quy trình này minh hoạ cách triển khai lớp phủ của nhà cung cấp sẽ phủ lên các thư mục /vendor/lib/*, /vendor/etc/*/vendor/app/*.

  1. Thêm các tệp nhà cung cấp tạo sẵn vào device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/:

    device/google/device/vendor_overlay/28/lib/libfoo.so
    device/google/device/vendor_overlay/28/lib/libbar.so
    device/google/device/vendor_overlay/28/etc/baz.xml
    device/google/device/vendor_overlay/28/app/qux.apk
  2. Cài đặt các tệp nhà cung cấp được tạo sẵn vào product/vendor_overlay trong device/google/device/device.mk:

    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
  3. Xác định ngữ cảnh tệp nếu các tệp phân vùng vendor đích có ngữ cảnh khác với vendor_file. Vì /vendor/lib/* sử dụng ngữ cảnh vendor_file, nên ví dụ này không bao gồm thư mục đó.

    Thêm nội dung sau vào device/google/device-sepolicy/private/file_contexts:

    /(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)?   u:object_r:vendor_configs_file:s0
    /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)?   u:object_r:vendor_app_file:s0
  4. Cho phép quy trình init gắn lớp phủ của nhà cung cấp trên các ngữ cảnh tệp khác với vendor_file. Vì quy trình init đã có quyền gắn kết trên ngữ cảnh vendor_file, nên ví dụ này không xác định chính sách cho vendor_file.

    Thêm nội dung sau vào device/google/device-sepolicy/public/init.te:

    allow init vendor_configs_file:dir mounton;
    allow init vendor_app_file:dir mounton;

Xác thực lớp phủ của nhà cung cấp

Để xác thực cấu hình lớp phủ của nhà cung cấp, hãy thêm các tệp vào /product/vendor_overlay/<target_vendor_version>/<overlay_dir> và kiểm tra xem các tệp đó có được phủ lên các tệp trong /vendor/<overlay_dir> hay không.

Đối với các bản dựng userdebug, có một mô-đun kiểm thử cho Atest:

$ atest -v fs_mgr_vendor_overlay_test

Cập nhật lên hệ thống dưới dạng gốc

Để cập nhật các thiết bị không phải A/B để sử dụng hệ thống dưới dạng gốc, bạn phải cập nhật sơ đồ phân vùng cho boot.imgsystem.img, thiết lập dm-verity và xoá mọi phần phụ thuộc khởi động trên các thư mục gốc dành riêng cho thiết bị.

Cập nhật phân vùng

Không giống như các thiết bị A/B sử dụng lại /boot làm phân vùng khôi phục, các thiết bị không phải A/B phải giữ phân vùng /recovery riêng biệt vì chúng không có phân vùng khe dự phòng (ví dụ: từ boot_a đến boot_b). Nếu /recovery bị xoá trên thiết bị không phải A/B và được tạo tương tự như sơ đồ A/B, thì chế độ khôi phục có thể bị hỏng trong quá trình cập nhật không thành công cho phân vùng /boot. Vì lý do này, phân vùng /recovery phải là một phân vùng riêng biệt với /boot đối với các thiết bị không phải A/B, điều này ngụ ý rằng hình ảnh khôi phục sẽ tiếp tục được cập nhật theo cách trì hoãn (tức là giống như trên các thiết bị chạy Android 8.1.0 trở xuống).

Bảng sau đây liệt kê các điểm khác biệt về phân vùng hình ảnh cho các thiết bị không phải A/B trước và sau Android 9.

Hình ảnh Ramdisk (trước Android 9) Hệ thống dưới dạng gốc (sau Android 9)
boot.img Chứa một nhân và một ramdisk.img:
ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
Chỉ chứa một kernel khởi động thông thường.
recovery.img Chứa một nhân khôi phục và một ramdisk.img khôi phục.
system.img Chứa những nội dung sau:
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
Chứa nội dung được hợp nhất của system.imgramdisk.img:
system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...

Bản thân các phân vùng không thay đổi; cả ramdisk và system-as-root đều sử dụng sơ đồ phân vùng sau:

  • /boot
  • /system
  • /system
  • /recovery
  • /vendor, v.v.

Thiết lập dm-verity

Trong system-as-root, nhân phải gắn system.img trong / (điểm gắn kết) bằng dm-verity. AOSP hỗ trợ các cách triển khai dm-verity sau đây cho system.img.

vboot 1.0

Đối với vboot 1.0, nhân phải phân tích cú pháp siêu dữ liệu dành riêng cho Android trên /system, sau đó chuyển đổi thành tham số dm-verity để thiết lập dm-verity (yêu cầu các bản vá nhân này). Ví dụ sau đây cho thấy các chế độ cài đặt liên quan đến dm-verity cho hệ thống dưới dạng gốc trong dòng lệnh của nhân:

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0

Đối với vboot 2.0 (AVB), trình tải khởi động phải tích hợp external/avb/libavb, sau đó phân tích cú pháp hashtree descriptor cho /system, chuyển đổi thành dm-verity params và cuối cùng truyền các tham số đến nhân thông qua dòng lệnh của nhân. (Các giá trị nhận dạng Hashtree của /system có thể nằm trên /vbmeta hoặc trên chính /system.)

vboot 2.0 yêu cầu các bản vá kernel sau:

Ví dụ sau đây cho thấy các chế độ cài đặt liên quan đến dm-verity cho hệ thống dưới dạng gốc trong dòng lệnh của nhân:

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"

Sử dụng thư mục gốc dành riêng cho thiết bị

Với system-as-root, sau khi hình ảnh hệ thống chung (GSI) được flash trên thiết bị (và trước khi chạy các kiểm thử Vendor Test Suite), mọi thư mục gốc dành riêng cho thiết bị được thêm bằng BOARD_ROOT_EXTRA_FOLDERS sẽ biến mất vì toàn bộ nội dung thư mục gốc đã được thay thế bằng GSI system-as-root. Việc xoá các thư mục này có thể khiến thiết bị không khởi động được nếu có một phần phụ thuộc vào các thư mục gốc dành riêng cho thiết bị (ví dụ: các thư mục này được dùng làm điểm gắn kết).

Để tránh gặp phải vấn đề này, đừng dùng BOARD_ROOT_EXTRA_FOLDERS để thêm các thư mục gốc dành riêng cho thiết bị. Nếu bạn cần chỉ định các điểm gắn kết dành riêng cho thiết bị, hãy sử dụng /mnt/vendor/<mount point> (được thêm vào danh sách thay đổi này). Bạn có thể chỉ định trực tiếp các điểm gắn kết dành riêng cho nhà cung cấp này trong cả cây thiết bị fstab (để gắn kết giai đoạn đầu) và tệp /vendor/etc/fstab.{ro.hardware} mà không cần thiết lập thêm (vì fs_mgr sẽ tự động tạo các điểm này trong /mnt/vendor/*).