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

В этом документе описывается разработка решения для кэширования APK-файлов, позволяющего быстро устанавливать предустановленные приложения на устройство, поддерживающее разделы A/B.

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

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

  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/+/android17-release/sepolicy/preloads_copy.te
  4. Зарегистрируйте домен в новом /sepolicy/file_contexts file:
    /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. Он ожидает, что предварительно загруженный контент будет доступен в vendor/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/
    
    Это окончательная структура каталогов на устройствах. Производители оборудования могут свободно выбирать любой подход к реализации, при условии, что окончательная структура файлов будет соответствовать описанной выше.

Подход 2. Содержимое образа пользовательских данных, прошиваемого на заводе.

Этот альтернативный подход предполагает, что предварительно загруженный контент уже находится в каталоге /data/preloads на разделе /data .

Плюсы : Работает сразу после установки — нет необходимости вносить изменения в устройство для копирования файлов при первом запуске. Содержимое уже находится в разделе /data .

Минус : Предустановленный контент теряется после сброса до заводских настроек. Хотя для некоторых это может быть приемлемо, это не всегда работает для производителей, которые выполняют сброс устройств до заводских настроек после проведения проверок качества.

В класс android.content.Context добавлен новый метод @SystemApi, getPreloadsFileCache() . Он возвращает абсолютный путь к каталогу, специфичному для приложения, в предварительно загруженном кэше.

Добавлен новый метод IPackageManager.deletePreloadsFileCache , позволяющий удалить каталог preloads для освобождения всего пространства. Этот метод могут вызывать только приложения с SYSTEM_UID, то есть системный сервер или Settings.

подготовка приложения

Доступ к каталогу кэша предварительной загрузки имеют только привилегированные приложения. Для этого приложения должны быть установлены в каталог /system/priv-app .

Валидация

  • После первой загрузки устройство должно содержать содержимое в каталоге /data/preloads/file_cache .
  • Содержимое каталога file_cache/ необходимо удалить, если на устройстве заканчивается место для хранения данных.

Для тестирования кэша APK используйте пример приложения ApkCacheTest .

  1. Соберите приложение, выполнив следующую команду из корневого каталога:
    make ApkCacheTest
    
  2. Установите приложение как приложение с привилегиями. (Помните, что доступ к кэшу APK имеют только приложения с привилегиями.) Для этого требуется устройство с правами root:
    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.