Memorizzazione nella cache dell'APK

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

Gli OEM possono inserire app precaricate e popolari nella cache APK archiviata nella partizione B per lo più vuota sui nuovi dispositivi con partizione A/B senza influire sullo spazio dati rivolto agli utenti. Avendo una cache APK disponibile sul dispositivo, i dispositivi nuovi o su cui è stato eseguito di recente il ripristino dei dati di fabbrica sono pronti per l'uso quasi immediatamente, senza dover scaricare i file APK da Google Play.

Casi d'uso

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

Prerequisiti

Per utilizzare questa funzionalità, il dispositivo deve avere:

  • È installata la release Android 8.1 (O MR1)
  • Partizione A/B implementata

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 delle immagini di sistema, ma contenuti precaricati come risorse demo per la vendita al dettaglio, file OAT e la cache APK. Dopo che le risorse sono state copiate nella partizione /data (questo avviene al 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 APK non può essere aggiornata tramite OTA; può essere precaricata solo in fabbrica. Il ripristino dei dati di fabbrica interessa solo la partizione /data. La partizione B del sistema contiene ancora i contenuti precaricati fino a quando 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 dell'APK non è disponibile se l'immagine OTA viene scaricata nella partizione B e poi il dispositivo viene ripristinato alle impostazioni di fabbrica.

Implementazione

Approccio 1. Contenuti sulla partizione system_other

Vantaggio: i contenuti preinstallati non vengono persi dopo il ripristino dei dati di fabbrica, ma vengono copiati dalla partizione B dopo il riavvio.

Con: richiede spazio nella partizione B. L'avvio dopo il ripristino dei dati di fabbrica richiede un tempo aggiuntivo per copiare i contenuti pre caricati.

Affinché i pre-caricamenti 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 (percorso al punto di montaggio di sola lettura per la partizione system_b):

Per implementare questa funzionalità, apporta le seguenti modifiche specifiche del dispositivo. Ecco un example da Marlin:

  1. Aggiungi lo script che esegue la copia al file device-common.mk (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
    
    Puoi trovare il codice sorgente 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
    
    Puoi trovare un esempio di codice sorgente del file init 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;
    
    Puoi trovare un file di dominio SELinux di esempio all'indirizzo: /device/google/marlin/+/main/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
    
    Puoi trovare un file di contesti SELinux di esempio all'indirizzo: device/google/marlin/sepolicy/preloads_copy.te
  5. Al momento della 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 file Makefile che consente di copiare le risorse della cache APK dal repository Git del fornitore (nel nostro caso era vendor/google_devices/marlin/preloads) alla posizione nella partizione system_other che in seguito verrà copiata in /data/preloads quando il dispositivo si avvia per la prima volta. Questo script viene eseguito in fase 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/il percorso del repository effettivo.
  6. La cache 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 di directory finale sui dispositivi. Gli OEM sono liberi di scegliere qualsiasi approccio di implementazione, a condizione che la struttura del file finale segua quella descritta sopra.

Approccio 2. Contenuti sull'immagine data dell'utente visualizzata in fabbrica

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

Vantaggio: funziona subito, non è necessario apportare personalizzazioni al dispositivo per copiare i file al primo avvio. I contenuti sono già nella partizione /data.

Svantaggio: i contenuti preinstallati vengono persi dopo un ripristino dei dati di fabbrica. Anche se questo potrebbe essere accettabile per alcuni, potrebbe non funzionare sempre per gli OEM che ripristinano i dati di fabbrica dei dispositivi dopo aver eseguito ispezioni di controllo qualità.

È stato aggiunto un nuovo metodo @SystemApi, getPreloadsFileCache(), a 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 dei pre-caricamenti per recuperare tutto lo spazio. Il metodo può essere chiamato solo dalle app con SYSTEM_UID, ovvero il server di sistema o Impostazioni.

Preparazione dell'app

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

Convalida

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

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

  1. Compila l'app eseguendo questo comando dalla directory principale:
    make ApkCacheTest
    
  2. Installa l'app come app privilegiata. Ricorda che solo le app privilegiate possono accedere alla cache APK. Per farlo, è 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. Simula la directory della cache dei file e i relativi contenuti, se necessario (sono richiesti 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 di test file_cache, apri l'app ApkCacheTest. Dovresti visualizzare un file test.txt e i relativi contenuti. Guarda questo screenshot per vedere come vengono visualizzati questi risultati nell'interfaccia utente.

    Figura 1. Risultati di ApkCacheTest.