Crashlytics ダッシュボードで ANR タグに基づいて Android アプリをデバッグする

アプリケーションの UI スレッドが 5 秒を超えて応答しない場合は、アプリケーション応答なし(ANR)エラーがトリガーされます。ANR とその診断の詳細については、Android のドキュメントをご覧ください。

また、問題のあるスレッドの特定には Crashlytics が役立ちます。Google は ANR を分析し、該当するスレッドにタグを付けて、Crashlytics ダッシュボードで ANR のデバッグ方法に関するヒントを提供します。

このページの以降のセクションでは、ANR の各タグの意味について説明し、タグが含まれる ANR の例を示し、ANR をデバッグする際に推奨される解決方法を紹介します。

Triggered ANR

長時間ブロックされて ANR をトリガーしたスレッドには、この Triggered ANR タグが付けられます。

問題のあるスレッドは、アプリのメインスレッドの場合もあれば、応答していないと判断された他のスレッドの場合もあります。ただし、Triggered ANR とタグ付けされたスレッドが ANR の実際の原因である場合と、そうではない場合があります。ANR のデバッグと修正を行うための分析情報を提供するために、Crashlytics は ANR に関連する他のスレッドにもタグを付けます。このページの以降のセクションでは、スレッドに付けられる可能性がある他のタグについて説明します。

Deadlocked

ANR の原因となったデッドロックに関連していると判断されたスレッドには、この Deadlocked タグが付けられます。

スレッド 1 が、スレッド 2 によって保持されているリソースが必要であるため待機状態に入り、スレッド 2 も、スレッド 1 によって保持されているリソースが必要であるため待機状態に入ると、デッドロックが発生します。アプリのメインスレッドがこの状況になった場合は、おそらく ANR が発生します。

デッドロックに関連している 2 つのスレッドの例を示します。

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

低速な I/O オペレーションを実行してして、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 )
  

推奨事項

一般的には、アプリのメインスレッドでは高負荷になる I/O オペレーションを実行しないでください。メインスレッドが IO Root blocking になった場合は、StrictMode を使用することによって、メインスレッドで発生している意図しない I/O オペレーションを特定できます。

Root blocking

Triggered ANR とタグ付けされたスレッドをブロックしたスレッドには、Root blocking タグが付けられます。スレッドに Root blockingTriggered 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 )
  

推奨事項

メインスレッドでは、CPU 使用率が高い処理を最小限に抑えてください。CPU 使用率が高いタスクの実行にはワーカー スレッド(バックグラウンド スレッド)を使用してください。

メインスレッドでは、データベースからの読み込みなど、I/O 負荷が高い処理を最小限に抑えてください。

Unknown root cause

あるスレッドが ANR をトリガーしたが、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 を防止するための一般的なアドバイスに従ってください。たとえば、アプリのメインスレッドが 5 秒を超えてビジー状態になる可能性があるコードの場所を特定します。