自 2025 年 3 月 27 日起,我們建議您使用 android-latest-release
而非 aosp-main
建構及貢獻 AOSP。詳情請參閱「Android 開放原始碼計畫變更」。
APK 快取
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
本文說明 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 分區後 (這會在首次開機時發生),OTA 更新會使用 B 分區下載更新版的系統映像檔。
因此,APK 快取無法透過 OTA 更新,只能在工廠預先載入。工廠重置只會影響 /data 分割區。在 OTA 映像檔下載之前,系統 B 分區仍會保留預先載入的內容。恢復原廠設定後,系統會再次進行首次啟動程序。也就是說,如果 OTA 映像檔下載至 B 分區,然後裝置恢復原廠設定,則無法使用 APK 快取功能。
實作
方法 1. system_other 分割區的內容
Pro:恢復原廠設定後,預先載入的內容不會遺失,會在重新啟動後從 B 分區複製。
Con:需要在 B 分區中留出空間。恢復原廠設定後的開機作業需要額外的時間來複製預先載入的內容。
為了在首次開機時複製預先載入內容,系統會在 /system/bin/preloads_copy.sh
中呼叫指令碼。這個指令碼會使用單一引數 (system_b
分區的唯讀掛載點路徑) 來呼叫:
如要實作這項功能,請進行以下裝置專屬變更。以下是 Marlin 的範例:
- 將執行複製作業的指令碼新增至
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/+/android16-release/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 存放區 (在本例中為 vendor/google_devices/marlin/preloads) 複製 APK 快取資源,並將其複製至 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
目錄中。
優點:開箱即用,無須進行裝置自訂設定,即可在第一次啟動時複製檔案。內容已位於 /data
區段。
缺點:恢復原廠設定後,預先載入的內容會遺失。雖然這對某些廠商來說可能可行,但對於在品質管制檢查後將裝置重設為出廠設定的 OEM 廠商來說,這可能不一定可行。
android.content.Context
新增了新的 @SystemApi 方法 getPreloadsFileCache()
。它會傳回預先載入快取中應用程式專屬目錄的絕對路徑。
我們新增了 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
目錄後,請開啟 ApkCacheTest 應用程式。應用程式應會顯示一個檔案 test.txt
及其內容。請參閱這張螢幕截圖,瞭解這些結果在使用者介面中的顯示方式。
圖 1. ApkCacheTest 結果。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-27 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-07-27 (世界標準時間)。"],[],[],null,["# APK caching\n\nThis document describes design of an APK caching solution for rapid installation\nof preloaded apps on a device that supports A/B partitions.\n\n\nOEMs can place preloads and popular apps in the APK cache stored in the mostly\nempty B partition on new [A/B-partitioned](/docs/core/ota/ab_updates) devices without impacting\nany user-facing data space. By having an APK cache available on the device, new or\nrecently factory reset devices are ready for use almost immediately, without\nneeding to download APK files from Google Play.\n\nUse cases\n---------\n\n- Store preloaded apps in B partition for faster setup\n- Store popular apps in B partition for faster restoration\n\nPrerequisites\n-------------\n\n\nTo use this feature, the device needs:\n\n- Android 8.1 (O MR1) release installed\n- A/B partition implemented\n\n\nPreloaded content can be copied only during first boot. This is because on\ndevices supporting A/B system updates, the B partition doesn't actually store\nsystem image files, but instead preloaded content like retail demo resources,\nOAT files and the APK cache. After resources have been copied to the /data\npartition (this happens on first boot), the B partition will be used by [over-the-air (OTA)\nupdates](/docs/core/ota) for downloading updated versions of the system image.\n\n\nTherefore, the APK cache cannot be updated through OTA; it can be preloaded only\nat a factory. Factory reset affects only the /data partition. The system B\npartition still has the preloaded content until the OTA image is downloaded.\nAfter factory reset, the system will go through first boot again. This means APK\ncaching isn't available if the OTA image is downloaded to the B partition, and\nthen the device is factory reset.\n\nImplementation\n--------------\n\n### Approach 1. Content on\nsystem_other partition\n\n\n**Pro**: Preloaded content isn't lost after factory reset - it\nwill be copied from the B partition after a reboot.\n\n\n**Con**: Requires space on B partition. Boot after factory reset\nrequires additional time to copy preloaded content.\n\n\nIn order for preloads to be copied during first boot, the system calls a script\nin `/system/bin/preloads_copy.sh`. The script is called with a single\nargument (path to the read-only mount point for `system_b`\npartition):\n\n\nTo implement this feature, make these device-specific changes. Here is an\nexample from Marlin:\n\n1. Add the script that does the copying to the `device-common.mk` file (in this case, `device/google/marlin/device-common.mk`), like so: \n\n ```\n # Script that copies preloads directory from system_other to data partition\n PRODUCT_COPY_FILES += \\\n device/google/marlin/preloads_copy.sh:system/bin/preloads_copy.sh\n ```\n Find example script source at: [device/google/marlin/preloads_copy.sh](https://android.googlesource.com/device/google/marlin/+/android16-release/preloads_copy.sh)\n2. Edit the `init.common.rc` file to have it create the necessary` /data/preloads` directory and subdirectories: \n\n mkdir /data/preloads 0775 system system\n mkdir /data/preloads/media 0775 system system\n mkdir /data/preloads/demo 0775 system system\n\n Find example `init` file source at: [device/google/marlin/init.common.rc](https://android.googlesource.com/device/google/marlin/+/android16-release/init.common.rc)\n3. Define a new SELinux domain in the file `preloads_copy.te`: \n\n ```\n type preloads_copy, domain, coredomain;\n type preloads_copy_exec, exec_type, vendor_file_type, file_type;\n\n init_daemon_domain(preloads_copy)\n\n allow preloads_copy shell_exec:file rx_file_perms;\n allow preloads_copy toolbox_exec:file rx_file_perms;\n allow preloads_copy preloads_data_file:dir create_dir_perms;\n allow preloads_copy preloads_data_file:file create_file_perms;\n allow preloads_copy preloads_media_file:dir create_dir_perms;\n allow preloads_copy preloads_media_file:file create_file_perms;\n\n # Allow to copy from /postinstall\n allow preloads_copy system_file:dir r_dir_perms;\n ```\n Find an example SELinux domain file at: [/device/google/marlin/+/android16-release/sepolicy/preloads_copy.te](https://android.googlesource.com/device/google/marlin/+/android16-release/sepolicy/preloads_copy.te)\n4. Register the domain in a new /sepolicy/file_contexts file: \n\n ```\n /system/bin/preloads_copy\\.sh u:object_r:preloads_copy_exec:s0\n ```\n Find an example SELinux contexts file at: [device/google/marlin/sepolicy/preloads_copy.te](https://android.googlesource.com/device/google/marlin/+/android16-release/sepolicy/preloads_copy.te)\n5. At build time, the directory with preloaded content must be copied to the `system_other` partition: \n\n ```\n # Copy contents of preloads directory to system_other partition\n PRODUCT_COPY_FILES += \\\n $(call find-copy-subdir-files,*,vendor/google_devices/marlin/preloads,system_other/preloads)\n ```\n This is an example of a change in a Makefile that allows copying APK cache resources from vendor's Git repository (in our case it was vendor/google_devices/marlin/preloads) to the location on system_other partition that will later be copied to /data/preloads when device boots for the first time. This script runs at build time to prepare system_other image. It expects preloaded content to be available in vendor/google_devices/marlin/preloads. OEM is free to choose the actual repository name/path.\n6. The APK cache is located in `/data/preloads/file_cache` and has the following layout: \n\n ```\n /data/preloads/file_cache/\n app.package.name.1/\n file1\n fileN\n app.package.name.N/\n ```\n This is the final directory structure on the devices. OEMs are free to choose any implementation approach as long as the final file structure replicates the one described above.\n\n### Approach 2. Content on user data\nimage flashed at factory\n\n\nThis alternative approach assumes that preloaded content is already included in\nthe `/data/preloads` directory on the `/data` partition.\n\n\n**Pro** : Works out of the box - no need to make device\ncustomizations to copy files on first boot. Content is already on the\n`/data` partition.\n\n\n**Con**: Preloaded content is lost after a factory reset. While\nthis might be acceptable for some, it might not always work for OEMs who factory\nreset devices after doing quality control inspections.\n\n\nA new @SystemApi method, `getPreloadsFileCache()`, was added to\n`android.content.Context`. It returns an absolute path to an\napp-specific directory in the preloaded cache.\n\n\nA new method, `IPackageManager.deletePreloadsFileCache`, was added\nthat allows deleting the preloads directory to reclaim all space. The method can\nbe called only by apps with SYSTEM_UID, i.e. system server or Settings.\n\nApp preparation\n---------------\n\n\nOnly privileged apps can access the preloads cache directory. For that\naccess, apps must be installed in the` /system/priv-app` directory.\n\nValidation\n----------\n\n- After first boot, the device should have content in the `/data/preloads/file_cache` directory.\n- The content in the `file_cache/` directory must be deleted if the device runs low on storage.\n\nUse the example [ApkCacheTest](https://android.googlesource.com/platform/development/+/android16-release/samples/apkcachetest/)\napp for testing APK cache.\n\n1. Build the app by running this command from the root directory: \n\n make ApkCacheTest\n\n2. Install the app as a privileged app. (Remember, only privileged apps can access the APK cache.) This requires a rooted device: \n\n adb root && adb remount\n adb shell mkdir /system/priv-app/ApkCacheTest\n adb push $ANDROID_PRODUCT_OUT/data/app/ApkCacheTest/ApkCacheTest.apk /system/priv-app/ApkCacheTest/\n adb shell stop && adb shell start\n\n3. Simulate the file cache directory and its content if needed (also requiring root privileges): \n\n adb shell mkdir -p /data/preloads/file_cache/com.android.apkcachetest\n adb shell restorecon -r /data/preloads\n adb shell \"echo \"Test File\" \u003e /data/preloads/file_cache/com.android.apkcachetest/test.txt\"\n\n4. Test the app. After installing the app and creating test `file_cache` directory, open the ApkCacheTest app. It should show one file `test.txt` and its contents. See this screenshot to see how these results appear in the user interface.\n\n **Figure 1.** ApkCacheTest results."]]