ANR

當 Android 應用程式的 UI 執行緒遭封鎖的時間過長,會觸發「應用程式無回應」(ANR) 錯誤。Android Vitals 會在 Google Play 管理中心追蹤及回報 ANR 指標,協助您監控應用程式在各種裝置上的穩定性和回應速度。

Android Vitals 指標和門檻

Android Vitals 可協助您監控和改善應用程式的 ANR 發生率。Android Vitals 會測量多種 ANR 發生率:

  • ANR 發生率:遇到任何 ANR 類型的每日活躍使用人數百分比。
  • 使用者感知 ANR 事件的發生率:每日活躍使用者中,至少遇到一次使用者感知 ANR 事件的人數百分比。目前,只有 Input dispatching timed out 類型的 ANR 會視為使用者感知的 ANR。
  • 多次 ANR 發生率:遇到至少兩次 ANR 的每日活躍使用人數百分比。

「每日活躍使用者」是指在一天內透過單一裝置使用應用程式的不重複使用者,可能會執行多個工作階段。如果使用者在一天內透過多部裝置使用應用程式,系統會依裝置數量計算當天的活躍使用者。

使用者感知 ANR 事件的發生率屬於核心指標,會影響應用程式在 Google Play 的曝光度。這項指標非常重要,因為計入指標的 ANR 情形皆是在使用者與應用程式互動時發生,嚴重影響了使用者體驗。

Google Play 針對這項指標定義了兩個不良行為門檻:

  • 整體不良行為門檻:在各種裝置型號上,至少有 0.47% 的每日活躍使用者感知到 ANR 情形。
  • 每部裝置不良行為門檻:在單一裝置型號上,至少 8% 的每日活躍使用者感知到使用者感知 ANR 事件。

如果應用程式超出整體不良行為門檻,使用者可能比較不容易在所有裝置上找到該應用程式。如果應用程式在某些裝置上超出每部裝置不良行為門檻,使用者可能比較不容易在這些裝置上找到該應用程式,而且您的商店資訊中或許會顯示警告訊息。

Android Vitals 會在應用程式發生太多次 ANR 時,透過 Play 管理中心發出提醒。

如要瞭解 Google Play 如何收集 Android Vitals 資料,請參閱 Play 管理中心說明文件。

偵測問題

如果應用程式在前景執行時發生 ANR,系統會向使用者顯示對話方塊,如圖 1 所示。ANR 對話方塊可讓使用者選擇強制退出應用程式。

向使用者顯示的 ANR 對話方塊。
圖 1. 向使用者顯示的 ANR 對話方塊

ANR 會對使用者造成困擾,是個問題,發生原因是應用程式負責更新 UI 的主要執行緒無法處理使用者輸入事件或繪圖。如要進一步瞭解應用程式的主要執行緒,請參閱「程序和執行緒總覽」。

當發生以下任一種情形,應用程式就會觸發 ANR:

  • 輸入分派作業逾時:如果應用程式未在 5 秒內回應輸入事件 (例如按鍵或螢幕觸控事件)。
  • 執行服務:如果應用程式宣告的服務無法在幾秒內完成執行 Service.onCreate 和 Service.onStartCommand 或 Service.onBind。
  • 未呼叫 Service.startForeground:如果應用程式使用 Context.startForegroundService 在前景啟動新服務,但服務未在 5 秒內呼叫 startForeground。
  • 廣播意圖:如果 BroadcastReceiver 未在一定時間內完成執行。如果應用程式在前景有任何活動,逾時時間為 10 秒。
  • JobScheduler 互動:如果 JobService 未在幾秒內從 JobService.onStartJob 或 JobService.onStopJob 傳回;或者,如果使用者發起的工作啟動了,而您的應用程式在呼叫 JobService.onStartJob 後的幾秒內並未呼叫 JobService.setNotification。如果應用程式指定 Android 13 以下版本,則 ANR 不會發出通知,也不會回報給應用程式。如果指定 Android 14 以上版本,ANR 會發出通知,也會回報給應用程式。

除了 Android Vitals 之外,您也可以使用其他工具偵測現場的 ANR,但第三方工具無法回報 Android 10 (API 級別 29) 以下版本的 ANR。

診斷 ANR

以下是 ANR 常見的模式,可供您在診斷時參考:

  • 應用程式在主執行緒進行含有 I/O 的作業時速度過慢。
  • 應用程式在主要執行緒進行長時間的運算。
  • 主要執行緒向另一個程序發出同步繫結呼叫,而該程序回傳花費的時間過長。
  • 由於等待其他執行緒上進行長時間作業的同步區塊,導致主要執行緒遭到封鎖。
  • 主要執行緒在程序中或透過繫結呼叫和另一個執行緒形成死結。主執行緒不只要等待長時間作業完成,並會形成死結。

以下技巧可以幫助您判斷 ANR 的發生原因。

HealthStats

HealthStats 會擷取各項總計資料,包括使用者和系統時間、CPU 作業時間、網路、無線電統計資料、螢幕開啟/關閉時間和喚醒時間,藉此提供應用程式運作狀態的指標。這有助於評估整體 CPU 使用率與電池耗電。

偵錯

Debug 可協助您檢查開發期間的 Android 應用程式,包括追蹤和配置計數,以識別應用程式中的卡頓和延遲。您也可以使用 Debug 取得執行階段和原生記憶體計數器,以及有助於識別特定程序記憶體用量的記憶體指標。

ApplicationExitInfo

ApplicationExitInfo 支援 Android 11 (API 級別 30) 以上版本,並提供應用程式結束原因等相關資訊。這包括 ANR、低記憶體、應用程式當機、額外的 CPU 使用率、使用者中斷、系統中斷和執行階段權限變更。

嚴格模式

使用 StrictMode 可以幫助您在應用程式開發期間找出主要執行緒上意外發生的 I/O 作業。您可以在應用程式或活動層級使用 StrictMode。

啟用背景 ANR 對話方塊

只有在裝置的「開發人員選項」中已啟用「Show all ANRs」的情況下,Android 才會在應用程式處理廣播訊息時間過長時,顯示 ANR 對話方塊。因此,即使應用程式發生效能問題,使用者也不一定會看到背景 ANR 對話方塊。

剖析 CPU 和系統追蹤記錄

使用 Android Studio CPU 分析器,在遊戲執行時記錄系統追蹤和 CPU 活動。檢查主要 Activity 執行緒以及遊戲引擎的轉譯、音訊和背景工作執行緒,有助於在觸發 ANR 之前找出長影格、同步資產載入和執行緒爭用。

擷取追蹤檔

發生 ANR 時,Android 會儲存追蹤資訊。在較舊的 Android 版本中,裝置上會有一個 /data/anr/traces.txt 檔案。在較高的 Android 版本中,則會有多個 /data/anr/anr_* 檔案。您可以使用 Android Debug Bridge (adb) 做為根層級,存取裝置或模擬器中的 ANR 追蹤記錄:

adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>

您可以使用裝置上的「Take bug report」開發人員選項,或在開發機器上使用 adb bugreport 指令,在實體裝置上擷取錯誤報告。詳情請參閱「擷取及查看錯誤報告」。

修正問題

找出問題後,您可以使用本章節提到的方法修復常見問題。

主要執行緒上的過慢程式碼

在程式碼中,找出應用程式主執行緒忙碌時間超過 5 秒的部分。請尋找遊戲中可疑的用途,並嘗試重現 ANR。

在遊戲中,如果同步資產解壓縮、著色器編譯或繁重的遊戲狀態初始化作業在 Android 主 Activity 執行緒上執行 (例如在 onCreate、onResume 或從 UI 執行緒叫用的 JNI 回呼中),通常會發生主執行緒停滯。將遊戲迴圈執行、素材資源處理和場景初始化作業移至專屬引擎、轉譯或背景工作執行緒,讓主要執行緒能自由處理輸入和生命週期事件。

主執行緒上的 I/O

在主執行緒執行 I/O 作業,是造成主執行緒作業緩慢的常見原因,也可能導致 ANR。

將所有資產套件讀取、遊戲存檔序列化、SharedPreferences 存取和網路要求從主 Activity 執行緒移至背景工作執行緒,以免儲存空間或網路延遲阻礙輸入內容調度。

死結

當某執行緒需要的資源被另一個執行緒佔據而必須進入等待狀態,但是這另一個執行緒也正在等待第一個執行緒佔據的資源時,就會發生死結。如果應用程式的主執行緒有這種情形,就可能發生 ANR。

在遊戲中,Android 主 Activity 執行緒 (處理生命週期、介面或輸入回呼) 與原生 C 或 C++ 轉譯、邏輯或音訊執行緒之間,經常會發生死結和鎖定爭用。避免在主執行緒上同步等待原生引擎鎖定,並在 JNI 和引擎執行緒之間通訊時,使用一致的鎖定順序或無鎖定訊息佇列。

死結現象已在電腦科學領域中經過充分研究,目前已有演算法可用於防範這項問題。

詳情請參閱維基百科上的「死結」和「死結防範演算法」內容。

過慢的廣播接收器

應用程式可透過廣播接收器回應廣播訊息,例如啟用/停用飛航模式或變更連線狀態。當應用程式處理廣播訊息的時間過長,就會發生 ANR。

ANR 會在下列情況發生:

應用程式在 BroadcastReceiver 的 onReceive 方法內應該只能執行短作業。不過,如果應用程式因廣播訊息而需要進行更複雜的處理作業,且預計最多需要幾秒鐘的時間,則應將工作延後到背景工作執行緒;如果預計需要超過幾秒鐘的時間,則應延後到 WorkManager。

GameActivity

根據個案研究,在以 C 或 C++ 編寫的遊戲和應用程式中,GameActivity 程式庫可減少 ANR 情形。如果您將現有原生活動替換為 GameActivity,可以減少 UI 執行緒封鎖情況,並防止某些 ANR 發生。

如果您使用 Unity 建構遊戲,請參閱「對 Unity 遊戲的 ANR 進行偵錯」、「常見的 Unity 遊戲 ANR」和「將 Unity 遊戲的 Android 當機和 ANR 問題符號化」。

如要進一步瞭解 ANR,請參閱「讓應用程式維持正常回應速度」。如要進一步瞭解執行緒,請參閱「透過執行緒提升效能」。