En este documento, se describe el diseño de una solución de almacenamiento en caché de APK para la instalación rápida de apps precargadas en un dispositivo que admite particiones A/B.
Los OEMs pueden colocar las precargas y las apps populares en la memoria caché de APK almacenadas en la partición B, que está casi vacía, en dispositivos nuevos con particiones A/B sin afectar el espacio de datos del usuario. Cuando hay una caché de APK disponible en el dispositivo, los dispositivos nuevos o que se restablecieron a la configuración de fábrica recientemente están listos para usarse casi de inmediato, sin necesidad de descargar archivos APK de Google Play.
Casos de uso
- Almacena las apps cargadas previamente en la partición B para una configuración más rápida
- Almacena las apps populares en la partición B para un restablecimiento más rápido
Requisitos previos
Para usar esta función, el dispositivo debe tener lo siguiente:
- Se instaló la versión de Android 8.1 (O MR1)
- Se implementó la partición A/B
El contenido precargado solo se puede copiar durante el primer inicio. Esto se debe a que, en los dispositivos que admiten actualizaciones del sistema A/B, la partición B no almacena archivos de imagen del sistema, sino contenido precargado, como recursos de demostración de venta minorista, archivos OAT y la caché de APK. Después de que los recursos se copien en la partición /data (esto ocurre en el primer inicio), las actualizaciones por aire (OTA) usarán la partición B para descargar versiones actualizadas de la imagen del sistema.
Por lo tanto, la caché del APK no se puede actualizar a través de OTA; solo se puede precargar en una fábrica. El restablecimiento de la configuración de fábrica solo afecta a la partición /data. La partición B del sistema aún tiene el contenido precargado hasta que se descarga la imagen OTA. Después de restablecer la configuración de fábrica, el sistema volverá a realizar el primer inicio. Esto significa que el almacenamiento en caché de APK no está disponible si la imagen OTA se descarga en la partición B y, luego, se restablece la configuración de fábrica del dispositivo.
Implementación
Enfoque 1. Contenido de la partición system_other
Pro: El contenido precargado no se pierde después del restablecimiento de la configuración de fábrica, sino que se copia de la partición B después de un reinicio.
Con: Requiere espacio en la partición B. El inicio después del restablecimiento de la configuración de fábrica requiere tiempo adicional para copiar el contenido precargado.
Para que se copien las cargas previas durante el primer inicio, el sistema llama a una secuencia de comandos en /system/bin/preloads_copy.sh
. Se llama a la secuencia de comandos con un solo argumento (la ruta de acceso al punto de activación de solo lectura para la partición system_b
):
Para implementar esta función, realiza estos cambios específicos del dispositivo. Este es un ejemplo de Marlin:
- Agrega la secuencia de comandos que realiza la copia al archivo
device-common.mk
(en este caso,device/google/marlin/device-common.mk
), de la siguiente manera: Encuentra la fuente de la secuencia de comandos de ejemplo en: device/google/marlin/preloads_copy.sh# 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
- Edita el archivo
init.common.rc
para que cree el directorio y los subdirectorios/data/preloads
necesarios: Encuentra un ejemplo de la fuente de archivosmkdir /data/preloads 0775 system system
mkdir /data/preloads/media 0775 system system
mkdir /data/preloads/demo 0775 system system
init
en: device/google/marlin/init.common.rc - Define un nuevo dominio de SELinux en el archivo
preloads_copy.te
: Encuentra un ejemplo de archivo de dominio de SELinux en: /device/google/marlin/+/main/sepolicy/preloads_copy.tetype 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;
- Registra el dominio en un nuevo archivo
:/sepolicy/file_contexts Encuentra un ejemplo de archivo de contexto de SELinux en: device/google/marlin/sepolicy/preloads_copy.te/system/bin/preloads_copy\.sh u:object_r:preloads_copy_exec:s0
- En el momento de la compilación, el directorio con el contenido precargado se debe copiar en la partición
system_other
: Este es un ejemplo de un cambio en un Makefile que permite copiar recursos de caché de APK del repositorio de Git del proveedor (en nuestro caso, era vendor/google_devices/marlin/preloads) a la ubicación en la partición system_other que luego se copiará en /data/preloads cuando el dispositivo se inicie por primera vez. Esta secuencia de comandos se ejecuta en el tiempo de compilación para preparar la imagen system_other. Espera que el contenido precargado esté disponible en vendor/google_devices/marlin/preloads. El OEM puede elegir el nombre o la ruta de acceso del repositorio real.# 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)
- La caché del APK se encuentra en
/data/preloads/file_cache
y tiene el siguiente diseño: Esta es la estructura de directorio final en los dispositivos. Los OEMs pueden elegir cualquier enfoque de implementación, siempre que la estructura de archivos final replique la que se describió anteriormente./data/preloads/file_cache/ app.package.name.1/ file1 fileN app.package.name.N/
Enfoque 2. Contenido de la imagen de datos del usuario que se grabó en la fábrica
En este enfoque alternativo, se da por sentado que el contenido precargado ya está incluido en el directorio /data/preloads
de la partición /data
.
Pro: Funciona de inmediato, no es necesario realizar personalizaciones del dispositivo para copiar archivos en el primer inicio. El contenido ya está en la partición /data
.
Desventaja: El contenido precargado se pierde después de un restablecimiento de la configuración de fábrica. Si bien esto puede ser aceptable para algunos, es posible que no siempre funcione para los OEM que restablecen la configuración de fábrica de los dispositivos después de realizar inspecciones de control de calidad.
Se agregó un nuevo método @SystemApi, getPreloadsFileCache()
, a android.content.Context
. Devuelve una ruta de acceso absoluta a un directorio específico de la app en la caché precargada.
Se agregó un método nuevo, IPackageManager.deletePreloadsFileCache
, que permite borrar el directorio de cargas previas para recuperar todo el espacio. Solo las apps con SYSTEM_UID, es decir, el servidor del sistema o la configuración, pueden llamar al método.
Preparación de la app
Solo las apps con privilegios pueden acceder al directorio de la caché de cargas previas. Para ese acceso, las apps deben estar instaladas en el directorio /system/priv-app
.
Validación
- Después del primer inicio, el dispositivo debería tener contenido en el directorio
/data/preloads/file_cache
. - Se debe borrar el contenido del directorio
file_cache/
si el dispositivo tiene poco espacio de almacenamiento.
Usa la app de ejemplo ApkCacheTest para probar la caché de APK.
- Ejecuta el siguiente comando desde el directorio raíz para compilar la app:
make ApkCacheTest
- Instala la app como una app con privilegios. (Recuerda que solo las apps con privilegios pueden acceder a la caché del APK).
Para ello, se requiere un dispositivo con permisos de administrador:
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
- Simula el directorio de la caché de archivos y su contenido si es necesario (también requiere privilegios de raíz):
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"
- Prueba la app. Después de instalarla y crear el directorio
file_cache
de prueba, abre la app de ApkCacheTest. Debería mostrar un archivotest.txt
y su contenido. Consulta esta captura de pantalla para ver cómo aparecen estos resultados en la interfaz de usuario.
Figura 1: Resultados de ApkCacheTest.