本文檔描述了一種 APK 緩存解決方案的設計,用於在支持 A/B 分區的設備上快速安裝預加載的應用程序。
OEM 可以將預加載和流行的應用程序放在存儲在新A/B 分區設備上大部分為空的 B 分區中的 APK 緩存中,而不會影響任何面向用戶的數據空間。通過在設備上提供 APK 緩存,新的或最近恢復出廠設置的設備幾乎可以立即使用,而無需從 Google Play 下載 APK 文件。
用例
- 將預加載的應用程序存儲在 B 分區中以加快設置速度
- 將流行的應用程序存儲在 B 分區中以更快地恢復
先決條件
要使用此功能,設備需要:
- 已安裝 Android 8.1 (O MR1) 版本
- 實現了 A/B 分區
預加載的內容只能在首次啟動時復制。這是因為在支持 A/B 系統更新的設備上,B 分區實際上並不存儲系統映像文件,而是預加載了零售演示資源、OAT 文件和 APK 緩存等內容。將資源複製到 /data 分區後(這發生在首次啟動時),B 分區將被無線 (OTA) 更新用於下載系統映像的更新版本。
因此無法通過OTA更新APK緩存;它只能在工廠預裝。恢復出廠設置僅影響 /data 分區。系統 B 分區仍然有預加載的內容,直到下載 OTA 映像。恢復出廠設置後,系統將再次進行首次引導。這意味著如果將OTA鏡像下載到B分區,則無法使用APK緩存,然後將設備恢復出廠設置。
執行
方法 1. system_other 分區上的內容
優點:恢復出廠設置後預加載的內容不會丟失 - 它將在重新啟動後從 B 分區復制。
缺點:需要 B 分區上的空間。恢復出廠設置後啟動需要額外的時間來複製預加載的內容。
為了在首次啟動期間複製預加載,系統調用/system/bin/preloads_copy.sh
中的腳本。該腳本使用單個參數調用( system_b
分區的只讀掛載點的路徑):
要實現此功能,請進行這些特定於設備的更改。這是馬林的一個例子:
- 將執行複制的腳本添加到
device-common.mk
文件(在本例中為device/google/marlin/device-common.mk
),如下所示:# 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
在以下位置查找示例腳本源: device/google/marlin /preloads_copy.sh - 編輯
init.common.rc
文件,讓它創建必要的/data/preloads
目錄和子目錄:mkdir /data/preloads 0775 system system
mkdir /data/preloads/media 0775 system system
mkdir /data/preloads/demo 0775 system system
init
文件源: device/google/marlin/init.common.rc - 在文件
preloads_copy.te
中定義一個新的 SELinux 域: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;
在以下位置查找示例 SELinux 域文件:/device/google/marlin/+/master/ sepolicy /preloads_copy.te - 在新的域名中註冊
/sepolicy/file_contexts
文件:/system/bin/preloads_copy\.sh u:object_r:preloads_copy_exec:s0
在以下位置查找示例 SELinux 上下文文件: device/google/marlin/sepolicy/preloads_copy.te - 在構建時,必須將帶有預加載內容的目錄複製到
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)
這是一個 Makefile 更改示例,允許從供應商的 Git 存儲庫複製 APK 緩存資源(在我們的例子中是 vendor/google_devices/ marlin/preloads) 到 system_other 分區上的位置,稍後將在設備首次啟動時復製到 /data/preloads。此腳本在構建時運行以準備 system_other 映像。它希望在 vendor/google_devices/marlin/preloads 中提供預加載的內容。 OEM 可以自由選擇實際的存儲庫名稱/路徑。 - APK 緩存位於
/data/preloads/file_cache
並具有以下佈局:/data/preloads/file_cache/ app.package.name.1/ file1 fileN app.package.name.N/
這是設備上的最終目錄結構。 OEM 可以自由選擇任何實施方法,只要最終的文件結構複製上述一種。
方法 2. 出廠時閃現的用戶數據圖像內容
這種替代方法假定預加載的內容已經包含在/data
分區的/data/preloads
目錄中。
Pro :開箱即用 - 無需進行設備自定義即可在首次啟動時復製文件。內容已經在/data
分區上。
缺點:恢復出廠設置後,預加載的內容會丟失。雖然這對某些人來說可能是可以接受的,但對於在進行質量控制檢查後出廠重置設備的 OEM 來說,它可能並不總是有效。
一個新的 @SystemApi 方法getPreloadsFileCache()
被添加到android.content.Context
中。它返回預加載緩存中特定於應用程序的目錄的絕對路徑。
添加了一個新方法IPackageManager.deletePreloadsFileCache
,允許刪除預加載目錄以回收所有空間。該方法只能由具有SYSTEM_UID的應用程序調用,即係統服務器或設置。
應用準備
只有特權應用程序才能訪問預加載緩存目錄。對於該訪問,應用程序必須安裝在/system/priv-app
目錄中。
驗證
- 首次啟動後,設備應該在
/data/preloads/file_cache
目錄中有內容。 - 如果設備存儲空間不足,則必須刪除
file_cache/
目錄中的內容。
使用示例ApkCacheTest應用程序來測試 APK 緩存。
- 通過從根目錄運行以下命令來構建應用程序:
make ApkCacheTest
- 將應用程序安裝為特權應用程序。 (請記住,只有特權應用才能訪問 APK 緩存。)這需要有根設備:
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
- 如果需要,模擬文件緩存目錄及其內容(也需要 root 權限):
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"
- 測試應用程序。安裝應用程序並創建測試文件緩存目錄後,打開
file_cache
應用程序。它應該顯示一個文件test.txt
及其內容。請參閱此屏幕截圖以了解這些結果在用戶界面中的顯示方式。圖 1. ApkCacheTest 結果