В этом документе описывается разработка решения для кэширования APK для быстрой установки предварительно загруженных приложений на устройство, поддерживающее разделы A/B.
OEM-производители могут размещать предварительные загрузки и популярные приложения в кэше APK, хранящемся в практически пустом разделе B на новых устройствах , разделенных на A/B, не затрагивая при этом какое-либо пространство данных, доступное пользователю. Благодаря наличию кэша APK на устройстве новые или устройства, недавно сброшенные до заводских настроек, готовы к использованию практически сразу, без необходимости загружать APK-файлы из Google Play.
Случаи использования
- Храните предварительно загруженные приложения в разделе B для более быстрой настройки.
- Храните популярные приложения в разделе B для более быстрого восстановления.
Предварительные условия
Чтобы использовать эту функцию, устройству необходимо:
- Установлена версия Android 8.1 (O MR1)
- Раздел A/B реализован
Предварительно загруженный контент можно скопировать только во время первой загрузки. Это связано с тем, что на устройствах, поддерживающих обновления системы A/B, раздел B фактически не хранит файлы образов системы, а вместо этого предварительно загружает контент, такой как розничные демонстрационные ресурсы, файлы OAT и кэш APK. После копирования ресурсов в раздел /data (это происходит при первой загрузке), раздел B будет использоваться обновлениями по беспроводной сети (OTA) для загрузки обновленных версий образа системы.
Следовательно, кэш APK не может быть обновлен через OTA; его можно предустановить только на заводе. Сброс к заводским настройкам влияет только на раздел /data. Раздел системы B по-прежнему содержит предварительно загруженное содержимое до тех пор, пока не будет загружен образ OTA. После сброса настроек система снова выполнит первую загрузку. Это означает, что кэширование APK недоступно, если OTA-образ загружен в раздел B, а затем на устройстве выполнен сброс настроек.
Выполнение
Подход 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 - Определите новый домен SELinux в файле
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;
Пример файла домена SELinux можно найти по адресу: /device/google/marlin/+/main/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, которое позволяет копировать ресурсы кэша APK из репозитория Git поставщика (в нашем случае это былvendor/google_devices/ marlin/preloads) в раздел system_other, который позже будет скопирован в /data/preloads при первой загрузке устройства. Этот сценарий запускается во время сборки для подготовки образа system_other. Он ожидает, что предварительно загруженный контент будет доступен в вендоре/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/preloads
раздела /data
.
Плюсы : работает «из коробки» — не нужно настраивать устройство для копирования файлов при первой загрузке. Содержимое уже находится в разделе /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