Wakelock parziali bloccati

I wakelock parziali sono un meccanismo dell'API PowerManager che consente agli sviluppatori di mantenere la CPU in esecuzione dopo lo spegnimento del display di un dispositivo (a causa di un timeout del sistema o della pressione dell'utente sul tasto di accensione). La tua app acquisisce un wakelock parziale chiamando acquire() con il flag PARTIAL_WAKE_LOCK. Un wakelock parziale si blocca se viene mantenuto per molto tempo mentre l'app è in esecuzione in background (nessuna parte dell'app è visibile all'utente). Questa condizione scarica la batteria del dispositivo perché impedisce al dispositivo di entrare in uno stato di alimentazione inferiore. I wakelock parziali devono essere utilizzati solo quando necessario e rilasciati il prima possibile, in quanto non sono più necessari.

Se la tua app ha un wakelock parziale bloccato, puoi utilizzare le indicazioni in questa pagina per diagnosticare e risolvere il problema.

Rileva il problema

Potresti non sapere sempre che i wakelock parziali dell'app sono bloccati. Se hai già pubblicato la tua app, Android vitals può aiutarti a informarti del problema.

Android vitals

Android vitals può aiutare a migliorare le prestazioni della tua app avvisandoti tramite Play Console quando nella tua app sono presenti wakelock parziali bloccati. Android vitals segnala che i wakelock parziali sono bloccati quando dura almeno un'ora, mentre in background si verifica un wakelock parziale in una sessione di batteria.

La definizione di sessione di batteria dipende dalla versione della piattaforma.

  • In Android 10, una sessione di batteria è l'aggregazione di tutti i report sulla batteria ricevuti entro un determinato periodo di 24 ore. Un report sulla batteria fa riferimento all'intervallo tra due ricariche da meno del 20% a oltre l'80% o da qualsiasi livello di carica al 100%.
  • In Android 11, una sessione di batteria è un periodo fisso di 24 ore.

Il numero di sessioni di batteria visualizzato è un valore aggregato per tutti gli utenti dell'app misurati. Per informazioni su come Google Play raccoglie i dati Android vitals, consulta la documentazione di Play Console.

Quando sai che nella tua app sono presenti troppi wakelock parziali bloccati, il passaggio successivo consiste nell'risolvere il problema.

Risolvi problema

I wakelock sono stati introdotti nelle prime versioni della piattaforma Android ma, nel tempo, molti casi d'uso che in precedenza richiedevano i wakelock ora sono gestiti meglio da API più recenti come WorkManager.

Questa sezione contiene suggerimenti per risolvere i wakelock; tuttavia, nel lungo periodo, valuta la possibilità di eseguire la migrazione della tua app in modo da seguire i consigli nella sezione delle best practice.

Identifica e correggi i punti nel tuo codice che acquisiscono un wakelock, come le chiamate a newWakeLock(int, String) o a WakefulBroadcastReceiver sottoclassi. Ecco alcuni suggerimenti:

  • Ti consigliamo di includere il nome del pacchetto, della classe o del metodo nel nome del tag wakelock in modo da poter identificare facilmente la posizione nella tua origine in cui è stato creato il wakelock. Ecco alcuni suggerimenti aggiuntivi:
    • Lascia nel nome eventuali informazioni che consentono l'identificazione personale (PII), ad esempio un indirizzo email. In caso contrario, il dispositivo registra _UNKNOWN anziché il nome del wakelock.
    • Non ottenere il nome della classe o del metodo in modo programmatico, ad esempio chiamando getName(), perché potrebbe essere offuscato da Proguard. Utilizza invece una stringa hardcoded.
    • Non aggiungere un contatore o identificatori univoci ai tag di wakelock. Il sistema non sarà in grado di aggregare i wakelock creati dallo stesso metodo perché hanno tutti identificatori univoci.
  • Assicurati che il codice rilasci tutti i wakelock che acquisisce. Questa operazione è più complicata rispetto ad assicurare che ogni chiamata a acquire() abbia una chiamata corrispondente a release(). Ecco un esempio di wakelock non rilasciato a causa di un'eccezione non rilevata:

    Kotlin

    @Throws(MyException::class)
    fun doSomethingAndRelease() {
        wakeLock.apply {
            acquire()
            doSomethingThatThrows()
            release()  // does not run if an exception is thrown
        }
    }

    Java

        void doSomethingAndRelease() throws MyException {
            wakeLock.acquire();
            doSomethingThatThrows();
            wakeLock.release();  // does not run if an exception is thrown
        }

    Ecco una versione corretta del codice:

    Kotlin

    @Throws(MyException::class)
    fun doSomethingAndRelease() {
        wakeLock.apply {
            try {
                acquire()
                doSomethingThatThrows()
            } finally {
                release()
            }
        }
    }

    Java

        void doSomethingAndRelease() throws MyException {
            try {
                wakeLock.acquire();
                doSomethingThatThrows();
            } finally {
                wakeLock.release();
            }
        }
  • Assicurati che i wakelock vengano sbloccati non appena non sono più necessari. Ad esempio, se utilizzi un wakelock per consentire il completamento di un'attività in background, assicurati che il rilascio avvenga al termine dell'attività. Se un wakelock viene mantenuto più a lungo del previsto senza essere rilasciato, potrebbe significare che l'attività in background sta richiedendo più tempo del previsto.

Dopo aver risolto il problema nel codice, verifica che la tua app rilasci correttamente i wakelock utilizzando i seguenti strumenti Android:

  • dumpsys: uno strumento che fornisce informazioni sullo stato dei servizi di sistema su un dispositivo. Esegui adb shell dumpsys power per controllare lo stato del servizio di alimentazione, che include un elenco di wakelock.

  • Battery Historian: uno strumento che analizza l'output di una segnalazione di bug di Android in una rappresentazione visiva degli eventi relativi all'alimentazione.

Best practice

In generale, l'app dovrebbe evitare wakelock parziali perché è troppo facile far scaricare la batteria dell'utente. Android fornisce API alternative per quasi tutti i casi d'uso che in precedenza richiedevano un wakelock parziale. Un altro caso d'uso per i wakelock parziali consiste nel garantire che un'app di musica continui a riprodurre quando lo schermo è spento. Se usi i wakelock per eseguire le attività, prendi in considerazione le alternative descritte nella guida all'elaborazione in background.

Se devi utilizzare i wakelock parziali, segui questi consigli:

  • Assicurati che una parte della tua app rimanga in primo piano. Ad esempio, se devi eseguire un servizio, avviane uno in primo piano. Questo indica visivamente all'utente che la tua app è ancora in esecuzione.
  • Assicurati che la logica per l'acquisizione e il rilascio dei wakelock sia il più semplice possibile. Quando la logica del wakelock è legata a macchine a stato complesse, timeout, pool di esecutori e/o eventi di callback, qualsiasi piccolo bug nella logica può causare una sospensione del wakelock più lungo del previsto. Questi bug sono difficili da diagnosticare e eseguire il debug.