Google cam kết thúc đẩy công bằng chủng tộc cho Cộng đồng người da đen. Xem cách thực hiện.

Định dạng tệp APEX

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Định dạng vùng chứa Android Pony EXpress (APEX) đã được giới thiệu trong Android 10 và nó được sử dụng trong quy trình cài đặt cho các mô-đun hệ thống cấp thấp hơn. Định dạng này tạo điều kiện thuận lợi cho việc cập nhật các thành phần hệ thống không phù hợp với mô hình ứng dụng Android tiêu chuẩn. Một số thành phần ví dụ là các dịch vụ và thư viện gốc, các lớp trừu tượng phần cứng ( HAL ), thời gian chạy ( ART ) và các thư viện lớp.

Thuật ngữ "APEX" cũng có thể đề cập đến một tệp APEX.

Tiểu sử

Mặc dù Android hỗ trợ cập nhật các mô-đun phù hợp với mô hình ứng dụng tiêu chuẩn (ví dụ: dịch vụ, hoạt động) thông qua ứng dụng trình cài đặt gói (chẳng hạn như ứng dụng Cửa hàng Google Play), việc sử dụng mô hình tương tự cho các thành phần hệ điều hành cấp thấp hơn có những hạn chế sau:

  • Không thể sử dụng mô-đun dựa trên APK sớm trong trình tự khởi động. Trình quản lý gói là kho lưu trữ trung tâm của thông tin về các ứng dụng và chỉ có thể được khởi động từ trình quản lý hoạt động, sẽ sẵn sàng trong giai đoạn sau của quy trình khởi động.
  • Định dạng APK (đặc biệt là tệp kê khai) được thiết kế cho các ứng dụng Android và mô-đun hệ thống không phải lúc nào cũng phù hợp.

Thiết kế

Phần này mô tả thiết kế cấp cao của định dạng tệp APEX và trình quản lý APEX, là một dịch vụ quản lý tệp APEX.

Để biết thêm thông tin về lý do thiết kế này cho APEX được chọn, hãy xem Các giải pháp thay thế được xem xét khi phát triển APEX .

Định dạng APEX

Đây là định dạng của tệp APEX.

Định dạng tệp APEX

Hình 1. Định dạng tệp APEX

Ở cấp cao nhất, tệp APEX là tệp zip trong đó tệp được lưu trữ không nén và nằm ở ranh giới 4 KB.

Bốn tệp trong một tệp APEX là:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

Tệp apex_manifest.json chứa tên gói và phiên bản để xác định tệp APEX.

Tệp AndroidManifest.xml cho phép tệp APEX sử dụng các công cụ và cơ sở hạ tầng liên quan đến APK như ADB, PackageManager và các ứng dụng trình cài đặt gói (chẳng hạn như Cửa hàng Play). Ví dụ: tệp APEX có thể sử dụng một công cụ hiện có như aapt để kiểm tra siêu dữ liệu cơ bản từ tệp. Tệp chứa tên gói và thông tin phiên bản. Thông tin này thường cũng có sẵn trong apex_manifest.json .

apex_manifest.json được khuyên dùng qua AndroidManifest.xml cho mã mới và hệ thống xử lý APEX. AndroidManifest.xml có thể chứa thông tin nhắm mục tiêu bổ sung có thể được sử dụng bởi các công cụ xuất bản ứng dụng hiện có.

apex_payload.img là hình ảnh hệ thống tệp ext4 được hỗ trợ bởi dm-verity. Hình ảnh được gắn trong thời gian chạy thông qua thiết bị lặp lại. Cụ thể, cây băm và khối siêu dữ liệu được tạo bằng thư viện libavb . Tải trọng hệ thống tệp không được phân tích cú pháp (vì hình ảnh phải được gắn tại chỗ). Các tệp thông thường được bao gồm bên trong tệp apex_payload.img .

apex_pubkey là khóa công khai được sử dụng để ký vào hình ảnh hệ thống tệp. Trong thời gian chạy, khóa này đảm bảo rằng APEX đã tải xuống được ký với cùng một thực thể ký cùng một APEX trong các phân vùng tích hợp sẵn.

Nguyên tắc đặt tên APEX

Để giúp ngăn xung đột đặt tên giữa các APEX mới khi nền tảng tiến bộ, hãy sử dụng các nguyên tắc đặt tên sau:

  • com.android.*
    • Dành riêng cho AOSP APEXes. Không phải là duy nhất cho bất kỳ công ty hoặc thiết bị nào.
  • com.<companyname>.*
    • Dành riêng cho một công ty. Có thể được sử dụng bởi nhiều thiết bị từ công ty đó.
  • com.<companyname>.<devicename>.*
    • Dành riêng cho APEXes duy nhất cho một thiết bị cụ thể (hoặc tập hợp con các thiết bị).

Người quản lý APEX

Trình quản lý APEX (hoặc apexd ) là một quy trình gốc độc lập chịu trách nhiệm xác minh, cài đặt và gỡ cài đặt các tệp APEX. Quá trình này được khởi chạy và sẵn sàng sớm trong trình tự khởi động. Các tệp APEX thường được cài đặt sẵn trên thiết bị theo /system/apex . Trình quản lý APEX mặc định sử dụng các gói này nếu không có bản cập nhật nào.

Trình tự cập nhật của một APEX sử dụng lớp PackageManager và như sau.

  1. Tệp APEX được tải xuống qua ứng dụng trình cài đặt gói, ADB hoặc nguồn khác.
  2. Trình quản lý gói bắt đầu quy trình cài đặt. Khi nhận ra rằng tệp là APEX, trình quản lý gói chuyển giao quyền kiểm soát cho trình quản lý APEX.
  3. Người quản lý APEX xác minh tệp APEX.
  4. Nếu tệp APEX được xác minh, cơ sở dữ liệu nội bộ của trình quản lý APEX được cập nhật để phản ánh rằng tệp APEX được kích hoạt ở lần khởi động tiếp theo.
  5. Người yêu cầu cài đặt nhận được một chương trình phát sóng khi xác minh gói thành công.
  6. Để tiếp tục cài đặt, hệ thống phải được khởi động lại.
  7. Ở lần khởi động tiếp theo, trình quản lý APEX khởi động, đọc cơ sở dữ liệu nội bộ và thực hiện các thao tác sau đối với từng tệp APEX được liệt kê:

    1. Xác minh tệp APEX.
    2. Tạo thiết bị lặp lại từ tệp APEX.
    3. Tạo thiết bị chặn trình ánh xạ thiết bị trên đầu thiết bị lặp lại.
    4. Gắn thiết bị khối ánh xạ thiết bị vào một đường dẫn duy nhất (ví dụ: /apex/ name @ ver ).

Khi tất cả các tệp APEX được liệt kê trong cơ sở dữ liệu nội bộ được gắn kết, trình quản lý APEX cung cấp dịch vụ liên kết cho các thành phần hệ thống khác để truy vấn thông tin về các tệp APEX đã cài đặt. Ví dụ: các thành phần hệ thống khác có thể truy vấn danh sách các tệp APEX được cài đặt trong thiết bị hoặc truy vấn đường dẫn chính xác nơi một APEX cụ thể được gắn kết, để các tệp có thể được truy cập.

Tệp APEX là tệp APK

Tệp APEX là tệp APK hợp lệ vì chúng là tệp lưu trữ zip đã ký (sử dụng lược đồ chữ ký APK) có chứa tệp AndroidManifest.xml . Điều này cho phép các tệp APEX sử dụng cơ sở hạ tầng cho các tệp APK, chẳng hạn như ứng dụng trình cài đặt gói, tiện ích ký và trình quản lý gói.

Tệp AndroidManifest.xml bên trong tệp APEX là tối thiểu, bao gồm name gói, Mã phiên bản và versionCode tùy targetSdkVersion , minSdkVersionmaxSdkVersion để nhắm mục tiêu chi tiết. Thông tin này cho phép phân phối tệp APEX qua các kênh hiện có như ứng dụng trình cài đặt gói và ADB.

Các loại tệp được hỗ trợ

Định dạng APEX hỗ trợ các loại tệp sau:

  • Các lib được chia sẻ tự nhiên
  • Các tệp thực thi gốc
  • Tệp JAR
  • Hồ sơ dữ liệu
  • Định cấu hình tệp

Điều này không có nghĩa là APEX có thể cập nhật tất cả các loại tệp này. Việc một loại tệp có thể được cập nhật hay không tùy thuộc vào nền tảng và mức độ ổn định của các định nghĩa về giao diện cho các loại tệp.

Đang ký

Các tệp APEX được ký theo hai cách. Đầu tiên, apex_payload.img (cụ thể là bộ mô tả vbmeta được nối vào apex_payload.img ) được ký bằng một khóa. Sau đó, toàn bộ APEX được ký bằng lược đồ chữ ký APK v3 . Hai khóa khác nhau được sử dụng trong quá trình này.

Ở phía thiết bị, một khóa công khai tương ứng với khóa cá nhân được sử dụng để ký bộ mô tả vbmeta được cài đặt. Trình quản lý APEX sử dụng khóa công khai để xác minh các APEX được yêu cầu cài đặt. Mỗi APEX phải được ký bằng các khóa khác nhau và được thực thi cả tại thời điểm xây dựng và thời gian chạy.

APEX trong các phân vùng tích hợp

Các tệp APEX có thể được đặt trong các phân vùng dựng sẵn như /system . Phân vùng đã vượt quá dm-verity, vì vậy các tệp APEX được gắn trực tiếp qua thiết bị loopback.

Nếu APEX có trong phân vùng dựng sẵn, APEX có thể được cập nhật bằng cách cung cấp gói APEX có cùng tên gói và lớn hơn hoặc bằng mã phiên bản. APEX mới được lưu trữ trong /data và, tương tự như APK, phiên bản mới được cài đặt sẽ làm mờ phiên bản đã có trong phân vùng tích hợp. Nhưng không giống như APK, phiên bản APEX mới được cài đặt chỉ được kích hoạt sau khi khởi động lại.

Yêu cầu về nhân

Để hỗ trợ mô-đun dòng chính APEX trên thiết bị Android, cần có các tính năng nhân Linux sau: trình điều khiển vòng lặp và dm-verity. Trình điều khiển loopback gắn hình ảnh hệ thống tệp trong mô-đun APEX và dm-verity xác minh mô-đun APEX.

Hiệu suất của trình điều khiển loopback và dm-verity rất quan trọng trong việc đạt được hiệu suất hệ thống tốt khi sử dụng mô-đun APEX.

Các phiên bản hạt nhân được hỗ trợ

Các mô-đun dòng chính APEX được hỗ trợ trên các thiết bị sử dụng phiên bản hạt nhân 4.4 trở lên. Các thiết bị mới khởi chạy với Android 10 trở lên phải sử dụng phiên bản hạt nhân 4.9 trở lên để hỗ trợ mô-đun APEX.

Các bản vá nhân bắt buộc

Các bản vá lỗi hạt nhân cần thiết để hỗ trợ mô-đun APEX được bao gồm trong cây chung của Android. Để nhận các bản vá hỗ trợ APEX, hãy sử dụng phiên bản mới nhất của cây chung Android.

Phiên bản hạt nhân 4.4

Phiên bản này chỉ được hỗ trợ cho các thiết bị được nâng cấp từ Android 9 lên Android 10 và muốn hỗ trợ mô-đun APEX. Để nhận được các bản vá lỗi cần thiết, bạn nên hợp nhất xuống từ nhánh android-4.4 . Sau đây là danh sách các bản vá lỗi riêng lẻ cần thiết cho phiên bản hạt nhân 4.4.

  • UPSTREAM: loop: thêm ioctl để thay đổi kích thước khối logic ( 4.4 )
  • BACKPORT: block / loop: set hw_sectors ( 4.4 )
  • UPSTREAM: loop: Thêm LOOP_SET_BLOCK_SIZE trong compat ioctl ( 4.4 )
  • ANDROID: mnt: Sửa next_descendent ( 4.4 )
  • ANDROID: mnt: remount nên truyền cho nô lệ của nô lệ ( 4.4 )
  • ANDROID: mnt: Truyền số tiền lại một cách chính xác ( 4.4 )
  • Hoàn nguyên "ANDROID: dm verity: thêm kích thước tìm nạp trước tối thiểu" ( 4.4 )
  • UPSTREAM: loop: drop caches nếu offset hoặc block_size được thay đổi ( 4.4 )

Phiên bản hạt nhân 4.9 / 4.14 / 4.19

Để nhận các bản vá lỗi cần thiết cho phiên bản hạt nhân 4.9 / 4.14 / 4.19, hãy hợp nhất xuống từ nhánh android-common .

Các tùy chọn cấu hình hạt nhân bắt buộc

Danh sách sau đây hiển thị các yêu cầu cấu hình cơ bản để hỗ trợ mô-đun APEX đã được giới thiệu trong Android 10. Các mục có dấu hoa thị (*) là các yêu cầu hiện có từ Android 9 trở xuống.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

Yêu cầu tham số dòng lệnh của nhân

Để hỗ trợ APEX, hãy đảm bảo các tham số dòng lệnh hạt nhân đáp ứng các yêu cầu sau:

  • loop.max_loop KHÔNG được đặt
  • loop.max_part phải <= 8

Xây dựng APEX

Phần này mô tả cách tạo APEX bằng hệ thống xây dựng Android. Sau đây là một ví dụ về Android.bp cho một APEX có tên là apex.test .

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

Ví dụ apex_manifest.json :

{
  "name": "com.android.example.apex",
  "version": 1
}

ví dụ về file_contexts :

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

Loại tệp và vị trí trong APEX

Loại tệp Vị trí ở APEX
Thư viện được chia sẻ /lib/lib64 ( /lib/arm cho nhánh đã dịch trong x86)
Thực thi /bin
Thư viện Java /javalib
Bản dựng sẵn /etc

Phụ thuộc bắc cầu

Các tệp APEX tự động bao gồm các phụ thuộc bắc cầu của các lib hoặc tệp thực thi được chia sẻ gốc. Ví dụ: nếu libFoo phụ thuộc vào libBar , thì hai lib được bao gồm khi chỉ libFoo được liệt kê trong thuộc tính native_shared_libs .

Xử lý nhiều ABI

Cài đặt thuộc tính native_shared_libs cho cả giao diện nhị phân ứng dụng chính và phụ (ABI) của thiết bị. Nếu APEX nhắm mục tiêu đến các thiết bị có một ABI duy nhất (nghĩa là chỉ 32 bit hoặc chỉ 64 bit), thì chỉ các thư viện có ABI tương ứng mới được cài đặt.

Chỉ cài đặt thuộc tính binaries cho ABI chính của thiết bị như được mô tả bên dưới:

  • Nếu thiết bị chỉ là 32 bit, thì chỉ có biến thể 32 bit của nhị phân được cài đặt.
  • Nếu thiết bị chỉ là 64 bit, thì chỉ có biến thể 64 bit của nhị phân được cài đặt.

Để thêm quyền kiểm soát chi tiết đối với ABI của các thư viện và mã nhị phân gốc, hãy sử dụng multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] .

  • first : Khớp với ABI chính của thiết bị. Đây là mặc định cho mã nhị phân.
  • lib32 : Khớp với ABI 32-bit của thiết bị, nếu được hỗ trợ.
  • lib64 : Khớp với ABI 64-bit của thiết bị, nó được hỗ trợ.
  • prefer32 : Khớp với ABI 32-bit của thiết bị, nếu được hỗ trợ. Nếu ABI 32 bit không được hỗ trợ, hãy khớp với ABI 64 bit.
  • both : Đối sánh cả hai ABI. Đây là mặc định cho native_shared_libraries .

Các thuộc tính java , libraries và các thuộc tính prebuilts là ABI-bất khả tri.

Ví dụ này dành cho thiết bị hỗ trợ 32/64 và không thích 32:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

ký vbmeta

Ký mỗi APEX bằng các khóa khác nhau. Khi cần khóa mới, hãy tạo một cặp khóa công khai-riêng tư và tạo mô-đun apex_key . Sử dụng thuộc tính key để ký APEX bằng khóa. Khóa công khai tự động được đưa vào APEX với tên avb_pubkey .

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

Trong ví dụ trên, tên của khóa công khai ( foo ) trở thành ID của khóa. ID của khóa được sử dụng để ký APEX được viết trong APEX. Trong thời gian chạy, apexd xác minh APEX bằng khóa công khai có cùng ID trong thiết bị.

Ký ZIP

Ký các APEX giống như cách bạn ký các APK. Ký APEXes hai lần; một lần cho hệ thống tệp nhỏ (tệp apex_payload.img ) và một lần cho toàn bộ tệp.

Để ký một APEX ở cấp tệp, hãy đặt thuộc tính certificate theo một trong ba cách sau:

  • Chưa đặt: Nếu không có giá trị nào được đặt, APEX được ký bằng chứng chỉ tại PRODUCT_DEFAULT_DEV_CERTIFICATE . Nếu không có cờ nào được đặt, đường dẫn sẽ được mặc định là build/target/product/security/testkey .
  • <name> : APEX được ký bằng chứng chỉ <name> trong cùng thư mục với PRODUCT_DEFAULT_DEV_CERTIFICATE .
  • :<name> : APEX được ký bằng chứng chỉ được xác định bởi mô-đun Soong có tên là <name> . Mô-đun chứng chỉ có thể được định nghĩa như sau.
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

Cài đặt APEX

Để cài đặt APEX, hãy sử dụng ADB.

adb install apex_file_name
adb reboot

Sử dụng APEX

Sau khi khởi động lại, APEX được gắn tại thư mục /apex/<apex_name>@<version> . Nhiều phiên bản của cùng một APEX có thể được gắn cùng một lúc. Trong số các đường dẫn gắn kết, đường dẫn tương ứng với phiên bản mới nhất được gắn kết tại /apex/<apex_name> .

Khách hàng có thể sử dụng đường dẫn được gắn kết để đọc hoặc thực thi các tệp từ APEX.

Các APEX thường được sử dụng như sau:

  1. OEM hoặc ODM tải trước APEX trong /system/apex khi thiết bị được xuất xưởng.
  2. Các tệp trong APEX được truy cập qua đường dẫn /apex/<apex_name>/ .
  3. Khi một phiên bản cập nhật của APEX được cài đặt trong /data/apex , đường dẫn sẽ trỏ đến APEX mới sau khi khởi động lại.

Cập nhật dịch vụ bằng APEX

Để cập nhật một dịch vụ bằng APEX:

  1. Đánh dấu dịch vụ trong phân vùng hệ thống là có thể cập nhật được. Thêm tùy chọn có updatable vào định nghĩa dịch vụ.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. Tạo tệp .rc mới cho dịch vụ cập nhật. Sử dụng tùy chọn override để xác định lại dịch vụ hiện có.

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

Định nghĩa dịch vụ chỉ có thể được xác định trong tệp .rc của APEX. Trình kích hoạt hành động không được hỗ trợ trong APEX.

Nếu một dịch vụ được đánh dấu là có thể cập nhật bắt đầu trước khi các APEX được kích hoạt, thì việc khởi động sẽ bị trì hoãn cho đến khi quá trình kích hoạt các APEX hoàn tất.

Cấu hình hệ thống để hỗ trợ cập nhật APEX

Đặt thuộc tính hệ thống sau thành true để hỗ trợ cập nhật tệp APEX.

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

hoặc chỉ

<device.mk>:

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

APEX phẳng

Đối với các thiết bị cũ, đôi khi không thể hoặc không thể cập nhật hạt nhân cũ để hỗ trợ đầy đủ APEX. Ví dụ: hạt nhân có thể đã được xây dựng mà không có CONFIG_BLK_DEV_LOOP=Y , điều này rất quan trọng để gắn hình ảnh hệ thống tệp bên trong APEX.

APEX phẳng là một APEX được xây dựng đặc biệt có thể được kích hoạt trên các thiết bị có nhân kế thừa. Các tệp trong APEX phẳng được cài đặt trực tiếp vào một thư mục trong phân vùng tích hợp sẵn. Ví dụ: lib/libFoo.so trong my.apex APEX phẳng được cài đặt vào /system/apex/my.apex/lib/libFoo.so .

Việc kích hoạt APEX phẳng không liên quan đến thiết bị vòng lặp. Toàn bộ thư /system/apex/my.apex được gắn trực tiếp vào /apex/name@ver .

Không thể cập nhật các APEX đã làm phẳng bằng cách tải xuống các phiên bản cập nhật của APEX từ mạng vì không thể làm phẳng các APEX đã tải xuống. Các APEX phẳng chỉ có thể được cập nhật thông qua OTA thông thường.

APEX phẳng là cấu hình mặc định. Điều này có nghĩa là tất cả các APEX đều được làm phẳng theo mặc định trừ khi bạn định cấu hình thiết bị của mình một cách rõ ràng để tạo các APEX không phẳng để hỗ trợ cập nhật APEX (như đã giải thích ở trên).

KHÔNG hỗ trợ trộn các APEX phẳng và không phẳng trong một thiết bị. Các APEX trong một thiết bị phải là tất cả không phẳng hoặc tất cả đều phẳng. Điều này đặc biệt quan trọng khi vận chuyển các bản dựng sẵn APEX đã ký trước cho các dự án như Mainline. Các APEX không được chỉ định trước (nghĩa là được xây dựng từ nguồn) cũng phải không được làm phẳng và được ký bằng các khóa thích hợp. Thiết bị phải kế thừa từ updatable_apex.mk như được giải thích trong Cập nhật dịch vụ với APEX .

APEX được nén

Android 12 trở lên có tính năng nén APEX để giảm tác động lưu trữ của các gói APEX có thể cập nhật. Sau khi bản cập nhật cho APEX được cài đặt, mặc dù phiên bản cài đặt sẵn của nó không được sử dụng nữa nhưng nó vẫn chiếm cùng một lượng dung lượng. Không gian bị chiếm dụng đó vẫn không có sẵn.

Nén APEX giảm thiểu tác động lưu trữ này bằng cách sử dụng một tập hợp các tệp APEX được nén cao trên các phân vùng chỉ đọc (chẳng hạn như phân vùng /system ). Android 12 trở lên sử dụng thuật toán nén zip DEFLATE.

Nén không cung cấp tối ưu hóa cho những điều sau:

  • Bootstrap APEXes được yêu cầu gắn rất sớm trong trình tự khởi động.

  • APEXes không thể cập nhật. Nén chỉ có lợi nếu một phiên bản cập nhật của APEX được cài đặt trên phân vùng /data . Danh sách đầy đủ các APEX có thể cập nhật có sẵn trên trang Thành phần Hệ thống Mô-đun .

  • APEXes lib được chia sẻ động. Vì apexd luôn kích hoạt cả hai phiên bản của các APEX như vậy (được cài đặt sẵn và nâng cấp) nên việc nén chúng không tăng thêm giá trị.

Định dạng tệp APEX được nén

Đây là định dạng của tệp APEX nén.

Diagram shows the format of a compressed APEX file

Hình 2. Định dạng tệp APEX nén

Ở cấp cao nhất, tệp APEX được nén là tệp zip chứa tệp đỉnh ban đầu ở dạng xì hơi với mức nén là 9 và với các tệp khác được lưu trữ không nén.

Bốn tệp bao gồm một tệp APEX:

  • original_apex : bị xì hơi với mức nén 9 Đây là tệp APEX gốc, không nén.
  • apex_manifest.pb : chỉ được lưu trữ
  • AndroidManifest.xml : chỉ được lưu trữ
  • apex_pubkey : chỉ được lưu trữ

Các apex_manifest.pb , AndroidManifest.xmlapex_pubkey là bản sao của các tệp tương ứng của chúng trong original_apex .

Xây dựng APEX nén

APEX nén có thể được tạo bằng công cụ apex_compression_tool.py có tại system/apex/tools .

Một số tham số liên quan đến nén APEX có sẵn trong hệ thống xây dựng.

Trong Android.bp , liệu một tệp APEX có thể nén được hay không được kiểm soát bởi thuộc tính có thể compressible :

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

Cờ sản phẩm PRODUCT_COMPRESSED_APEX kiểm soát xem hình ảnh hệ thống được tạo từ nguồn có phải chứa tệp APEX nén hay không.

Đối với thử nghiệm cục bộ, bạn có thể buộc một bản dựng nén APEX bằng cách đặt OVERRIDE_PRODUCT_COMPRESSED_APEX OVERRIDE_PRODUCT_COMPRESSED_APEX= thành true .

Các tệp APEX nén được tạo bởi hệ thống xây dựng có phần mở rộng .capex . Phần mở rộng giúp bạn dễ dàng phân biệt giữa các phiên bản nén và không nén của tệp APEX.

Các thuật toán nén được hỗ trợ

Android 12 chỉ hỗ trợ nén deflate-zip.

Kích hoạt tệp APEX nén trong khi khởi động

Trước khi một APEX nén có thể được kích hoạt, tệp original_apex bên trong nó được giải nén vào thư mục /data/apex/decompressed . Tệp APEX được giải nén kết quả được liên kết cứng với thư mục /data/apex/active .

Hãy coi ví dụ sau như một minh họa của quá trình được mô tả ở trên.

Hãy coi /system/apex/com.android.foo.capex là một APEX nén đang được kích hoạt, với Mã phiên bản 37.

  1. Tệp original_apex bên trong /system/apex/com.android.foo.capex được giải nén thành /data/apex/decompressed/com.android.foo@37.apex .
  2. restorecon /data/apex/decompressed/com.android.foo@37.apex được thực hiện để xác minh rằng nó có nhãn SELinux chính xác.
  3. Kiểm tra xác minh được thực hiện trên /data/apex/decompressed/com.android.foo@37.apex để đảm bảo tính hợp lệ của nó: apexd kiểm tra khóa công khai có trong /data/apex/decompressed/com.android.foo@37.apex tới xác minh rằng nó bằng với một gói trong /system/apex/com.android.foo.capex .
  4. Tệp /data/apex/decompressed/com.android.foo@37.apex được liên kết cứng với thư /data/apex/active/com.android.foo@37.apex .
  5. Logic kích hoạt thông thường cho các tệp APEX không nén được thực hiện trên /data/apex/active/com.android.foo@37.apex .

Tương tác với OTA

Các tệp APEX được nén có tác động đến việc phân phối và ứng dụng OTA. Vì bản cập nhật OTA có thể chứa tệp APEX nén với cấp phiên bản cao hơn so với những gì đang hoạt động trên thiết bị, nên phải dành một lượng dung lượng trống nhất định trước khi thiết bị được khởi động lại để áp dụng bản cập nhật OTA.

Để hỗ trợ hệ thống OTA, apexd tiết lộ hai API chất kết dính sau:

  • calculateSizeForCompressedApex - tính toán kích thước cần thiết để giải nén các tệp APEX trong một gói OTA. Điều này có thể được sử dụng để xác minh rằng một thiết bị có đủ dung lượng trước khi một OTA được tải xuống.
  • reserveSpaceForCompressedApex - dự trữ dung lượng trên đĩa để apexd sử dụng trong tương lai để giải nén các tệp APEX đã nén bên trong gói OTA.

Trong trường hợp cập nhật A / B OTA, apexd cố gắng giải nén ở chế độ nền như một phần của quy trình cài đặt OTA sau khi cài đặt. Nếu giải nén không thành công, apexd thực hiện giải nén trong quá trình khởi động áp dụng bản cập nhật OTA.

Các giải pháp thay thế được xem xét khi phát triển APEX

Dưới đây là một số tùy chọn mà AOSP đã xem xét khi thiết kế định dạng tệp APEX và tại sao chúng được bao gồm hoặc loại trừ.

Hệ thống quản lý gói thông thường

Các bản phân phối Linux có các hệ thống quản lý gói như dpkgrpm , rất mạnh mẽ, hoàn thiện và mạnh mẽ. Tuy nhiên, chúng không được sử dụng cho APEX vì chúng không thể bảo vệ các gói sau khi cài đặt. Việc xác minh chỉ được thực hiện khi các gói đang được cài đặt. Những kẻ tấn công có thể phá vỡ tính toàn vẹn của các gói đã cài đặt, không được chú ý. Đây là một hồi quy dành cho Android trong đó tất cả các thành phần hệ thống được lưu trữ trong các hệ thống tệp chỉ đọc có tính toàn vẹn được bảo vệ bởi dm-verity cho mọi I / O. Mọi hành vi giả mạo thành phần hệ thống đều phải bị cấm hoặc có thể phát hiện được để thiết bị có thể từ chối khởi động nếu bị xâm phạm.

dm-crypt cho tính toàn vẹn

Các tệp trong vùng chứa APEX là từ các phân vùng tích hợp sẵn (ví dụ: phân vùng /system ) được bảo vệ bởi dm-verity, nơi mọi sửa đổi đối với tệp đều bị cấm ngay cả sau khi các phân vùng được gắn kết. Để cung cấp cùng một mức độ bảo mật cho các tệp, tất cả các tệp trong APEX được lưu trữ trong một hình ảnh hệ thống tệp được ghép nối với cây băm và bộ mô tả vbmeta. Nếu không có dm-verity, APEX trong phân vùng /data sẽ dễ bị ảnh hưởng bởi các sửa đổi ngoài ý muốn được thực hiện sau khi nó được xác minh và cài đặt.

Trên thực tế, phân vùng /data cũng được bảo vệ bởi các lớp mã hóa như dm-crypt. Mặc dù điều này cung cấp một số mức độ bảo vệ chống lại sự giả mạo, mục đích chính của nó là quyền riêng tư, không phải tính toàn vẹn. Khi kẻ tấn công giành được quyền truy cập vào phân vùng /data , không thể có biện pháp bảo vệ nào nữa và đây lại là một hồi quy so với mọi thành phần hệ thống nằm trong phân vùng /system . Cây băm bên trong tệp APEX cùng với dm-verity cung cấp cùng một mức độ bảo vệ nội dung.

Chuyển hướng đường dẫn từ / system đến / apex

Các tệp thành phần hệ thống được đóng gói trong APEX có thể truy cập được qua các đường dẫn mới như /apex/<name>/lib/libfoo.so . Khi các tệp là một phần của phân vùng /system , chúng có thể truy cập được thông qua các đường dẫn như /system/lib/libfoo.so . Ứng dụng khách của tệp APEX (tệp APEX khác hoặc nền tảng) phải sử dụng các đường dẫn mới. Bạn có thể cần cập nhật mã hiện có do thay đổi đường dẫn.

Mặc dù một cách để tránh thay đổi đường dẫn là phủ nội dung tệp trong tệp APEX lên phân vùng /system , nhóm Android đã quyết định không phủ các tệp trên phân vùng /system vì điều này có thể ảnh hưởng đến hiệu suất do số lượng tệp được chồng lên ( thậm chí có thể xếp chồng lên nhau) tăng lên.

Một tùy chọn khác là chiếm quyền điều khiển các chức năng truy cập tệp như open , statreadlink , để các đường dẫn bắt đầu bằng /system được chuyển hướng đến các đường dẫn tương ứng của chúng trong /apex . Nhóm Android đã loại bỏ tùy chọn này vì không thể thay đổi tất cả các chức năng chấp nhận đường dẫn. Ví dụ: một số ứng dụng liên kết tĩnh Bionic, ứng dụng này thực hiện các chức năng. Trong những trường hợp như vậy, những ứng dụng đó không được chuyển hướng.