Ошибки ANR ("Приложение не отвечает") возникают, когда поток UI приложения не отвечает более пяти секунд. Подробную информацию об ошибках ANR и их диагностике можно найти в документации Android.
Кроме того, Crashlytics помогает выявлять проблемные цепочки писем. Мы анализируем ошибки ANR и на панели DevOps & Engagement (DevOps и вовлеченность) > Crashlytics помечаем подходящие потоки, чтобы помочь вам отладить ошибку ANR.
В разделах ниже объясняется, что означает каждый тег ANR, приводится пример ошибки ANR с этим тегом и предлагается решение для отладки.
Triggered ANR
Поток, который был заблокирован слишком долго и вызвал ANR, отмечен тегом Triggered ANR.
Проблемным может быть основной поток приложения или любой другой поток, который не отвечает. Однако поток, помеченный как Triggered ANR, может быть или не быть фактической причиной ошибки ANR. Чтобы помочь вам отладить и устранить ошибки ANR, Crashlytics также отмечает все другие потоки, связанные с ошибкой ANR. В следующих разделах этой страницы рассказывается о других тегах, которые можно применить к теме.
Deadlocked
Все потоки, которые были вовлечены во взаимную блокировку, приведшую к ошибке ANR, помечаются тегом Deadlocked.
Взаимная блокировка возникает, когда поток переходит в состояние ожидания, поскольку необходимый ресурс удерживается другим потоком, который также ожидает ресурс, удерживаемый первым потоком. Если основной поток приложения находится в таком состоянии, скорее всего, возникнет ошибка ANR.
Посмотреть пример
Вот два потока, которые находятся в состоянии взаимной блокировки:
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)
Рекомендация
Посмотрите на потоки, участвующие в блокировке, и проверьте ресурсы/блокировки, полученные этими потоками. Возможные решения описаны в статьях Взаимная блокировка и Алгоритмы предотвращения взаимной блокировки.
IO Root blocking
Любой поток, который выполнял медленные операции ввода-вывода и блокировал поток Triggered ANR, аннотируется тегом IO Root blocking. Если поток Triggered ANR не заблокирован другими потоками, то поток IO Root blocking также является потоком Root blocking.
Посмотреть примеры
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 )
Рекомендация
Как правило, в основном потоке приложения не должны выполняться ресурсоемкие операции ввода-вывода. Если основной поток IO Root blocking, вы также можете использовать строгий режим, чтобы выявить любые непреднамеренные операции ввода-вывода, выполняемые в основном потоке.
Root blocking
Любая цепочка, заблокировавшая цепочку, помеченную тегом Triggered ANR, аннотируется тегом Root blocking. Если цепочка помечена как Root blocking и Triggered ANR, то нет других цепочек, которые блокируют эту цепочку.
Если какие-либо потоки Triggered ANR ожидали (возможно, транзитивно) другие потоки, они будут Root blocking. Причины, по которым поток может быть основной причиной ошибки ANR, могут быть разными.
Посмотреть примеры
Вот несколько примеров на основе состояния цепочки:
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 )
Рекомендация
Минимизируйте работу, требующую больших ресурсов процессора, в основном потоке. Используйте рабочие или фоновые потоки для выполнения задач, требующих значительных ресурсов процессора.
Старайтесь не выполнять в основном потоке операции ввода-вывода, например загрузку из базы данных.
Unknown root cause
Если поток вызвал ошибку ANR, но был неактивен в процессе, когда она произошла, он помечается тегом Unknown root cause. Crashlytics не располагает достаточной информацией, чтобы определить первопричину. Причина ошибки ANR не очевидна.
Посмотреть пример
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 )
Рекомендация
Следуйте общим рекомендациям по предотвращению ошибок ANR. Например, определите в коде места, где основной поток приложения может быть занят более пяти секунд.
Waiting for binder call
Все потоки, которые ожидали вызова связывателя и блокировали поток Triggered ANR, помечаются тегом Waiting for binder call. Если поток Triggered ANR не заблокирован другими потоками, то поток Waiting for binder call также является потоком Root blocking.
Посмотреть пример
Thread main(THREAD_STATE_NATIVE_WAITING)
syscall
android::IPCThreadState::talkWithDriver(bool)
android::IPCThreadState::waitForResponse(android::Parcel*, int*)
android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android_os_BinderProxy_transact(_JNIEnv*, _jobject*, int, _jobject*, _jobject*, int)
android.os.BinderProxy.transactNative( BinderProxy.java:0 )
android.os.BinderProxy.transact( BinderProxy.java:540 )
android.app.IActivityManager$Stub$Proxy.getContentProvider( IActivityManager.java:5945 )
android.app.ActivityThread.acquireProvider( ActivityThread.java:7138 )
android.app.ActivityThread$H.handleMessage( ActivityThread.java:1982 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:236 )
android.app.ActivityThread.main( ActivityThread.java:8037 )
Рекомендация
Поскольку задержка вызова механизма Binder может быть непредсказуемой, относитесь к таким вызовам как к операциям ввода-вывода и по возможности не выполняйте их в основном потоке. Перенесите код, который вызывает механизм Binder (включая вызовы API платформы, приводящие к транзакциям Binder), в фоновый поток или кэшируйте результаты, если вызов из основного потока неизбежен.