Błędy typu Aplikacja nie odpowiada (ANR) są wywoływane, gdy wątek UI aplikacji nie odpowiada przez ponad 5 sekund. Więcej informacji o błędach ANR i ich diagnozowaniu znajdziesz w
dokumentacji Androida.
Crashlytics może też pomóc w określeniu konkretnych problematycznych wątków.Crashlytics Analizujemy błędy ANR, a następnie w panelu
DevOps i zaangażowanie > Crashlytics dashboard oznaczamy
odpowiednie wątki, aby podać wskazówki dotyczące debugowania błędów ANR.
W sekcjach poniżej wyjaśniamy, co oznacza każdy tag ANR, podajemy przykład błędu ANR z tym tagiem oraz zalecane rozwiązanie umożliwiające debugowanie błędu ANR.
Triggered ANR
Wątek, który był zablokowany zbyt długo i wywołał błąd ANR, jest oznaczony tagiem
Triggered ANR.
Problematyczny wątek może być wątkiem głównym aplikacji lub dowolnym wątkiem, który nie odpowiada. Wątek oznaczony tagiem
Triggered ANR może być lub nie być rzeczywistą przyczyną
błędu ANR. Aby dostarczyć informacji umożliwiających debugowanie i naprawianie tych błędów ANR,
Crashlytics oznacza też wszystkie inne wątki, które są powiązane z błędem ANR. W kolejnych sekcjach tej strony dowiesz się więcej o innych tagach, które można zastosować do wątku.
Deadlocked
Wszystkie wątki, które uczestniczyły w zakleszczeniu, które doprowadziło do błędu ANR, są
oznaczane tagiem Deadlocked.
Zakleszczenie występuje, gdy wątek przechodzi w stan oczekiwania, ponieważ wymagany zasób jest używany przez inny wątek, który również czeka na zasób używany przez pierwszy wątek. Jeśli w takiej sytuacji znajdzie się wątek główny aplikacji, prawdopodobnie wystąpią błędy ANR.
Zobacz przykład
Oto 2 wątki, które uczestniczą w zakleszczeniu:
main (unknown): tid=1 systid=1568
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.getPackage(PackageManagerService.java:22701)
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.filterOnlySystemPackages(PackageManagerService.java:22787)
...
com.android.server.SystemServer.main(SystemServer.java:368)
java.lang.reflect.Method.invoke(Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:517)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:934)
ActivityManager (unknown): tid=21 systid=1902
com.android.server.pm.PackageManagerService.getPackageSetting(PackageManagerService.java:23618)
com.android.server.pm.PackageManagerService.getPackageUid(PackageManagerService.java:4542)
...
android.os.Handler.handleCallback(Handler.java:907)
android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:216)
android.os.HandlerThread.run(HandlerThread.java:67)
com.android.server.ServiceThread.run(ServiceThread.java:44)
Rekomendacja
Sprawdź wątki uczestniczące w zakleszczeniu i zasoby/blokady uzyskane przez te wątki. Możliwe rozwiązania znajdziesz w artykułach
Deadlock i
Deadlock prevention algorithms.
IO Root blocking
Każdy wątek, który wykonywał powolne operacje wejścia-wyjścia i zablokował
Triggered ANR wątek jest oznaczony tagiem
IO Root blocking. Jeśli wątek
Triggered ANR nie jest zablokowany przez inne wątki,
to wątek IO Root blocking jest też wątkiem
Root blocking.
Zobacz przykłady
Thread main(THREAD_STATE_TIMED_WAITING)
sun.misc.Unsafe.park( Unsafe.java:0 )
java.util.concurrent.locks.LockSupport.parkNanos( LockSupport.java:230 )
android.database.sqlite.SQLiteConnectionPool.waitForConnection( SQLiteConnectionPool.java:756 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
Thread main(THREAD_STATE_NATIVE_WAITING)
Syscall
art::ConditionVariable::WaitHoldingLocks(art::Thread*)
art::GoToRunnable(art::Thread*)
art::JniMethodEnd(unsigned int, art::Thread*)
libcore.io.Linux.fdatasync( Linux.java:0 )
libcore.io.ForwardingOs.fdatasync( ForwardingOs.java:105 )
...
java.io.RandomAccessFile.write( RandomAccessFile.java:559 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
Rekomendacja
Ogólnie rzecz biorąc, aplikacja nie powinna wykonywać kosztownych operacji wejścia-wyjścia w wątku głównym. Jeśli wątek główny jest oznaczony tagiem
IO Root blocking, możesz też użyć
trybu ścisłego
aby zidentyfikować nieumyślne operacje wejścia-wyjścia wykonywane w wątku
głównym.
Root blocking
Każdy wątek, który zablokował wątek oznaczony tagiem
Triggered ANR jest oznaczony tagiem
Root blocking. Jeśli wątek jest oznaczony jednocześnie tagami
Root blocking i
Triggered ANR, to nie ma innych wątków, które
blokują ten wątek.
Jeśli jakiekolwiek Triggered ANR wątki oczekiwały (być może
przejściowo) na inne wątki, są one
Root blocking. Przyczyn, dla których wątek może być główną przyczyną błędu ANR, może być wiele.
Zobacz przykłady
Oto kilka przykładów opartych na stanie wątku:
Thread main(THREAD_STATE_RUNNABLE)
android.os.Parcel.createTypedArray( Parcel.java:3086 )
android.content.pm.PackageInfo.<init>( PackageInfo.java:546 )
...
android.app.ActivityThread$H.handleMessage( ActivityThread.java:2166 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:246 )
android.app.ActivityThread.main( ActivityThread.java:8633 )
Thread main(THREAD_STATE_BLOCKED)
DBHelper.runOnDB( DBHelper.java:97 )
DBHelper.runDb( DBHelper.java:125 )
...
java.lang.reflect.Method.invoke( Method.java:0 )
EventBus.invokeSubscriber( EventBus.java:510 )
postToSubscription( EventBus.java:437 )
...
android.os.Handler.handleCallback( Handler.java:938 )
android.os.Handler.dispatchMessage( Handler.java:99 )
android.os.Looper.loop( Looper.java:268 )
android.app.ActivityThread.main( ActivityThread.java:7904 )
Rekomendacja
Zminimalizuj obciążenie procesora w wątku głównym. Do wykonywania zadań obciążających procesor używaj wątków roboczych lub wątków działających w tle.
Zminimalizuj obciążenie wejścia-wyjścia, np. wczytywanie z bazy danych, w wątku głównym.
Unknown root cause
Wątek jest oznaczony tagiem Unknown root cause, jeśli
wywołał błąd ANR, ale w momencie wystąpienia błędu ANR był w procesie bezczynny. Crashlytics nie ma wystarczających informacji, aby określić
główną przyczynę. Nie ma oczywistego powodu, dla którego wystąpił ten błąd ANR.
Zobacz przykład
Thread main(THREAD_STATE_NATIVE_WAITING) __epoll_pwait
android::Looper::pollInner(int)
android::Looper::pollOnce(int, int*, int*, void**)
android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)
android.os.MessageQueue.nativePollOnce( MessageQueue.java:0 )
android.os.MessageQueue.next( MessageQueue.java:335 )
android.os.Looper.loop( Looper.java:193 )
android.app.ActivityThread.main( ActivityThread.java:8019 )
Rekomendacja
Postępuj zgodnie z ogólnymi wskazówkami dotyczącymi zapobiegania błędom ANR. Na przykład zidentyfikuj
miejsca w kodzie, w których wątek główny aplikacji może być zajęty przez ponad
5 sekund.