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 Crashlytics może też pomóc w określeniu konkretnych problematycznych wątków. 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 sekcjach poniżej dowiesz się więcej o innych tagach, które można zastosować do wątku.
Deadlocked
Wszystkie wątki, które są powiązane z zakleszczeniem, 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ątek główny aplikacji znajduje się w takiej sytuacji, prawdopodobnie wystąpią błędy ANR.
Zobacz przykład
Oto 2 wątki powiązane z zakleszczeniem:
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 powiązane z zakleszczeniem i zasoby/blokady uzyskane przez te wątki. Możliwe rozwiązania znajdziesz w sekcji
Algorytmy zapobiegania zakleszczeniom.
IO Root blocking
Każdy wątek, który wykonywał wolne operacje wejścia-wyjścia i zablokował wątek
Triggered ANR 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 czekały (być może
przejściowo) na inne wątki, są one oznaczone tagiem
Root blocking. Przyczyn, dla których wątek jest 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 jego wystąpienia był w stanie bezczynności. 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.