找出無回應的會話串

本文說明如何找出 ANR 堆疊傾印中的無回應執行緒。非回應執行緒因 ANR 類型而異,如下表所示。

ANR 類型 討論串無回應
輸入分派 主要執行緒
未聚焦在輸入分派作業期間 主執行緒。這類 ANR 通常並非由執行緒遭到封鎖所致。
廣播接收器 (同步) 執行 onReceive() 的執行緒。除非使用 Context.registerReceiver 指定非主執行緒上的自訂處理常式,否則這是主執行緒。
廣播接收器 (非同步) 請檢查程式碼,瞭解哪些執行緒或執行緒集區是由哪個執行緒或執行緒集區負責在呼叫 goAsync 後處理廣播訊息。
執行服務逾時 主要執行緒
前景服務啟動 主要執行緒
內容供應器沒有回應 符合以下任一條件:
  • 如果內容供應器查詢速度緩慢導致 ANR,就屬於繫結執行緒。
  • 主要執行緒是因應用程式啟動時間過長而導致 ANR。
沒有回應「onStartJob」或「onStopJob 主要執行緒

有時候,執行緒會因不同的執行緒或程序的根本原因而沒有回應。執行緒可能沒有回應,原因如下:

  • 其他執行緒保留的鎖定。
  • Binder 呼叫其他程序速度緩慢。

無回應執行緒的常見原因

以下是執行緒無回應的常見原因。

Binder 呼叫速度緩慢

雖然大部分繫結器呼叫快速,但長尾連線的速度可能非常慢。如果裝置已載入或繫結器回應執行緒速度緩慢 (例如鎖定爭用、多次傳入繫結器呼叫或硬體抽象層 (HAL) 逾時),就很有可能發生這種情況。

如要解決這個問題,請在可能的情況下將同步繫結器呼叫移至背景執行緒。如果呼叫必須在主執行緒上進行,請找出呼叫速度緩慢的原因。最佳做法是來自 Perfetto 追蹤記錄。

在堆疊中尋找 BinderProxy.transactNativeBinderproxy.transact。這表示正在進行 Binder 呼叫。看完這兩行後 您可以看到呼叫的繫結器 API在以下範例中,呼叫為 IAccessibilityManager.addClient

main tid=123

...
android.os.BinderProxy.transactNative (Native method)
android.os.BinderProxy.transact (BinderProxy.java:568)
android.view.accessibility.IAccessibilityManager$Stub$Proxy.addClient (IAccessibilityManager.java:599)
...

連續多個繫結器呼叫

在緊密迴圈中執行多個連續的繫結器呼叫,可能會長時間封鎖執行緒。

封鎖的 I/O

切勿在主執行緒上執行封鎖 I/O。這是反面模式。

鎖定爭用

如果執行緒在獲取鎖定時遭到封鎖,則可能導致 ANR。

以下範例顯示主要執行緒在嘗試取得鎖定時遭到封鎖:

main (tid=1) Blocked

Waiting for com.example.android.apps.foo.BarCache (0x07d657b7) held by
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD
[...]
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5412)
[...]

封鎖執行緒正在發出 HTTP 要求以下載影片:

ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD (tid=110) Waiting

at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1047)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230)
at com.example.android.apps.foo.HttpRequest.execute(HttpRequest:136)
at com.example.android.apps.foo$Task$VideoLoadTask.downloadVideoToFile(RequestExecutor:711)
[...]

昂貴的影格

在單一影格中算繪過多事物可能會導致主執行緒在影格期間沒有回應,例如:

  • 轉譯許多不必要的畫面外項目。
  • 算繪多個 UI 元素時,使用效率不佳的演算法,例如 O(n^2)

已由其他元件封鎖

如果廣播接收器等其他元件封鎖超過五秒,可能會導致輸入分派 ANR 和嚴重卡頓。

避免在應用程式元件的主執行緒上進行任何繁重的工作。請盡可能在不同執行緒上執行廣播接收器。