APK-Caching

In diesem Dokument wird das Design einer APK-Caching-Lösung für die schnelle Installation vorinstallierter Apps auf einem Gerät beschrieben, das A/B-Partitionen unterstützt.

OEMs können Preloads und beliebte Apps im APK-Cache ablegen, der sich auf neuen Geräten mit A/B-Partition in der größtenteils leeren B-Partition befindet, ohne den für Nutzer sichtbaren Datenspeicher zu beeinträchtigen. Wenn auf dem Gerät ein APK-Cache verfügbar ist, können neue oder vor Kurzem auf die Werkseinstellungen zurückgesetzte Geräte fast sofort verwendet werden, ohne dass APK-Dateien von Google Play heruntergeladen werden müssen.

Anwendungsfälle

  • Vorab geladene Apps in der B-Partition speichern, um die Einrichtung zu beschleunigen
  • Beliebte Apps in der B-Partition speichern, um sie schneller wiederherzustellen

Voraussetzungen

Für die Nutzung dieser Funktion muss das Gerät folgende Voraussetzungen erfüllen:

  • Android 8.1 (O MR1) installiert
  • A/B-Partition implementiert

Vorab geladene Inhalte können nur beim ersten Start kopiert werden. Das liegt daran, dass auf Geräten, die A/B-Systemupdates unterstützen, in der B-Partition keine System-Imagedateien gespeichert werden, sondern vorab geladene Inhalte wie Demoressourcen für den Einzelhandel, OAT-Dateien und der APK-Cache. Nachdem die Ressourcen in die Partition „/data“ kopiert wurden (dies geschieht beim ersten Start), wird die B-Partition von Over-the-air-Updates (OTA-Updates) zum Herunterladen aktualisierter Versionen des System-Images verwendet.

Daher kann der APK-Cache nicht über OTA aktualisiert werden, sondern nur in der Fabrik vorab geladen werden. Das Zurücksetzen auf die Werkseinstellungen wirkt sich nur auf die Partition „/data“ aus. Die System-B-Partition enthält weiterhin die vorab geladenen Inhalte, bis das OTA-Image heruntergeladen wurde. Nach dem Zurücksetzen auf die Werkseinstellungen wird das System noch einmal gestartet. Das bedeutet, dass das APK-Caching nicht verfügbar ist, wenn das OTA-Image in die B-Partition heruntergeladen und das Gerät dann auf die Werkseinstellungen zurückgesetzt wird.

Implementierung

Ansatz 1. Inhalte auf der Partition „system_other“

Vorteil: Vorinstallierte Inhalte gehen nach dem Zurücksetzen auf die Werkseinstellungen nicht verloren. Sie werden nach einem Neustart von der B-Partition kopiert.

Con: Erfordert Speicherplatz auf der B-Partition. Nach dem Zurücksetzen auf die Werkseinstellungen benötigt das Gerät zusätzliche Zeit, um vorab geladene Inhalte zu kopieren.

Damit Preloads beim ersten Start kopiert werden, ruft das System ein Script in /system/bin/preloads_copy.sh auf. Das Script wird mit einem einzigen Argument aufgerufen (Pfad zum schreibgeschützten Bereitstellungspunkt für die system_b-Partition):

Nehmen Sie die folgenden gerätespezifischen Änderungen vor, um diese Funktion zu implementieren. Hier ist ein Beispiel aus Marlin:

  1. Fügen Sie das Skript, das die Kopie erstellt, der device-common.mk-Datei (in diesem Fall device/google/marlin/device-common.mk) hinzu:
    # 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
    
    Beispiel-Scriptquelle: device/google/marlin/preloads_copy.sh
  2. Bearbeiten Sie die Datei init.common.rc, damit das erforderliche Verzeichnis /data/preloads und die erforderlichen Unterverzeichnisse erstellt werden:
    mkdir /data/preloads 0775 system system
    mkdir /data/preloads/media 0775 system system
    mkdir /data/preloads/demo 0775 system system
    
    Beispiel für eine init-Dateiquelle finden Sie unter: device/google/marlin/init.common.rc
  3. Definieren Sie in der Datei preloads_copy.te eine neue SELinux-Domain:
    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;
    
    Beispiel für eine SELinux-Domaindatei: /device/google/marlin/+/main/sepolicy/preloads_copy.te
  4. Registrieren Sie die Domain in einer neuen /sepolicy/file_contexts-Datei:
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    Eine Beispieldatei für SELinux-Kontexte finden Sie unter device/google/marlin/sepolicy/preloads_copy.te.
  5. Zum Zeitpunkt des Builds muss das Verzeichnis mit den vorab geladenen Inhalten in die Partition system_other kopiert werden:
    # 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)
    
    Das ist ein Beispiel für eine Änderung in einem Makefile, mit der APK-Cache-Ressourcen aus dem Git-Repository des Anbieters (in unserem Fall war es vendor/google_devices/marlin/preloads) an den Speicherort auf der Partition „system_other“ kopiert werden, von dem aus sie beim ersten Start des Geräts in /data/preloads kopiert werden. Dieses Script wird zum Zeitpunkt des Builds ausgeführt, um das Image „system_other“ vorzubereiten. Es wird davon ausgegangen, dass vorab bereitgestellte Inhalte unter „vendor/google_devices/marlin/preloads“ verfügbar sind. Der OEM kann den tatsächlichen Repository-Namen/-Pfad kostenlos wählen.
  6. Der APK-Cache befindet sich unter /data/preloads/file_cache und hat das folgende Layout:
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    Dies ist die endgültige Verzeichnisstruktur auf den Geräten. OEMs können jeden Implementierungsansatz wählen, solange die endgültige Dateistruktur der oben beschriebenen entspricht.

Ansatz 2. Inhalte auf dem vom Hersteller geflashten Nutzerdaten-Image

Bei diesem alternativen Ansatz wird davon ausgegangen, dass vorinstallierte Inhalte bereits im Verzeichnis /data/preloads auf der Partition /data enthalten sind.

Vorteile: Funktioniert sofort – keine Anpassungen am Gerät erforderlich, um Dateien beim ersten Start zu kopieren. Die Inhalte befinden sich bereits auf der Partition /data.

Nachteil: Vorinstallierte Inhalte gehen nach einem Zurücksetzen auf die Werkseinstellungen verloren. Das ist für einige zwar akzeptabel, funktioniert aber möglicherweise nicht immer für OEMs, die Geräte nach der Qualitätskontrolle auf die Werkseinstellungen zurücksetzen.

android.content.Context wurde die neue @SystemApi-Methode getPreloadsFileCache() hinzugefügt. Er gibt einen absoluten Pfad zu einem app-spezifischen Verzeichnis im vorab geladenen Cache zurück.

Die neue Methode IPackageManager.deletePreloadsFileCache ermöglicht das Löschen des Verzeichnisses „preloads“, um den gesamten Speicherplatz wiederherzustellen. Die Methode kann nur von Apps mit SYSTEM_UID aufgerufen werden, also vom Systemserver oder den Einstellungen.

App-Vorbereitung

Nur Apps mit Berechtigungen können auf das Cache-Verzeichnis für Vorabdaten zugreifen. Dazu müssen Apps im Verzeichnis /system/priv-app installiert sein.

Zertifizierungsstufe

  • Nach dem ersten Start sollte das Gerät Inhalte im Verzeichnis /data/preloads/file_cache haben.
  • Der Inhalt des Verzeichnisses file_cache/ muss gelöscht werden, wenn der Speicherplatz auf dem Gerät knapp wird.

Verwenden Sie die Beispiel-App ApkCacheTest zum Testen des APK-Caches.

  1. Erstellen Sie die App mit dem folgenden Befehl im Stammverzeichnis:
    make ApkCacheTest
    
  2. Installieren Sie die App als privilegierte App. Denken Sie daran, dass nur privilegierte Apps auf den APK-Cache zugreifen können. Dazu ist ein gerootetes Gerät erforderlich:
    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. Simulieren Sie bei Bedarf das Dateicache-Verzeichnis und seinen Inhalt (erfordert auch Root-Berechtigungen):
    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. Testen Sie die App. Nachdem Sie die App installiert und das Testverzeichnis file_cache erstellt haben, öffnen Sie die ApkCacheTest App. Es sollte eine Datei test.txt und deren Inhalt angezeigt werden. Auf diesem Screenshot sehen Sie, wie diese Ergebnisse in der Benutzeroberfläche angezeigt werden.

    Abbildung 1: ApkCacheTest-Ergebnisse