Typowe błędy ANR w grach Unity

Błędy ANR w Unity występują z różnych powodów. Najczęstsze błędy ANR są spowodowane niewłaściwego użycia Androida i komponentów Unity oraz nieporozumień.

WebView | komponent WebView

WebView to klasa na Androida, która wyświetla strony internetowe. Dostarczane przez inną firmę Pakiety SDK (np. reklamy) używają WebView do wyświetlania dynamicznych treści internetowych w ramach aktywności innych niż UnityPlayerActivity. Błędy ANR występują, gdy Pakiety SDK nieprawidłowo używają WebView.

Zrzut stosu

Zrzut stosu to pierwszy sposób na zrozumienie przyczyny błędu 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)

Rys. 1. Zrzut stosu ANR spowodowany przez oczekiwanie futex.

Przyczyna

Jak dotąd główna przyczyna tego problemu nie jest znana. Niektóre potencjalne przyczyny uwzględnij:

  • Błędna implementacja reklamy.
  • Nieaktualna wersja WebView, ponieważ użytkownik mógł zrezygnować z aktualizacji automatycznie uruchamiać aplikację.
  • Duże wykorzystanie zasobów systemowych (CPU, GPU itp.), które może wymagać dużo pracy profilowanie.
  • Awaria kompilacji Shader, co może oznaczać, że treść ma niezgodny program do cieniowania lub użytkownik korzysta ze starszej wersji WebView .

Rozwiązanie

  • Aby doprecyzować, jaki typ treści sprawia, że WebView blokuje w wątku głównym, dodawaj logi do gry za każdym razem, gdy wczytuje się, wyświetla lub zamknięte.
    • Możesz używać aplikacji Backtrace lub Crashlytics i usług raportowych.
    • Następnie, po przeanalizowaniu danych i znalezieniu problemu, spróbuj wyłączyć tych obraźliwych.
    • Dołącz dzienniki pamięci, aby mieć pewność, że problem nie jest związany z pamięcią.
  • Poproś użytkownika o zaktualizowanie aplikacji WebView z Google Play. Android 5.0 (poziom interfejsu API 21) lub wyższym, aplikacja WebView została przeniesiona do pliku APK. W związku z tym aktualizowane niezależnie od platformy Androida. Aby sprawdzić wersję aplikacji WebView jest używany na urządzeniu, wybierz Ustawienia > Aplikacje > System Android WebView i sprawdź wersję u dołu strony.
.
Ekran z informacjami o aplikacji przedstawiający wersje WebView.
Rysunek 1. Sprawdź wersję WebView.

Pauza

Gdy UnityPlayerActivity otrzymuje wywołanie onPause(), następujący łańcuch: operacje rozpoczynają się:

  1. UnityPlayerActivity powiadamia silnik środowiska wykonawczego Unity, że aktywność wstrzymane.
  2. Unity wywołuje każde MonoBehaviour, które implementuje metodę OnApplicationPause.
  3. Unity zatrzymuje komponenty i moduły, takie jak odtwarzanie dźwięku, renderowanie pętla gry i animacja.
  4. Aby upewnić się, że Unity Android Player (UAP) i wyszukiwarka są zsynchronizowane, UAP czeka 4 sekundy na zatrzymanie silnika.
  5. Jeśli ta operacja potrwa dłużej niż 5 sekund, system wywoła błąd ANR.

Zrzut stosu

"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)

Rysunek 3. Błąd ANR spowodowany przez semafor, który nigdy nie został wydany.

Rozwiązanie

Upewnij się, że wykonanie kodu gry w C# nie trwa zbyt długo wstrzymać lub wznowić wydarzenie.

  • Profiluj grę i sprawdź, czy OnApplicationPause nie jest drogi w drodze . Możesz użyć: Stopwatch.
  • Unikaj operacji wejścia-wyjścia i synchronicznych żądań sieciowych.
  • Przenieś operacje do innego zasobu Thread za pomocą Task Unity 2023.1 obsługuje uproszczone asynchroniczny model programowania w C# async i await słów kluczowych.

Zablokowano UnitySendMessage

Wtyczki Java Unity i pakiety SDK wysyłają dane do warstwy gry C# za pomocą JNI. Jednak ta komunikacja może zablokować główny wątek ze względu na procedury synchronizacji, takiej jak mutex, powodując błąd ANR z powodu rywalizacji o blokadę.

Zrzut stosu

Błąd ANR na ilustracji 4 został spowodowany długą operację w kodzie C# wywołaną przez Wtyczka Java. Mechanizm Unity wykorzystuje dziedziczenie inne niż priorytetowe mutex, aby zapewnić prawidłowe wykonanie.

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)

Rysunek 4. Błąd ANR spowodowany rywalizacją o blokadę.

Przyczyna

Problem polega na tym, że gdy aplikacja jest wysyłanych kilka wiadomości, został wznowiony. Wiadomości znajdują się w kolejce, ponieważ nie można ich wysłać w czasie gry Aplikacja znajduje się w tle. Wszystkie wiadomości są wysyłane jednocześnie, gdy wznowienie aplikacji.

W tym czasie zwykle przechowujesz informacje o grze na serwer; Na przykład możesz rejestrować pozycję gracza w grze, mogą wrócić do tego samego miejsca po wznowieniu gry.

To zadanie, w połączeniu z innym kodem innej firmy tworzącym własny zbiór zadań, może przeciążyć zasoby urządzenia, zwłaszcza wątek główny. Główny uruchamia interfejs użytkownika aplikacji i często jest główną lokalizacją błędów ANR. A więc, każde dodane zadanie w wątku głównym zwiększa ryzyko błędu ANR.

Rozwiązanie

Podczas wstrzymania aplikacji sprawdź, czy wszystkie działania związane z kodem są konieczne. spróbuj zapisać stan użytkownika w lokalnej pamięci urządzenia. Oczywiście zobaczysz też czy możesz wykonać te działania również poza okresem wstrzymania.

Jak zrobić to na kilka sposobów:

  • Przenieś operację C#, która obsługuje wiadomość, do wątku niż w głównym wątku.
    • Jeśli Twój kod nie zależy od głównego wątku Unity, użyj Task na potrzeby komunikacji zamiast wysyłania wiadomości.
  • Nie wysyłaj wielu wiadomości z wtyczki, gdy gra jest wstrzymana.
    • Silnik nie może wysyłać wiadomości, gdy gra działa w tle.
    • Wysyłaj ostatni stan danych do gry tylko wtedy, gdy nie ma to wpływu na grę funkcji.

Zainstaluj stronę odsyłającą

Strona odsyłająca do instalacji z Play to unikalny ciąg znaków wysyłany do Sklepu Play, gdy użytkownik klika reklamę. Jest to identyfikator śledzenia reklam specyficzny dla Androida. Jednorazowo aplikacja wysyła stronę odsyłającą do instalacji do partnera atrybucji, który dopasowuje źródło do instalacji (przypisuje konwersję).

Zrzut stosu

Rysunek 5 przedstawia zrzut stosu ANR z gry, która korzysta z pakietu SDK Facebooka, pobierze dane o atrybucji instalacji.

Rysunek 5. raport Android Vitals zawierający wywołanie Binder.

Przyczyna

Błąd ANR został spowodowany przez powolne wywołanie Binder. Nie możemy jednak określić bez dostępu do kodu źródłowego pakietu SDK.

Rozwiązanie

Rozwiązanie tego typu problemów wymaga komunikacji z deweloperem pakietu SDK lub często szukają w internecie potencjalnego rozwiązania, sprawdzając, czy nowszy model pozwala na rozwiązanie problemu ANR u innych. Czas eksperymentu jest też strategii wdrożenia.

Google udostępnia stronę indeksu SDK, która łączy dane o korzystaniu od aplikacji Google Play z informacjami zbieranymi za pomocą wykrywania kodu, dostarczają atrybuty i sygnały, które mają pomóc w podjęciu decyzji, zachować lub usunąć pakiet SDK z aplikacji.

Dodatkowe materiały

Więcej informacji o błędach ANR znajdziesz w tych materiałach: