APK-Caching

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

Auf neuen A/B-partitionierten Geräten können OEMs Vorabinstallationen und beliebte Apps im APK-Cache platzieren, der sich in der meist leeren B-Partition befindet, ohne den für Nutzer sichtbaren Datenbereich zu beeinträchtigen. Durch den APK-Cache auf dem Gerät sind neue oder kürzlich auf die Werkseinstellungen zurückgesetzte Geräte fast sofort einsatzbereit, ohne dass APK-Dateien von Google Play heruntergeladen werden müssen.

Anwendungsfälle

  • Vorab geladene Apps in Partition B speichern, um die Einrichtung zu beschleunigen
  • Beliebte Apps in Partition B speichern, um sie schneller wiederherstellen zu können

Voraussetzungen

Damit diese Funktion genutzt werden kann, muss das Gerät Folgendes bieten:

  • Android 8.1 (O MR1) ist installiert.
  • A/B-Aufteilung implementiert

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

Daher kann der APK-Cache nicht über OTA aktualisiert werden. Er kann nur in einer Fabrik vorab geladen werden. Das Zurücksetzen auf die Werkseinstellungen wirkt sich nur auf die Partition „/data“ aus. Die B-Partition des Systems enthält weiterhin die vorinstallierten Inhalte, bis das OTA-Image heruntergeladen wurde. Nach dem Zurücksetzen auf die Werkseinstellungen wird das System noch einmal neu gestartet. Das bedeutet, dass das APK-Caching nicht verfügbar ist, wenn das OTA-Image auf 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 aus der B-Partition kopiert.

Nachteil: Erfordert Speicherplatz auf der B-Partition. Das Booten nach dem Zurücksetzen auf die Werkseinstellungen dauert länger, da vorinstallierte Inhalte kopiert werden müssen.

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

Um diese Funktion zu implementieren, müssen Sie die folgenden gerätespezifischen Änderungen vornehmen. Hier ist ein Beispiel aus Marlin:

  1. Fügen Sie das Skript, mit dem die Dateien kopiert werden, der Datei device-common.mk (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
    
    Beispielskriptquelle: device/google/marlin/preloads_copy.sh
  2. Bearbeiten Sie die Datei init.common.rc so, dass das erforderliche Verzeichnis /data/preloads und die 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 die init-Dateiquelle: device/google/marlin/init.common.rc
  3. Definieren Sie eine neue SELinux-Domain in der Datei 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;
    
    Eine Beispieldatei für die SELinux-Domain finden Sie unter /device/google/marlin/+/android16-release/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 Beispielkontextdatei für SELinux finden Sie unter device/google/marlin/sepolicy/preloads_copy.te.
  5. Zur Build-Zeit muss das Verzeichnis mit 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)
    
    Dies ist ein Beispiel für eine Änderung in einer Makefile, die das Kopieren von APK-Cache-Ressourcen aus dem Git-Repository des Anbieters (in unserem Fall vendor/google_devices/marlin/preloads) an den Speicherort auf der Partition „system_other“ ermöglicht, der später beim ersten Start des Geräts nach /data/preloads kopiert wird. Dieses Skript wird zur Build-Zeit ausgeführt, um das Image „system_other“ vorzubereiten. Vorinstallierte Inhalte werden unter „vendor/google_devices/marlin/preloads“ erwartet. Der OEM kann den tatsächlichen Repository-Namen bzw. -Pfad kostenlos wählen.
  6. Der APK-Cache befindet sich in /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 einen beliebigen Implementierungsansatz wählen, solange die endgültige Dateistruktur der oben beschriebenen entspricht.

Ansatz 2. Inhalte auf dem Bild mit Nutzerdaten, das im Werk aufgespielt wurde

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

Vorteil: Funktioniert sofort. Es sind keine Geräteanpassungen erforderlich, um Dateien beim ersten Start zu kopieren. In der Partition /data sind bereits Inhalte vorhanden.

Nachteil: Vorinstallierte Inhalte gehen nach dem Zurücksetzen auf die Werkseinstellungen verloren. Für einige ist das vielleicht akzeptabel, für OEMs, die Geräte nach der Qualitätskontrolle auf die Werkseinstellungen zurücksetzen, jedoch nicht immer.

Der Klasse android.content.Context wurde eine neue @SystemApi-Methode, getPreloadsFileCache(), hinzugefügt. Es wird ein absoluter Pfad zu einem app-spezifischen Verzeichnis im vorab geladenen Cache zurückgegeben.

Es wurde eine neue Methode, IPackageManager.deletePreloadsFileCache, hinzugefügt, mit der das Vorabladungsverzeichnis gelöscht werden kann, um den gesamten Speicherplatz freizugeben. Die Methode kann nur von Apps mit SYSTEM_UID aufgerufen werden, d.h. vom Systemserver oder von den Einstellungen.

App-Vorbereitung

Nur Apps mit Berechtigungen können auf das Cache-Verzeichnis für Preloads zugreifen. Für diesen Zugriff 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, um den APK-Cache zu testen.

  1. Erstellen Sie die App, indem Sie diesen Befehl im Stammverzeichnis ausführen:
    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 Dateicacheverzeichnis 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. Öffnen Sie nach der Installation der App und dem Erstellen des Testverzeichnisses file_cache die App „ApkCacheTest“. Sie sollte eine Datei test.txt und deren Inhalt anzeigen. Auf diesem Screenshot sehen Sie, wie diese Ergebnisse in der Benutzeroberfläche angezeigt werden.

    Abbildung 1: ApkCacheTest-Ergebnisse.