Modifiche del comportamento di Android 7.0

Oltre a nuove funzionalità e capacità, Android 7.0 include una serie di modifiche al comportamento del sistema e delle API. Questo documento evidenzia alcune delle modifiche principali che devi comprendere e di cui devi tenere conto nelle tue app.

Se hai già pubblicato un'app per Android, tieni presente che la tua app potrebbe essere interessata da queste modifiche alla piattaforma.

Batteria e memoria

Android 7.0 include modifiche al comportamento del sistema volte a migliorare la durata della batteria dei dispositivi e a ridurre l'utilizzo della RAM. Queste modifiche possono influire sull'accesso della tua app alle risorse di sistema, nonché sul modo in cui l'app interagisce con altre app utilizzando determinati intent impliciti.

Sospensione

Introdotta in Android 6.0 (livello API 23), la modalità Doze migliora la durata della batteria posticipando le attività della CPU e della rete quando un utente lascia un dispositivo scollegato, fermo e con lo schermo spento. Android 7.0 apporta ulteriori miglioramenti a Doze applicando un sottoinsieme di limitazioni della CPU e della rete mentre il dispositivo è scollegato con lo schermo spento, ma non necessariamente fermo, ad esempio quando un telefono è in viaggio nella tasca di un utente.

Illustrazione di come Doze applica un primo livello di limitazioni dell'attività di sistema per migliorare la durata della batteria

Figura 1. Illustrazione di come Doze applica un primo livello di limitazioni dell'attività di sistema per migliorare la durata della batteria.

Quando un dispositivo è alimentato a batteria e lo schermo è spento per un certo periodo di tempo, il dispositivo entra in modalità di sospensione e applica il primo sottoinsieme di limitazioni: disattiva l'accesso alla rete delle app e posticipa i job e le sincronizzazioni. Se il dispositivo rimane fermo per un determinato periodo di tempo dopo l'attivazione di Doze, il sistema applica il resto delle limitazioni di Doze a PowerManager.WakeLock, sveglie AlarmManager, GPS e scansioni Wi-Fi. Indipendentemente dal fatto che vengano applicate alcune o tutte le limitazioni di Doze, il sistema riattiva il dispositivo per brevi periodi di manutenzione, durante i quali alle applicazioni è consentito l'accesso alla rete e possono eseguire eventuali job/sincronizzazioni differiti.

Illustrazione di come Doze applica un secondo livello di limitazioni dell'attività di sistema dopo che il dispositivo è rimasto fermo per un determinato periodo di tempo

Figura 2. Illustrazione di come Doze applica un secondo livello di limitazioni dell'attività di sistema dopo che il dispositivo è rimasto fermo per un determinato periodo di tempo.

Tieni presente che l'attivazione dello schermo o il collegamento del dispositivo interrompe la modalità di sospensione e rimuove queste limitazioni di elaborazione. Il comportamento aggiuntivo non influisce sui consigli e sulle best practice per l'adattamento della tua app alla versione precedente di Doze introdotta in Android 6.0 (livello API 23), come descritto in Ottimizzazione per Doze e Standby delle app. Devi comunque seguire questi consigli, ad esempio utilizzare Firebase Cloud Messaging (FCM) per inviare e ricevere messaggi, e iniziare a pianificare gli aggiornamenti per adattarli al comportamento aggiuntivo di Doze.

Project Svelte: ottimizzazioni in background

Android 7.0 rimuove tre trasmissioni implicite per ottimizzare l'utilizzo della memoria e il consumo energetico. Questa modifica è necessaria perché le trasmissioni implicite spesso avviano app che si sono registrate per ascoltarle in background. La rimozione di queste trasmissioni può migliorare notevolmente le prestazioni del dispositivo e l'esperienza utente.

I dispositivi mobili subiscono frequenti variazioni di connettività, ad esempio quando passano dal Wi-Fi ai dati mobili. Al momento, le app possono monitorare le modifiche alla connettività registrando un broadcast receiver per la trasmissione implicita CONNECTIVITY_ACTION nel proprio manifest. Poiché molte app si registrano per ricevere questa trasmissione, un singolo switch di rete può causare l'attivazione di tutte le app e l'elaborazione della trasmissione contemporaneamente.

Analogamente, nelle versioni precedenti di Android, le app potevano registrarsi per ricevere trasmissioni ACTION_NEW_PICTURE e ACTION_NEW_VIDEO implicite da altre app, ad esempio Fotocamera. Quando un utente scatta una foto con l'app Fotocamera, queste app si attivano per elaborare la trasmissione.

Per alleviare questi problemi, Android 7.0 applica le seguenti ottimizzazioni:

Se la tua app utilizza uno di questi intent, devi rimuovere le dipendenze da questi il prima possibile in modo da poter scegliere come target i dispositivi Android 7.0 correttamente. Il framework Android fornisce diverse soluzioni per ridurre la necessità di queste trasmissioni implicite. Ad esempio, l'API JobScheduler fornisce un meccanismo efficace per pianificare le operazioni di rete quando vengono soddisfatte condizioni specifiche, come la connessione a una rete non a consumo. Puoi anche utilizzare JobScheduler per reagire alle modifiche ai provider di contenuti.

Per ulteriori informazioni sulle ottimizzazioni in background in Android 7.0 (livello API 24) e su come adattare la tua app, consulta Ottimizzazioni in background.

Modifiche alle autorizzazioni

Android 7.0 include modifiche alle autorizzazioni che potrebbero influire sulla tua app.

Modifiche alle autorizzazioni del file system

Per migliorare la sicurezza dei file privati, la directory privata delle app che hanno come target Android 7.0 o versioni successive ha accesso limitato (0700). Questa impostazione impedisce la fuga di metadati dei file privati, ad esempio le dimensioni o l'esistenza. Questa modifica delle autorizzazioni ha diversi effetti collaterali:

Condivisione di file tra app

Per le app che hanno come target Android 7.0, il framework Android applica la policy dell'API StrictMode che vieta l'esposizione degli URI file:// all'esterno dell'app. Se un intent contenente un URI file esce dall'app, l'app non va a buon fine con un'eccezione FileUriExposedException.

Per condividere file tra applicazioni, devi inviare un URI content:// e concedere un'autorizzazione di accesso temporaneo all'URI. Il modo più semplice per concedere questa autorizzazione è utilizzare la classe FileProvider. Per ulteriori informazioni sulle autorizzazioni e sulla condivisione dei file, consulta Condivisione dei file.

Accessibilità migliorata

Android 7.0 include modifiche volte a migliorare l'usabilità della piattaforma per gli utenti con disabilità visiva o ipovedenti. In genere, queste modifiche non dovrebbero richiedere modifiche al codice della tua app, ma dovresti esaminare queste funzionalità e testarle con la tua app per valutare i potenziali impatti sull'esperienza utente.

Zoom schermo

Android 7.0 consente agli utenti di impostare le dimensioni di visualizzazione, che ingrandiscono o riducono tutti gli elementi sullo schermo, migliorando così l'accessibilità del dispositivo per gli utenti ipovedenti. Gli utenti non possono aumentare lo zoom dello schermo oltre una larghezza minima dello schermo di sw320dp, che è la larghezza di un Nexus 4, un comune smartphone di medie dimensioni.

Schermata che mostra le dimensioni di visualizzazione non ingrandite del dispositivo con un'immagine di sistema Android 7.0
Schermata che mostra l'effetto dell'aumento delle dimensioni di visualizzazione di un dispositivo con un'immagine di sistema Android 7.0

Figura 3. La schermata a destra mostra l'effetto dell'aumento delle dimensioni di visualizzazione di un dispositivo che esegue un'immagine di sistema Android 7.0.

Quando la densità del dispositivo cambia, il sistema invia una notifica alle app in esecuzione nei seguenti modi:

  • Se un'app ha come target il livello API 23 o versioni precedenti, il sistema interrompe automaticamente tutti i suoi processi in background. Ciò significa che se un utente passa da un'app di questo tipo per aprire la schermata Impostazioni e modifica l'impostazione Dimensioni visualizzazione, il sistema termina l'app nello stesso modo in cui lo farebbe in una situazione di memoria insufficiente. Se l'app ha processi in primo piano, il sistema li informa della modifica della configurazione, come descritto in Gestione delle modifiche di runtime, proprio come se l'orientamento del dispositivo fosse cambiato.
  • Se un'app ha come target Android 7.0, tutti i suoi processi (in primo piano e in background) ricevono una notifica della modifica della configurazione, come descritto in Gestione delle modifiche di runtime.

La maggior parte delle app non deve apportare modifiche per supportare questa funzionalità, a condizione che segua le best practice di Android. Aspetti specifici da controllare:

  • Testa la tua app su un dispositivo con larghezza dello schermo sw320dp e assicurati che funzioni correttamente.
  • Quando la configurazione del dispositivo cambia, aggiorna tutte le informazioni memorizzate nella cache che dipendono dalla densità, ad esempio le bitmap memorizzate nella cache o le risorse caricate dalla rete. Controlla se sono state apportate modifiche alla configurazione quando l'app riprende dallo stato di pausa.

    Nota: se memorizzi nella cache dati dipendenti dalla configurazione, è una buona idea includere metadati pertinenti, come le dimensioni dello schermo o la densità di pixel appropriate per questi dati. Il salvataggio di questi metadati ti consente di decidere se devi aggiornare i dati memorizzati nella cache dopo una modifica della configurazione.

  • Evita di specificare le dimensioni con unità px, poiché non vengono ridimensionate in base alla densità dello schermo. Specifica invece le dimensioni con unità di pixel indipendenti dalla densità (dp).

Impostazioni visive nella configurazione guidata

Android 7.0 include le impostazioni di visualizzazione nella schermata di benvenuto, dove gli utenti possono configurare le seguenti impostazioni di accessibilità su un nuovo dispositivo: Gesto di ingrandimento, Dimensioni carattere, Dimensioni di visualizzazione e TalkBack. Questa modifica aumenta la visibilità dei bug relativi alle diverse impostazioni dello schermo. Per valutare l'impatto di questa funzionalità, devi testare le tue app con queste impostazioni attivate. Puoi trovare le impostazioni in Impostazioni > Accessibilità.

App NDK che si collegano alle librerie della piattaforma

A partire da Android 7.0, il sistema impedisce alle app di collegarsi dinamicamente a librerie non NDK, il che potrebbe causare l'arresto anomalo dell'app. Questa modifica del comportamento mira a creare un'esperienza con l'app coerente tra gli aggiornamenti della piattaforma e i diversi dispositivi. Anche se il tuo codice potrebbe non essere collegato a librerie private, è possibile che lo sia una libreria statica di terze parti nella tua app. Pertanto, tutti gli sviluppatori devono verificare che le loro app non si arrestino in modo anomalo sui dispositivi con Android 7.0. Se la tua app utilizza codice nativo, devi utilizzare solo API NDK pubbliche.

Esistono tre modi in cui la tua app potrebbe tentare di accedere alle API della piattaforma privata:

  • La tua app accede direttamente alle librerie private della piattaforma. Devi aggiornare la tua app in modo che includa la propria copia di queste librerie o utilizzare le API NDK pubbliche.
  • La tua app utilizza una libreria di terze parti che accede a librerie di piattaforme private. Anche se hai la certezza che la tua app non acceda direttamente alle librerie private, devi comunque testarla per questo scenario.
  • La tua app fa riferimento a una libreria non inclusa nel suo APK. Ad esempio, questo potrebbe accadere se hai provato a utilizzare la tua copia di OpenSSL, ma hai dimenticato di raggrupparla con l'APK della tua app. L'app potrebbe funzionare normalmente sulle versioni della piattaforma Android che includono libcrypto.so. Tuttavia, l'app potrebbe arrestarsi in modo anomalo nelle versioni successive di Android che non includono questa libreria (ad esempio Android 6.0 e versioni successive). Per risolvere il problema, assicurati di raggruppare tutte le librerie non NDK con l'APK.

Le app non devono utilizzare librerie native non incluse nell'NDK perché potrebbero cambiare o essere rimosse tra le diverse versioni di Android. Il passaggio da OpenSSL a BoringSSL è un esempio di questa modifica. Inoltre, poiché non esistono requisiti di compatibilità per le librerie della piattaforma non incluse nell'NDK, dispositivi diversi potrebbero offrire livelli di compatibilità diversi.

Per ridurre l'impatto che questa limitazione potrebbe avere sulle app attualmente rilasciate, un insieme di librerie che vengono utilizzate in modo significativo, come libandroid_runtime.so, libcutils.so, libcrypto.so e libssl.so, sono temporaneamente accessibili su Android 7.0 (livello API 24) per le app che hanno come livello API target il livello API 23 o versioni precedenti. Se la tua app carica una di queste librerie, logcat genera un avviso e sul dispositivo di destinazione viene visualizzato un avviso popup per informarti. Se visualizzi questi avvisi, devi aggiornare l'app in modo che includa la propria copia di queste librerie o utilizzi solo le API NDK pubbliche. Le versioni future della piattaforma Android potrebbero limitare completamente l'utilizzo delle librerie private e causare l'arresto anomalo dell'app.

Tutte le app generano un errore di runtime quando chiamano un'API che non è pubblica né temporaneamente accessibile. Il risultato è che System.loadLibrary e dlopen(3) restituiscono entrambi NULL e potrebbero causare l'arresto anomalo dell'app. Devi esaminare il codice della tua app per rimuovere l'utilizzo delle API della piattaforma privata e testare accuratamente le tue app utilizzando un dispositivo o un emulatore con Android 7.0 (livello API 24). Se non sai con certezza se la tua app utilizza librerie private, puoi controllare logcat per identificare l'errore di runtime.

La tabella seguente descrive il comportamento che dovresti aspettarti da un'app in base all'utilizzo di librerie native private e al livello API target (android:targetSdkVersion).

Librerie Livello API target Accesso di runtime tramite linker dinamico Comportamento di Android 7.0 (livello API 24) Comportamento futuro della piattaforma Android
NDK pubblico Qualsiasi Accessibile Funziona come previsto Funziona come previsto
Privato (librerie private accessibili temporaneamente) 23 o meno Accessibile temporaneamente Funziona come previsto, ma ricevi un avviso logcat. Errore di runtime
Privato (librerie private accessibili temporaneamente) 24 o superiore Con restrizioni Errore di runtime Errore di runtime
Privato (altro) Qualsiasi Con restrizioni Errore di runtime Errore di runtime

Controlla se la tua app utilizza librerie private

Per aiutarti a identificare i problemi di caricamento delle librerie private, logcat potrebbe generare un avviso o un errore di runtime. Ad esempio, se la tua app ha come target il livello API 23 o precedente e tenta di accedere a una libreria privata su un dispositivo con Android 7.0, potresti visualizzare un avviso simile al seguente:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

Questi avvisi di logcat indicano quale libreria sta tentando di accedere a un'API della piattaforma privata, ma non causano l'arresto anomalo dell'app. Se l'app ha come livello API target 24 o versioni successive, logcat genera il seguente errore di runtime e l'app potrebbe avere un arresto anomalo:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

Potresti anche visualizzare questi output logcat se la tua app utilizza librerie di terze parti che si collegano dinamicamente ad API di piattaforme private. Lo strumento readelf nell'NDK di Android 7.0 ti consente di generare un elenco di tutte le librerie condivise collegate dinamicamente di un determinato file .so eseguendo il seguente comando:

aarch64-linux-android-readelf -dW libMyLibrary.so

Aggiorna la tua app

Ecco alcuni passaggi che puoi seguire per correggere questi tipi di errori e assicurarti che la tua app non si arresti in modo anomalo con i futuri aggiornamenti della piattaforma:

  • Se la tua app utilizza librerie di piattaforme private, devi aggiornarla in modo che includa la propria copia di queste librerie o utilizzi le API NDK pubbliche.
  • Se la tua app utilizza una libreria di terze parti che accede a simboli privati, contatta l'autore della libreria per aggiornarla.
  • Assicurati di pacchettizzare tutte le librerie non NDK con l'APK.
  • Utilizza le funzioni JNI standard anziché getJavaVM e getJNIEnv da libandroid_runtime.so:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • Utilizza __system_property_get anziché il simbolo privato property_get di libcutils.so. Per farlo, utilizza __system_property_get con il seguente include:
    #include <sys/system_properties.h>

    Nota: la disponibilità e i contenuti delle proprietà di sistema non vengono testati tramite CTS. Una soluzione migliore sarebbe evitare del tutto l'utilizzo di queste proprietà.

  • Utilizza una versione locale del simbolo SSL_ctrl di libcrypto.so. Ad esempio, devi collegare staticamente libcyrpto.a nel tuo file .so o includere una versione collegata dinamicamente di libcrypto.so da BoringSSL/OpenSSL e pacchettizzarla nel tuo APK.

Android for Work

Android 7.0 contiene modifiche per le app che hanno come target Android for Work, tra cui modifiche all'installazione dei certificati, alla reimpostazione della password, alla gestione degli utenti secondari e all'accesso agli identificatori dei dispositivi. Se stai creando app per ambienti Android for Work, devi esaminare queste modifiche e modificare la tua app di conseguenza.

  • Devi installare un programma di installazione di certificati delegati prima che il DPC possa impostarlo. Per le app del profilo e del proprietario del dispositivo che hanno come target Android 7.0 (livello API 24), devi installare il programma di installazione dei certificati delegati prima che il controller di policy dei dispositivi (DPC) chiami DevicePolicyManager.setCertInstallerPackage(). Se il programma di installazione non è già installato, il sistema genera un'eccezione IllegalArgumentException.
  • Le limitazioni per la reimpostazione della password per gli amministratori dei dispositivi ora si applicano ai proprietari dei profili. Gli amministratori dei dispositivi non possono più utilizzare DevicePolicyManager.resetPassword() per cancellare le password o modificare quelle già impostate. Gli amministratori dei dispositivi possono comunque impostare una password, ma solo quando il dispositivo non ha una password, un PIN o una sequenza.
  • I proprietari di dispositivi e profili possono gestire gli account anche se sono impostate limitazioni. I proprietari dei dispositivi e dei profili possono chiamare le API Account Management anche se sono in vigore limitazioni per gli utenti DISALLOW_MODIFY_ACCOUNTS.
  • I proprietari dei dispositivi possono gestire gli utenti secondari. Quando un dispositivo è in modalità device owner, la limitazione DISALLOW_ADD_USER viene impostata automaticamente. In questo modo, gli utenti non possono creare utenti secondari non gestiti. Inoltre, i metodi CreateUser() e createAndInitializeUser() sono deprecati e vengono sostituiti dal nuovo metodo DevicePolicyManager.createAndManageUser().
  • I proprietari dei dispositivi possono accedere agli identificatori dei dispositivi. Un proprietario del dispositivo può accedere all'indirizzo MAC Wi-Fi di un dispositivo utilizzando DevicePolicyManager.getWifiMacAddress(). Se il Wi-Fi non è mai stato attivato sul dispositivo, questo metodo restituisce il valore null.
  • L'impostazione Modalità Lavoro controlla l'accesso alle app di lavoro. Quando la modalità di lavoro è disattivata, l'Avvio app di sistema indica che le app di lavoro non sono disponibili disattivandole. Se riattivi la modalità di lavoro, il comportamento normale viene ripristinato.
  • Quando installi un file PKCS #12 contenente una catena di certificati client e la chiave privata corrispondente dalla UI Impostazioni, il certificato CA nella catena non viene più installato nell'archivio credenziali attendibili. Ciò non influisce sul risultato di KeyChain.getCertificateChain() quando le app tentano di recuperare la catena di certificati client in un secondo momento. Se necessario, il certificato CA deve essere installato nell'archivio credenziali attendibili utilizzando l'interfaccia utente Impostazioni separatamente, con un formato con codifica DER con estensione del file .crt o .cer.
  • A partire da Android 7.0, la registrazione e l'archiviazione delle impronte vengono gestite per utente. Se il client Device Policy (DPC) di un proprietario del profilo ha come target il livello API 23 (o precedente) su un dispositivo con Android 7.0 (livello API 24), l'utente può comunque impostare l'impronta sul dispositivo, ma le applicazioni di lavoro non possono accedere all'impronta del dispositivo. Quando il DPC ha come target il livello API 24 e versioni successive, l'utente può impostare l'impronta specificamente per il profilo di lavoro andando su Impostazioni > Sicurezza > Sicurezza del profilo di lavoro.
  • DevicePolicyManager.getStorageEncryptionStatus() restituisce un nuovo stato di crittografia ENCRYPTION_STATUS_ACTIVE_PER_USER per indicare che la crittografia è attiva e la chiave di crittografia è associata all'utente. Il nuovo stato viene restituito solo se il DPC ha come target il livello API 24 e versioni successive. Per le app che hanno come target livelli API precedenti, viene restituito ENCRYPTION_STATUS_ACTIVE, anche se la chiave di crittografia è specifica per l'utente o il profilo.
  • In Android 7.0, diversi metodi che normalmente influiscono sull'intero dispositivo si comportano in modo diverso se sul dispositivo è installato un profilo di lavoro con una verifica lavoro separata. Anziché interessare l'intero dispositivo, questi metodi si applicano solo al profilo di lavoro. (L'elenco completo di questi metodi è disponibile nella documentazione di DevicePolicyManager.getParentProfileInstance().) Ad esempio, DevicePolicyManager.lockNow() blocca solo il profilo di lavoro, anziché l'intero dispositivo. Per ognuno di questi metodi, puoi ottenere il comportamento precedente chiamando il metodo sull'istanza principale di DevicePolicyManager; puoi ottenere questa istanza principale chiamando DevicePolicyManager.getParentProfileInstance(). Ad esempio, se chiami il metodo lockNow() dell'istanza principale, l'intero dispositivo viene bloccato.

Conservazione delle annotazioni

Android 7.0 corregge un bug per cui la visibilità delle annotazioni veniva ignorata. Questo problema ha consentito al runtime di accedere ad annotazioni a cui non avrebbe dovuto avere accesso. Queste annotazioni includevano:

  • VISIBILITY_BUILD: deve essere visibile solo in fase di build.
  • VISIBILITY_SYSTEM: deve essere visibile in fase di runtime, ma solo al sistema sottostante.

Se la tua app si basa su questo comportamento, aggiungi una policy di conservazione alle annotazioni che devono essere disponibili in fase di runtime. A questo scopo, utilizza @Retention(RetentionPolicy.RUNTIME).

Modifiche alla configurazione predefinita TLS/SSL

Android 7.0 apporta le seguenti modifiche alla configurazione TLS/SSL predefinita utilizzata dalle app per il traffico HTTPS e altro traffico TLS/SSL:

  • Le suite di crittografia RC4 sono ora disattivate.
  • Le suite di cifrari CHACHA20-POLY1305 sono ora abilitate.

La disattivazione di RC4 per impostazione predefinita potrebbe causare interruzioni della connettività HTTPS o TLS/SSL quando il server non negozia suite di crittografia moderne. La correzione preferita consiste nel migliorare la configurazione del server per abilitare suite di cifrari e protocolli più efficaci e moderni. Idealmente, TLSv1.2 e AES-GCM devono essere abilitati e le suite di crittografia Forward Secrecy (ECDHE) devono essere abilitate e preferite.

Un'alternativa è modificare l'app in modo che utilizzi un SSLSocketFactory personalizzato per comunicare con il server. La factory deve essere progettata per creare istanze SSLSocket che abbiano alcune delle suite di crittografia richieste dal server abilitate oltre alle suite di crittografia predefinite.

Nota: queste modifiche non riguardano WebView.

App che hanno come target Android 7.0

Queste modifiche al comportamento si applicano esclusivamente alle app che hanno come target Android 7.0 (livello API 24) o versioni successive. Le app che vengono compilate per Android 7.0 o che impostano targetSdkVersion su Android 7.0 o versioni successive devono essere modificate per supportare correttamente questi comportamenti, ove applicabile all'app.

Modifiche alla serializzazione

Android 7.0 (livello API 24) ha corretto un bug nel calcolo del serialVersionUID predefinito, che non corrispondeva alla specifica.

Le classi che implementano Serializable e non specificano un campo serialVersionUID esplicito potrebbero vedere una modifica nel loro serialVersionUID predefinito, il che causerebbe la generazione di un'eccezione quando si tenta di deserializzare le istanze della classe che sono state serializzate in una versione precedente o serializzate da un'app che ha come target una versione precedente. Il messaggio di errore sarà simile al seguente:

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

Per risolvere questi problemi, devi aggiungere un campo serialVersionUID a qualsiasi classe interessata con il valore di stream classdesc serialVersionUID del messaggio di errore, ad esempio 1234 in questo caso. Questa modifica rispetta tutti i consigli sulle best practice per la scrittura del codice di serializzazione e funzionerà su tutte le versioni di Android.

Il bug specifico che è stato corretto era correlato alla presenza di metodi di inizializzazione statici, ovvero <clinit>. In base alla specifica, la presenza o l'assenza di un metodo di inizializzazione statico nella classe influirà sul serialVersionUID predefinito calcolato per quella classe. Prima della correzione di bug, il calcolo controllava anche la superclasse per un inizializzatore statico se una classe non ne aveva uno.

Per chiarire, questa modifica non influisce sulle app che hanno come livello API target i livelli API 23 o inferiori, sulle classi che hanno un campo serialVersionUID o sulle classi che hanno un metodo di inizializzazione statico.

Altri punti importanti

  • Quando un'app è in esecuzione su Android 7.0, ma ha come target un livello API inferiore e l'utente modifica le dimensioni di visualizzazione, il processo dell'app viene interrotto. L'app deve essere in grado di gestire questo scenario in modo corretto. In caso contrario, si arresta in modo anomalo quando l'utente la ripristina da Recenti.

    Dovresti testare la tua app per assicurarti che questo comportamento non si verifichi. Puoi farlo causando un arresto anomalo identico quando chiudi l'app manualmente utilizzando DDMS.

    Le app che hanno come target Android 7.0 (livello API 24) e versioni successive non vengono terminate automaticamente in caso di modifiche alla densità, ma potrebbero comunque rispondere in modo non ottimale alle modifiche alla configurazione.

  • Le app su Android 7.0 dovrebbero essere in grado di gestire correttamente le modifiche alla configurazione e non dovrebbero arrestarsi in modo anomalo agli avvii successivi. Puoi verificare il comportamento dell'app modificando le dimensioni del carattere (Impostazioni > Display > Dimensioni carattere) e poi ripristinando l'app da Recenti.
  • A causa di un bug nelle versioni precedenti di Android, il sistema non segnalava la scrittura su un socket TCP nel thread principale come violazione della modalità StrictMode. Android 7.0 corregge questo bug. Le app che mostrano questo comportamento ora generano un android.os.NetworkOnMainThreadException. In genere, l'esecuzione di operazioni di rete sul thread principale non è una buona idea perché queste operazioni di solito hanno una latenza elevata che causa ANR e jank.
  • La famiglia di metodi Debug.startMethodTracing() ora archivia per impostazione predefinita l'output nella directory specifica del pacchetto nello spazio di archiviazione condiviso, anziché nel livello più alto della scheda SD. Ciò significa che le app non devono più richiedere l'autorizzazione WRITE_EXTERNAL_STORAGE per utilizzare queste API.
  • Molte API della piattaforma hanno iniziato a verificare l'invio di payload di grandi dimensioni tramite transazioni Binder e il sistema ora genera nuovamente TransactionTooLargeExceptions come RuntimeExceptions, anziché registrarli o sopprimerli in modo silenzioso. Un esempio comune è l'archiviazione di troppi dati in Activity.onSaveInstanceState(), che fa sì che ActivityThread.StopInfo generi un RuntimeException quando la tua app ha come target Android 7.0.
  • Se un'app pubblica Runnable attività in un View e View non è collegato a una finestra, il sistema mette in coda l'attività Runnable con View; l'attività Runnable non viene eseguita finché View non viene collegato a una finestra. Questo comportamento corregge i seguenti bug:
    • Se un'app ha pubblicato un messaggio in un View da un thread diverso dal thread dell'interfaccia utente della finestra prevista, il Runnable potrebbe essere eseguito nel thread sbagliato.
    • Se l'attività Runnable è stata pubblicata da un thread diverso da un thread looper, l'app potrebbe esporre l'attività Runnable.
  • Se un'app su Android 7.0 con l'autorizzazione DELETE_PACKAGES tenta di eliminare un pacchetto, ma un'altra app ha installato quel pacchetto, il sistema richiede la conferma dell'utente. In questo scenario, le app devono aspettarsi STATUS_PENDING_USER_ACTION come stato restituito quando richiamano PackageInstaller.uninstall().
  • Il provider JCA denominato Crypto è deprecato, perché il suo unico algoritmo, SHA1PRNG, è debole dal punto di vista crittografico. Le app non possono più utilizzare SHA1PRNG per derivare le chiavi (in modo non sicuro), perché questo provider non è più disponibile. Per ulteriori informazioni, consulta il blog post Provider di sicurezza "Crypto" ritirato in Android N.