Memorizzazione nella cache dell'APK

Questo documento descrive la progettazione di una soluzione di memorizzazione nella cache degli APK per l'installazione rapida di app precaricate su un dispositivo che supporta le partizioni A/B.

Gli OEM possono inserire le app precaricate e quelle più usate nella cache degli APK memorizzata nella partizione B, per lo più vuota, sui nuovi dispositivi con partizioni A/B senza influire sullo spazio dati visibile all'utente. Grazie alla cache degli APK disponibile sul dispositivo, i dispositivi nuovi o di cui è stato ripristinato di recente lo stato di fabbrica sono pronti all'uso quasi immediatamente, senza dover scaricare i file APK da Google Play.

Casi d'uso

  • Memorizzare le app precaricate nella partizione B per una configurazione più rapida
  • Memorizzare le app più usate nella partizione B per un ripristino più rapido

Prerequisiti

Per utilizzare questa funzionalità, il dispositivo deve:

  • Avere installata la release di Android 8.1 (O MR1)
  • Avere implementato la partizione A/B

I contenuti precaricati possono essere copiati solo durante il primo avvio. Questo perché sui dispositivi che supportano gli aggiornamenti di sistema A/B, la partizione B non memorizza effettivamente i file immagine di sistema, ma i contenuti precaricati come le risorse demo per la vendita al dettaglio, i file OAT e la cache degli APK. Dopo che le risorse sono state copiate nella partizione /data (durante il primo avvio), la partizione B verrà utilizzata dagli aggiornamenti over-the-air (OTA) per scaricare le versioni aggiornate dell'immagine di sistema.

Pertanto, la cache degli APK non può essere aggiornata tramite OTA; può essere precaricata solo in fabbrica. Il ripristino dei dati di fabbrica influisce solo sulla partizione /data. La partizione B del sistema contiene ancora i contenuti precaricati finché non viene scaricata l'immagine OTA. Dopo il ripristino dei dati di fabbrica, il sistema eseguirà di nuovo il primo avvio. Ciò significa che la memorizzazione nella cache degli APK non è disponibile se l'immagine OTA viene scaricata nella partizione B e poi vengono ripristinati i dati di fabbrica del dispositivo.

Implementazione

Approccio 1. Contenuti nella partizione system_other

Pro: i contenuti precaricati non vengono persi dopo il ripristino dei dati di fabbrica: verranno copiati dalla partizione B dopo un riavvio.

Contro: richiede spazio nella partizione B. L'avvio dopo il ripristino dei dati di fabbrica richiede più tempo per copiare i contenuti precaricati.

Affinché i contenuti precaricati vengano copiati durante il primo avvio, il sistema chiama uno script in /system/bin/preloads_copy.sh. Lo script viene chiamato con un singolo argomento (il percorso del punto di montaggio di sola lettura per la partizione system_b):

Per implementare questa funzionalità, apporta queste modifiche specifiche del dispositivo. Ecco un esempio di Marlin:

  1. Aggiungi lo script che esegue la copia al device-common.mk file (in questo caso, device/google/marlin/device-common.mk), come segue:
    # 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
    
    Trova il codice dello script di esempio all'indirizzo: device/google/marlin/preloads_copy.sh
  2. Modifica il file init.common.rc in modo che crei la directory e le sottodirectory /data/preloads necessarie:
    mkdir /data/preloads 0775 system system
    mkdir /data/preloads/media 0775 system system
    mkdir /data/preloads/demo 0775 system system
    
    Trova il codice del file init di esempio all'indirizzo: device/google/marlin/init.common.rc
  3. Definisci un nuovo dominio SELinux nel file 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;
    
    Trova un file di dominio SELinux di esempio all'indirizzo: /device/google/marlin/+/android17-release/sepolicy/preloads_copy.te
  4. Registra il dominio in un nuovo file /sepolicy/file_contexts:
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    Trova un file di contesti SELinux di esempio all'indirizzo: device/google/marlin/sepolicy/preloads_copy.te
  5. Al tempo di compilazione, la directory con i contenuti precaricati deve essere copiata nella partizione 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)
    
    Questo è un esempio di modifica in un Makefile che consente di copiare le risorse della cache degli APK dal repository Git del fornitore (nel nostro caso vendor/google_devices/marlin/preloads) nella posizione della partizione system_other che verrà copiata in /data/preloads al primo avvio del dispositivo. Questo script viene eseguito al tempo di compilazione per preparare l'immagine system_other. Si prevede che i contenuti precaricati siano disponibili in vendor/google_devices/marlin/preloads. L'OEM è libero di scegliere il nome/percorso effettivo del repository.
  6. La cache degli APK si trova in /data/preloads/file_cache e ha il seguente layout:
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    Questa è la struttura finale delle directory sui dispositivi. Gli OEM sono liberi di scegliere qualsiasi approccio di implementazione, purché la struttura finale dei file sia uguale a quella descritta sopra.

Approccio 2. Contenuti nell'immagine dei dati utente caricata in fabbrica

Questo approccio alternativo presuppone che i contenuti precaricati siano già inclusi in nella directory /data/preloads nella partizione /data.

Pro: funziona subito, senza dover apportare personalizzazioni al dispositivo per copiare i file al primo avvio. I contenuti si trovano già nella partizione /data.

Contro: i contenuti precaricati vengono persi dopo il ripristino dei dati di fabbrica. Sebbene questo possa essere accettabile per alcuni, potrebbe non funzionare sempre per gli OEM che ripristinano i dati di fabbrica dei dispositivi dopo aver eseguito i controlli di qualità.

È stato aggiunto un nuovo metodo @SystemApi, getPreloadsFileCache(), ad android.content.Context. Restituisce un percorso assoluto a una directory specifica dell'app nella cache precaricata.

È stato aggiunto un nuovo metodo, IPackageManager.deletePreloadsFileCache, che consente di eliminare la directory preloads per recuperare tutto lo spazio. Il metodo può essere chiamato solo dalle app con SYSTEM_UID, ad es. il server di sistema o Impostazioni.

Preparazione dell'app

Solo le app con privilegi possono accedere alla directory della cache preloads. Per questo accesso, le app devono essere installate nella directory /system/priv-app.

Convalida

  • Dopo il primo avvio, il dispositivo deve avere contenuti nella directory /data/preloads/file_cache.
  • I contenuti nella directory file_cache/ devono essere eliminati se lo spazio di archiviazione del dispositivo è insufficiente.

Utilizza l'app di esempio ApkCacheTest per testare la cache degli APK.

  1. Crea l'app eseguendo questo comando dalla directory principale:
    make ApkCacheTest
    
  2. Installa l'app come app con privilegi. Ricorda che solo le app con privilegi possono accedere alla cache degli APK. Per questa operazione è necessario un dispositivo rooted:
    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. Se necessario, simula la directory della cache dei file e i relativi contenuti (richiede anche i privilegi di 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. Testa l'app. Dopo aver installato l'app e creato la directory file_cache di test, apri l'app ApkCacheTest. Dovrebbe mostrare un file test.txt e i relativi contenuti. Consulta questo screenshot per vedere come vengono visualizzati questi risultati nell'interfaccia utente.

    Figura 1. Risultati di ApkCacheTest.