Lưu tệp APK vào bộ nhớ đệm

Tài liệu này mô tả thiết kế của giải pháp lưu vào bộ nhớ đệm APK để cài đặt nhanh các ứng dụng tải trước trên thiết bị hỗ trợ phân vùng A/B.

Nhà sản xuất thiết bị gốc (OEM) có thể đặt các ứng dụng tải trước và ứng dụng phổ biến vào bộ nhớ đệm APK được lưu trữ trong phân vùng B hầu như trống trên các thiết bị phân vùng A/B mới mà không ảnh hưởng đến không gian dữ liệu mà người dùng nhìn thấy. Nhờ có bộ nhớ đệm APK trên thiết bị, các thiết bị mới hoặc mới đặt lại về trạng thái ban đầu gần như có thể sử dụng ngay lập tức mà không cần tải tệp APK xuống từ Google Play.

Trường hợp sử dụng

  • Lưu trữ các ứng dụng tải sẵn trong phân vùng B để thiết lập nhanh hơn
  • Lưu trữ các ứng dụng phổ biến trong phân vùng B để khôi phục nhanh hơn

Điều kiện tiên quyết

Để sử dụng tính năng này, thiết bị cần:

  • Đã cài đặt bản phát hành Android 8.1 (O MR1)
  • Đã triển khai phân vùng A/B

Bạn chỉ có thể sao chép nội dung được tải trước trong lần khởi động đầu tiên. Lý do là trên các thiết bị hỗ trợ bản cập nhật hệ thống A/B, phân vùng B không thực sự lưu trữ các tệp hình ảnh hệ thống mà thay vào đó là nội dung tải trước như tài nguyên minh hoạ bán lẻ, tệp OAT và bộ nhớ đệm APK. Sau khi các tài nguyên được sao chép vào phân vùng /data (việc này xảy ra trong lần khởi động đầu tiên), phân vùng B sẽ được các bản cập nhật qua mạng không dây (OTA) sử dụng để tải các phiên bản cập nhật của ảnh hệ thống xuống.

Do đó, bạn không thể cập nhật bộ nhớ đệm APK thông qua OTA; bạn chỉ có thể tải trước bộ nhớ đệm này tại nhà máy. Tính năng đặt lại về trạng thái ban đầu chỉ ảnh hưởng đến phân vùng /data. Phân vùng hệ thống B vẫn có nội dung được tải trước cho đến khi tải hình ảnh OTA xuống. Sau khi đặt lại về trạng thái ban đầu, hệ thống sẽ khởi động lại lần đầu. Điều này có nghĩa là bạn không thể lưu APK vào bộ nhớ đệm nếu hình ảnh OTA được tải xuống phân vùng B, sau đó thiết bị được đặt lại về trạng thái ban đầu.

Triển khai

Phương pháp 1. Nội dung trên phân vùng system_other

Pro: Nội dung tải trước sẽ không bị mất sau khi đặt lại về trạng thái ban đầu – nội dung này sẽ được sao chép từ phân vùng B sau khi khởi động lại.

Con: Yêu cầu dung lượng trên phân vùng B. Việc khởi động sau khi đặt lại về trạng thái ban đầu sẽ mất thêm thời gian để sao chép nội dung được tải trước.

Để sao chép nội dung tải trước trong lần khởi động đầu tiên, hệ thống sẽ gọi một tập lệnh trong /system/bin/preloads_copy.sh. Tập lệnh được gọi bằng một đối số duy nhất (đường dẫn đến điểm gắn chỉ có thể đọc cho phân vùng system_b):

Để triển khai tính năng này, hãy thực hiện những thay đổi sau đây theo từng thiết bị. Sau đây là ví dụ về Marlin:

  1. Thêm tập lệnh thực hiện việc sao chép vào tệp device-common.mk (trong trường hợp này là device/google/marlin/device-common.mk), như sau:
    # Script that copies preloads directory from system_other to data partition
    PRODUCT_COPY_FILES += \
        device/google/marlin/preloads_copy.sh:system/bin/preloads_copy.sh
    
    Tìm nguồn tập lệnh mẫu tại: device/google/marlin/preloads_copy.sh
  2. Chỉnh sửa tệp init.common.rc để tạo thư mục /data/preloads và thư mục con cần thiết:
    mkdir /data/preloads 0775 system system
    mkdir /data/preloads/media 0775 system system
    mkdir /data/preloads/demo 0775 system system
    
    Tìm nguồn tệp init mẫu tại: device/google/marlin/init.common.rc
  3. Xác định một miền SELinux mới trong tệp preloads_copy.te:
    type preloads_copy, domain, coredomain;
    type preloads_copy_exec, exec_type, vendor_file_type, file_type;
    
    init_daemon_domain(preloads_copy)
    
    allow preloads_copy shell_exec:file rx_file_perms;
    allow preloads_copy toolbox_exec:file rx_file_perms;
    allow preloads_copy preloads_data_file:dir create_dir_perms;
    allow preloads_copy preloads_data_file:file create_file_perms;
    allow preloads_copy preloads_media_file:dir create_dir_perms;
    allow preloads_copy preloads_media_file:file create_file_perms;
    
    # Allow to copy from /postinstall
    allow preloads_copy system_file:dir r_dir_perms;
    
    Tìm tệp miền SELinux mẫu tại: /device/google/marlin/+/main/sepolicy/preloads_copy.te
  4. Đăng ký miền trong tệp /sepolicy/file_contexts mới:
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    Tìm tệp ngữ cảnh SELinux mẫu tại: device/google/marlin/sepolicy/preloads_copy.te
  5. Tại thời điểm tạo bản dựng, thư mục có nội dung tải sẵn phải được sao chép vào phân vùng system_other:
    # Copy contents of preloads directory to system_other partition
    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,vendor/google_devices/marlin/preloads,system_other/preloads)
    
    Đây là ví dụ về một thay đổi trong Makefile cho phép sao chép tài nguyên bộ nhớ đệm APK từ kho lưu trữ Git của nhà cung cấp (trong trường hợp của chúng tôi là vendor/google_devices/marlin/preloads) vào vị trí trên phân vùng system_other sau đó sẽ được sao chép vào /data/preloads khi thiết bị khởi động lần đầu. Tập lệnh này chạy tại thời điểm tạo bản dựng để chuẩn bị hình ảnh system_other. Phương thức này dự kiến nội dung được tải trước sẽ có trong vendor/google_devices/marlin/preloads. OEM có thể tự do chọn tên/đường dẫn kho lưu trữ thực tế.
  6. Bộ nhớ đệm APK nằm trong /data/preloads/file_cache và có bố cục sau:
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    Đây là cấu trúc thư mục cuối cùng trên các thiết bị. Nhà sản xuất thiết bị gốc (OEM) có thể tự do chọn phương pháp triển khai bất kỳ, miễn là cấu trúc tệp cuối cùng sao chép cấu trúc được mô tả ở trên.

Phương pháp 2. Nội dung trên hình ảnh dữ liệu người dùng được cài đặt ROM tại nhà máy

Phương pháp thay thế này giả định rằng nội dung tải trước đã có trong thư mục /data/preloads trên phân vùng /data.

Pro: Hoạt động ngay từ đầu – không cần tuỳ chỉnh thiết bị để sao chép tệp trong lần khởi động đầu tiên. Nội dung đã có trên phân vùng /data.

Con: Nội dung tải trước sẽ bị mất sau khi đặt lại về trạng thái ban đầu. Mặc dù một số nhà sản xuất thiết bị gốc (OEM) có thể chấp nhận điều này, nhưng không phải lúc nào cách này cũng hiệu quả với những nhà sản xuất thiết bị gốc đặt lại thiết bị về trạng thái ban đầu sau khi kiểm tra chất lượng.

Thêm một phương thức @SystemApi mới, getPreloadsFileCache(), vào android.content.Context. Phương thức này trả về một đường dẫn tuyệt đối đến thư mục dành riêng cho ứng dụng trong bộ nhớ đệm được tải trước.

Thêm một phương thức mới là IPackageManager.deletePreloadsFileCache cho phép xoá thư mục tải trước để lấy lại tất cả không gian. Phương thức này chỉ có thể được gọi bởi các ứng dụng có SYSTEM_UID, tức là máy chủ hệ thống hoặc Cài đặt.

Chuẩn bị ứng dụng

Chỉ những ứng dụng đặc quyền mới có thể truy cập vào thư mục bộ nhớ đệm tải trước. Để có quyền truy cập đó, bạn phải cài đặt ứng dụng trong thư mục /system/priv-app.

Xác nhận kết quả

  • Sau lần khởi động đầu tiên, thiết bị sẽ có nội dung trong thư mục /data/preloads/file_cache.
  • Bạn phải xoá nội dung trong thư mục file_cache/ nếu thiết bị sắp hết bộ nhớ.

Sử dụng ứng dụng mẫu ApkCacheTest để kiểm thử bộ nhớ đệm APK.

  1. Tạo ứng dụng bằng cách chạy lệnh sau từ thư mục gốc:
    make ApkCacheTest
    
  2. Cài đặt ứng dụng dưới dạng ứng dụng đặc quyền. (Hãy nhớ rằng chỉ những ứng dụng đặc quyền mới có thể truy cập vào bộ nhớ đệm APK.) Bạn cần có thiết bị bị can thiệp hệ thống để thực hiện việc này:
    adb root && adb remount
    adb shell mkdir /system/priv-app/ApkCacheTest
    adb push $ANDROID_PRODUCT_OUT/data/app/ApkCacheTest/ApkCacheTest.apk /system/priv-app/ApkCacheTest/
    adb shell stop && adb shell start
    
  3. Mô phỏng thư mục bộ nhớ đệm tệp và nội dung của thư mục đó nếu cần (cũng yêu cầu đặc quyền cấp gốc):
    adb shell mkdir -p /data/preloads/file_cache/com.android.apkcachetest
    adb shell restorecon -r /data/preloads
    adb shell "echo "Test File" > /data/preloads/file_cache/com.android.apkcachetest/test.txt"
    
  4. Kiểm thử ứng dụng. Sau khi cài đặt ứng dụng và tạo thư mục file_cache kiểm thử, hãy mở ứng dụng ApkCacheTest. Ứng dụng này sẽ hiển thị một tệp test.txt và nội dung của tệp đó. Hãy xem ảnh chụp màn hình này để biết cách những kết quả này xuất hiện trong giao diện người dùng.

    Hình 1. Kết quả ApkCacheTest.