Mise en cache APK

Ce document décrit la conception d'une solution de mise en cache APK pour une installation rapide d'applications préchargées sur un appareil prenant en charge les partitions A/B.

Les OEM peuvent placer des préchargements et des applications populaires dans le cache APK stocké dans la partition B pratiquement vide sur les nouveaux appareils partitionnés A/B sans affecter l'espace de données destiné à l'utilisateur. Grâce à un cache APK disponible sur l'appareil, les appareils nouveaux ou récemment réinitialisés aux paramètres d'usine sont prêts à être utilisés presque immédiatement, sans avoir besoin de télécharger des fichiers APK depuis Google Play.

Cas d'utilisation

  • Stockez les applications préchargées dans la partition B pour une configuration plus rapide
  • Stockez les applications populaires dans la partition B pour une restauration plus rapide

Conditions préalables

Pour utiliser cette fonctionnalité, l'appareil a besoin de :

  • Version Android 8.1 (O MR1) installée
  • Partition A/B implémentée

Le contenu préchargé ne peut être copié que lors du premier démarrage. En effet, sur les appareils prenant en charge les mises à jour du système A/B, la partition B ne stocke pas réellement les fichiers d'image système, mais plutôt le contenu préchargé comme les ressources de démonstration au détail, les fichiers OAT et le cache APK. Une fois les ressources copiées sur la partition /data (cela se produit au premier démarrage), la partition B sera utilisée par les mises à jour en direct (OTA) pour télécharger les versions mises à jour de l'image système.

Par conséquent, le cache APK ne peut pas être mis à jour via OTA ; il ne peut être préchargé qu'en usine. La réinitialisation d'usine affecte uniquement la partition /data. La partition système B contient toujours le contenu préchargé jusqu'à ce que l'image OTA soit téléchargée. Après la réinitialisation d'usine, le système effectuera à nouveau le premier démarrage. Cela signifie que la mise en cache APK n'est pas disponible si l'image OTA est téléchargée sur la partition B, puis que l'appareil est réinitialisé aux paramètres d'usine.

Mise en œuvre

Approche 1. Contenu sur la partition system_other

Pro : Le contenu préchargé n'est pas perdu après la réinitialisation d'usine - il sera copié depuis la partition B après un redémarrage.

Inconvénient : Nécessite de l'espace sur la partition B. Le démarrage après la réinitialisation d'usine nécessite plus de temps pour copier le contenu préchargé.

Pour que les préchargements soient copiés lors du premier démarrage, le système appelle un script dans /system/bin/preloads_copy.sh . Le script est appelé avec un seul argument (chemin d'accès au point de montage en lecture seule pour la partition system_b ) :

Pour implémenter cette fonctionnalité, apportez ces modifications spécifiques à l’appareil. Voici un exemple de Marlin :

  1. Ajoutez le script qui effectue la copie dans le fichier device-common.mk (dans ce cas, device/google/marlin/device-common.mk ), comme ceci :
    # 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
    
    Recherchez un exemple de source de script sur : device/google/marlin /preloads_copy.sh
  2. Modifiez le fichier init.common.rc pour qu'il crée le répertoire et les sous-répertoires /data/preloads nécessaires :
    mkdir /data/preloads 0775 system system
    mkdir /data/preloads/media 0775 system system
    mkdir /data/preloads/demo 0775 system system
    
    Recherchez un exemple de source de fichier init à l'adresse : device/google/marlin/init.common.rc.
  3. Définissez un nouveau domaine SELinux dans le fichier 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;
    
    Trouvez un exemple de fichier de domaine SELinux à l'adresse : /device/google/marlin/+/main/sepolicy/preloads_copy.te
  4. Enregistrez le domaine dans un nouveau /sepolicy/file_contexts fichier :
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    Recherchez un exemple de fichier de contextes SELinux à l'adresse : device/google/marlin/sepolicy/preloads_copy.te
  5. Au moment de la construction, le répertoire avec le contenu préchargé doit être copié sur la partition 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)
    
    Ceci est un exemple de modification dans un Makefile qui permet de copier les ressources de cache APK à partir du référentiel Git du fournisseur (dans notre cas, il s'agissait de supplier/google_devices/ marlin/preloads) à l'emplacement sur la partition system_other qui sera ensuite copié dans /data/preloads lors du premier démarrage du périphérique. Ce script s'exécute au moment de la construction pour préparer l'image system_other. Il s'attend à ce que le contenu préchargé soit disponible dans supplier/google_devices/marlin/preloads. L'OEM est libre de choisir le nom/chemin d'accès réel du référentiel.
  6. Le cache APK se trouve dans /data/preloads/file_cache et a la disposition suivante :
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    Il s'agit de la structure de répertoires finale sur les appareils. Les OEM sont libres de choisir n’importe quelle approche de mise en œuvre à condition que la structure de fichier finale reproduise celle décrite ci-dessus.

Approche 2. Le contenu de l'image des données utilisateur flashé en usine

Cette approche alternative suppose que le contenu préchargé est déjà inclus dans le répertoire /data/preloads sur la partition /data .

Pro : Fonctionne immédiatement - pas besoin de personnaliser l'appareil pour copier les fichiers au premier démarrage. Le contenu se trouve déjà sur la partition /data .

Inconvénient : le contenu préchargé est perdu après une réinitialisation d'usine. Bien que cela puisse être acceptable pour certains, cela ne fonctionne pas toujours pour les constructeurs OEM qui réinitialisent leurs appareils après avoir effectué des inspections de contrôle qualité.

Une nouvelle méthode @SystemApi, getPreloadsFileCache() , a été ajoutée à android.content.Context . Il renvoie un chemin absolu vers un répertoire spécifique à l'application dans le cache préchargé.

Une nouvelle méthode, IPackageManager.deletePreloadsFileCache , a été ajoutée pour permettre de supprimer le répertoire de préchargement pour récupérer tout l'espace. La méthode ne peut être appelée que par les applications avec SYSTEM_UID, c'est-à-dire le serveur système ou les paramètres.

Préparation de l'application

Seules les applications privilégiées peuvent accéder au répertoire de cache de préchargements. Pour cet accès, les applications doivent être installées dans le répertoire /system/priv-app .

Validation

  • Après le premier démarrage, le périphérique doit avoir du contenu dans le répertoire /data/preloads/file_cache .
  • Le contenu du répertoire file_cache/ doit être supprimé si l'appareil manque de stockage.

Utilisez l'exemple d'application ApkCacheTest pour tester le cache APK.

  1. Créez l'application en exécutant cette commande à partir du répertoire racine :
    make ApkCacheTest
    
  2. Installez l'application en tant qu'application privilégiée. (N'oubliez pas que seules les applications privilégiées peuvent accéder au cache APK.) Cela nécessite un appareil 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. Simulez le répertoire du cache de fichiers et son contenu si nécessaire (nécessitant également les privilèges 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. Testez l'application. Après avoir installé l'application et créé le répertoire test file_cache , ouvrez l'application ApkCacheTest. Il devrait afficher un fichier test.txt et son contenu. Consultez cette capture d'écran pour voir comment ces résultats apparaissent dans l'interface utilisateur.

    Figure 1. Résultats d'ApkCacheTest