Les ANR Unity se produisent pour différentes raisons. La plupart des ANR sont causées par une mauvaise utilisation des composants Android et Unity, et par une mauvaise communication entre eux.
WebView
WebView
est une classe Android qui affiche des pages Web. Les SDK tiers (comme les annonces) utilisent WebView
pour afficher du contenu Web dynamique dans des activités autres que UnityPlayerActivity
. Les ANR se produisent lorsque des SDK tiers utilisent WebView
de manière abusive.
Trace de la pile
La trace de pile est votre premier recours pour comprendre la cause de l'ANR.
/data/app/~~p-0ksfCD6bF6Sdq6kpVePg==/com.google.android.webview-5YQZOqKbbqp-uoLY6WYnTw==/base.apk!libmonochrome.so
at J.N.Mhc_M_H$ (Native method)
at org.chromium.components.viz.service.frame_sinks.ExternalBeginFrameSourceAndroid.doFrame (chromium-TrichromeWebViewGoogle.aab-stable-579013831:60)
at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1054)
at android.view.Choreographer.doCallbacks (Choreographer.java:878)
at android.view.Choreographer.doFrame (Choreographer.java:807)
at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1041)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:223)
at android.app.ActivityThread.main (ActivityThread.java:7721)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:952)
Figure 1 : Trace de la pile ANR causée par une attente futex.
Cause
Pour le moment, la cause première de ce problème n'est pas claire. Voici quelques causes potentielles :
- Mauvaise implémentation des annonces.
- Une version obsolète de
WebView
, car l'utilisateur peut avoir choisi de ne pas mettre à jour l'application automatiquement. - Utilisation élevée des ressources système (CPU, GPU, etc.), qui peut nécessiter beaucoup de profilage.
- Les plantages de la compilation des nuanceurs, qui peuvent indiquer que le contenu comporte un nuanceur incompatible ou que l'utilisateur a installé une ancienne version de
WebView
.
Solution
- Pour identifier le type de contenu qui provoque le blocage du thread principal par
WebView
, ajoutez des journaux à votre jeu chaque fois qu'une page Web est chargée, affichée ou fermée.- Vous pouvez utiliser les services de création de rapports Backtrace ou Crashlytics.
- Ensuite, après avoir analysé les données et identifié le problème, essayez de désactiver les fournisseurs d'annonces concernés.
- Incluez les journaux de mémoire pour vous assurer que le problème n'est pas lié à la mémoire.
- Alertez l'utilisateur pour qu'il mette à jour
WebView
depuis Google Play. À partir d'Android 5.0 (niveau d'API 21) et versions ultérieures,WebView
a été déplacé vers un APK. Il peut donc être mis à jour indépendamment de la plate-forme Android. Pour connaître la version deWebView
utilisée sur un appareil, accédez à Paramètres > Applications > WebView du système Android, puis consultez la version en bas de la page.

WebView
.Mise en pause Unity
Lorsque UnityPlayerActivity
reçoit un appel onPause()
, la chaîne d'opérations suivante démarre :
UnityPlayerActivity
indique au moteur d'exécution Unity que l'activité a été mise en pause.- Unity appelle chaque
MonoBehaviour
qui implémente l'événementOnApplicationPause
. - Unity arrête ses composants et modules, tels que la lecture du son, le rendu, la boucle de jeu et l'animation.
- Pour s'assurer que
Unity Android Player
(UAP) et le moteur sont synchronisés, l'UAP attend quatre secondes que le moteur s'arrête. - Si cette opération prend plus de cinq secondes, le système déclenche une erreur ANR.
Trace de la pile
"main" tid=1 Timed Waiting
jdk.internal.misc.Unsafe.park (Native method)
java.util.concurrent.locks.LockSupport.parkNanos (LockSupport.java:234)
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos (AbstractQueuedSynchronizer.java:1079)
java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos (AbstractQueuedSynchronizer.java:1369)
java.util.concurrent.Semaphore.tryAcquire (Semaphore.java:415)
com.unity3d.player.UnityPlayer.pauseUnity (UnityPlayer.java:833)
com.unity3d.player.UnityPlayer.pause (UnityPlayer.java:796)
com.unity3d.player.UnityPlayerActivity.onPause (UnityPlayerActivity.java:117)
android.app.Activity.performPause (Activity.java:8517)
android.app.Instrumentation.callActivityOnPause (Instrumentation.java:1618)
android.app.ActivityThread.performPauseActivityIfNeeded (ActivityThread.java:5061)
android.app.ActivityThread.performPauseActivity (ActivityThread.java:5022)
android.app.ActivityThread.handlePauseActivity (ActivityThread.java:4974)
android.app.servertransaction.PauseActivityItem.execute (PauseActivityItem.java:48)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:179)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:97)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2303)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:201)
android.os.Looper.loop (Looper.java:288)
android.app.ActivityThread.main (ActivityThread.java:7884)
java.lang.reflect.Method.invoke (Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)
Figure 3. ANR causée par un sémaphore qui n'est jamais libéré.
Solution
Assurez-vous que le code de votre jeu en C# ne met pas trop de temps à s'exécuter lors d'un événement de pause ou de reprise.
- Profilez votre jeu et vérifiez si
OnApplicationPause
est une opération coûteuse. Vous pouvez utiliser unStopwatch
. - Évitez les opérations d'E/S ou les requêtes réseau synchrones.
- Déplacez les opérations vers un autre
Thread
à l'aide deTask
. Unity 2023.1 est compatible avec un modèle de programmation asynchrone simplifié utilisant les mots clés C#async
etawait
.
UnitySendMessage bloqué
Les plug-ins et SDK Java Unity envoient des données à la couche de jeu C# à l'aide de JNI. Toutefois, cette communication peut bloquer le thread principal en raison d'une routine de synchronisation native telle qu'un mutex, ce qui provoque un ANR en raison d'un conflit de verrouillage.
Trace de la pile
L'ANR de la figure 4 a été causée par une opération de longue durée dans le code C# appelé par un plug-in Java. Le moteur Unity utilise un mutex sans héritage de priorité pour garantir une exécution correcte.
libc.so NonPI::MutexLockWithTimeout(pthread_mutex_internal_t*, bool, timespec const*) + 604
com.unity3d.player.UnityPlayer.nativeUnitySendMessage (Native method)
com.unity3d.player.UnityPlayer.UnitySendMessage (UnityPlayer.java:665)
Figure 4. Erreur ANR causée par un conflit de verrouillage.
Cause
Le problème est que plusieurs messages sont envoyés lorsque l'application est reprise. Les messages sont mis en file d'attente, car ils ne peuvent pas être envoyés lorsque le jeu est en arrière-plan. Les messages sont tous envoyés simultanément lorsque l'application reprend.
Pendant une période de pause, vous stockez généralement les informations de votre jeu sur le serveur. Par exemple, vous enregistrez la position d'un joueur dans le jeu afin qu'il puisse revenir au même endroit lorsque le jeu reprend.
Cette charge de travail, combinée à d'autres codes tiers créant leur propre charge de travail, peut surcharger les ressources de l'appareil, en particulier le thread principal. Le thread principal exécute l'interface utilisateur d'une application et est souvent le principal emplacement des erreurs ANR. Par conséquent, toute charge de travail ajoutée sur le thread principal augmente le risque d'ANR.
Solution
Lorsque vous mettez une application en pause, assurez-vous que toutes les actions de code sont nécessaires ou essayez d'enregistrer l'état de l'utilisateur dans la mémoire locale de votre appareil. Et bien sûr, vérifiez si vous pouvez également effectuer ces actions en dehors de la période de suspension.
Voici quelques approches :
- Déplacez l'opération C# qui gère un message vers un thread autre que le thread principal.
- Si votre code ne dépend pas du contexte du thread principal d'Unity, utilisez
Task
pour la communication au lieu du message.
- Si votre code ne dépend pas du contexte du thread principal d'Unity, utilisez
- N'envoyez pas plusieurs messages depuis votre plug-in lorsque le jeu est en pause.
- Le moteur ne peut pas envoyer de messages lorsque le jeu est en arrière-plan.
- N'envoyez le dernier état des données à votre jeu que si cela n'a pas d'incidence sur ses fonctionnalités.
Install Referrer
Play Install Referrer est une chaîne unique envoyée au Play Store chaque fois qu'un utilisateur clique sur une annonce. Il s'agit d'un identifiant de suivi des annonces spécifique à Android. Une fois l'application installée, elle envoie le referrer d'installation au partenaire d'attribution, qui fait correspondre la source à l'installation (en attribuant la conversion).
Trace de la pile
La figure 5 montre une trace de pile ANR provenant d'un jeu qui utilise le SDK Facebook pour récupérer l'attribution de l'installation.

Cause
L'erreur ANR a été causée par un appel de liaison lent. Toutefois, il est impossible de déterminer la cause première sans avoir accès au code source du SDK.
Solution
Pour résoudre ce type de problème, vous devez communiquer avec le développeur du SDK ou effectuer de nombreuses recherches en ligne pour trouver une solution potentielle, vérifier si une version plus récente du SDK résout l'ANR pour d'autres utilisateurs, ou même tester une stratégie de déploiement à petite échelle.
Google fournit une page SDK Index qui associe les données d'utilisation des applications Google Play aux informations recueillies via la détection de code afin de fournir des attributs et des signaux conçus pour vous aider à décider si vous voulez adopter, conserver ou supprimer un SDK au sein de votre application.
Ressources supplémentaires
Pour en savoir plus sur les ANR, consultez les ressources suivantes :
- Déboguer les ANR : développement de jeux Android
- ANR : qualité de l'application