Кэширование APK

В этом документе описывается разработка решения для кэширования 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 ):

Чтобы реализовать эту функцию, внесите следующие изменения для конкретного устройства. Вот пример от Марлина:

  1. Добавьте сценарий, который выполняет копирование, в файл 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
  2. Отредактируйте файл 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
  3. Определите новый домен 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 .
  4. Зарегистрируйте домен в новом Файл /sepolicy/file_contexts :
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    Найдите пример файла контекстов SELinux по адресу: device/google/marlin/sepolicy/preloads_copy.te
  5. Во время сборки каталог с предварительно загруженным содержимым необходимо скопировать в раздел 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-производитель может свободно выбирать фактическое имя/путь к репозиторию.
  6. Кэш 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.

  1. Создайте приложение, выполнив эту команду из корневого каталога:
    make ApkCacheTest
    
  2. Установите приложение как привилегированное. (Помните, что только привилегированные приложения могут получить доступ к кешу 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
    
  3. При необходимости смоделируйте каталог файлового кэша и его содержимое (также требуются права 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"
    
  4. Протестируйте приложение. После установки приложения и создания тестового каталога file_cache откройте приложение ApkCacheTest. Он должен показать один файл test.txt и его содержимое. Посмотрите этот снимок экрана, чтобы увидеть, как эти результаты отображаются в пользовательском интерфейсе.

    Рисунок 1. Результаты ApkCacheTest.