Wakelocks partiels figés

Les wakelocks partiels sont un mécanisme de l'API PowerManager qui permet aux développeurs de maintenir le processeur en fonctionnement après l'arrêt de l'écran d'un appareil (en raison d'un dépassement de délai système ou lorsque l'utilisateur appuie sur le bouton Marche/Arrêt). Votre application acquiert un wakelock partiel en appelant acquire() avec l'indicateur PARTIAL_WAKE_LOCK. Un wakelock partiel devient figé s'il est maintenu pendant une longue période alors que votre application s'exécute en arrière-plan (l'utilisateur ne peut voir aucune partie de votre application). Cette condition décharge la batterie de l'appareil, car cela l'empêche de passer à un état de puissance plus faible. Les wakelocks partiels ne doivent être utilisés que lorsqu'ils sont nécessaires et libérés dès qu'ils ne le sont plus.

Si votre application présente un wakelock partiel figé, vous pouvez suivre les instructions de cette page pour diagnostiquer et résoudre le problème.

Détecter le problème

Les wakelocks partiels figés de votre application ne sont pas toujours portés à votre connaissance. Si vous avez déjà publié votre application, Android Vitals peut vous aider à prendre conscience du problème.

Android Vitals

Android Vitals améliore les performances de votre application en vous alertant via la Play Console lorsque votre application présente des wakelocks partiels figés. Android Vitals signale les wakelocks partiels comme figés lorsqu'au moins un wakelock partiel en arrière-plan, d'une durée d'une heure, intervient dans une session de batterie.

La définition d'une session de batterie dépend de la version de la plate-forme.

  • Sous Android 10, ce terme désigne l'agrégation de tous les rapports sur la batterie reçus sur une période de 24 heures. Le rapport sur la batterie fait référence à l'intervalle entre deux charges de la batterie, qui passe de moins de 20 % à plus de 80 %, ou de n'importe quel niveau de charge à 100 %.
  • Sous Android 11, une session de batterie correspond à une période fixe de 24 heures.

Le nombre de sessions de batterie affiché est une donnée cumulée pour tous les utilisateurs mesurés de l'application. Pour savoir comment Google Play collecte les données Android Vitals, consultez la documentation de la Play Console.

Une fois que vous savez que votre application présente un nombre excessif de wakelocks partiels figés, vous devez résoudre le problème.

Résoudre le problème

Les wakelocks ont été introduits dans les premières versions de la plate-forme Android. Mais au fil du temps, de nombreux cas d'utilisation nécessitant auparavant des wakelocks sont désormais mieux adaptés aux nouvelles API, telles que WorkManager.

Cette section contient des conseils pour réparer les wakelocks, mais à long terme, envisagez de migrer votre application conformément aux recommandations de la section Bonnes pratiques.

Identifiez et corrigez les points de votre code qui acquièrent un wakelock, tels que les appels vers newWakeLock(int, String) ou les sous-classes WakefulBroadcastReceiver. Voici quelques conseils :

  • Nous vous recommandons d'inclure le nom du package, de la classe ou de la méthode dans le nom de la balise de wakelock, de façon à pouvoir identifier facilement l'emplacement de la source dans lequel le wakelock a été créé. Voici quelques conseils supplémentaires :
    • N'indiquez aucune information permettant d'identifier personnellement l'utilisateur dans le nom, comme une adresse e-mail. Sinon, l'appareil enregistre _UNKNOWN au lieu du nom du wakelock.
    • N'obtenez pas le nom de la classe ou de la méthode par programmation, par exemple en appelant getName(), car il pourrait être obscurci par ProGuard. Utilisez plutôt une chaîne codée en dur.
    • N'ajoutez pas de compteur ni d'identifiants uniques pour réactiver les balises de wakelock. Le système ne pourra pas agréger les wakelocks créés par la même méthode, car ils possèdent tous des identifiants uniques.
  • Assurez-vous que votre code libère tous les wakelocks qu'il acquiert. Ceci est plus compliqué que de s'assurer que chaque appel à acquire() présente un appel correspondant à release(). Voici un exemple de wakelock qui n'est pas libéré en raison d'une exception non détectée :

    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
        }

    Voici une version correcte du code :

    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();
            }
        }
  • Assurez-vous que les wakelocks sont libérés dès qu'ils ne sont plus nécessaires. Par exemple, si vous utilisez un wakelock pour qu'une tâche en arrière-plan se termine, veillez à ce qu'il soit libéré une fois la tâche finie. Si un wakelock est conservé plus longtemps que prévu sans être libéré, cela peut signifier que votre tâche en arrière-plan prend plus de temps qu'escompté.

Après avoir résolu le problème dans le code, vérifiez que votre application lève correctement les wakelocks à l'aide des outils Android suivants :

  • dumpsys : outil qui fournit des informations sur l'état des services système d'un appareil. Pour afficher l'état du service d'alimentation, qui comprend une liste de wakelocks, exécutez adb shell dumpsys power.

  • Batterie Historian : outil qui analyse la sortie d'un rapport de bug Android dans une représentation visuelle des événements liés à l'alimentation.

Bonnes pratiques

En général, votre application doit éviter les wakelocks partiels, car il est trop facile de décharger la batterie de l'utilisateur. Android fournit des API alternatives pour presque tous les cas d'utilisation nécessitant auparavant un wakelock partiel. Un cas d'utilisation restant pour les wakelocks partiels est de s'assurer qu'une application musicale continue de fonctionner lorsque l'écran est éteint. Si vous utilisez des wakelocks pour exécuter des tâches, envisagez d'autres solutions décrites dans le guide de traitement en arrière-plan.

Si vous devez utiliser des wakelocks partiels, suivez ces recommandations :

  • Assurez-vous qu'une partie de votre application reste au premier plan. Par exemple, si vous devez exécuter un service, démarrez un service de premier plan. Cet élément indique visuellement à l'utilisateur que votre application est toujours en cours d'exécution.
  • Assurez-vous que la logique d'acquisition et de libération des wakelocks est aussi simple que possible. Lorsque votre logique de wakelock est liée à des machines d'état, à des délais d'exécution, à des pools d'exécuteurs et/ou à des événements de rappel complexes, tout bug subtil dans cette logique peut entraîner le blocage du wakelock plus longtemps que prévu. Ces bugs sont difficiles à diagnostiquer et à déboguer.