常見的 Unity 遊戲 ANR

Unity ANR 發生的原因很多,最常見的 ANR 發生原因是 以及 Android 和 Unity 元件遭濫用的情形

WebView

WebView 是顯示網頁的 Android 類別。第三方 SDK (例如廣告) 會使用 WebView 顯示動態網頁內容 在 UnityPlayerActivity 以外的活動中。這是因為第三方服務供應商 SDK 濫用 WebView

堆疊追蹤

如要瞭解 ANR 發生的原因,首先要學習堆疊追蹤。

/data/app/~~p-0ksfCD6bF6Sdq6kpVePg==/com.google.android.webview-5YQZOqKbbqp-uoLY6WYnTw==/base.apk!libmonochrome.so
  at J.N.Mhc_M_H$ (Native method)
  at org.chromium.components.viz.service.frame_sinks.ExternalBeginFrameSourceAndroid.doFrame (chromium-TrichromeWebViewGoogle.aab-stable-579013831:60)
  at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1054)
  at android.view.Choreographer.doCallbacks (Choreographer.java:878)
  at android.view.Choreographer.doFrame (Choreographer.java:807)
  at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1041)
  at android.os.Handler.handleCallback (Handler.java:938)
  at android.os.Handler.dispatchMessage (Handler.java:99)
  at android.os.Looper.loop (Looper.java:223)
  at android.app.ActivityThread.main (ActivityThread.java:7721)
  at java.lang.reflect.Method.invoke (Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:952)

圖 1:「futex」等待造成的 ANR 堆疊追蹤。

原因

目前為止,我們還不清楚這個問題的根本原因,部分可能原因 包括:

  • 廣告導入方式錯誤。
  • WebView 版本過舊,因為使用者可能選擇不更新 應用程式就會自動播放。
  • 系統資源 (CPU、GPU 等) 會耗用大量資源,因此可能需要
  • 著色器編譯異常終止,這可能表示 內容含有不相容的著色器,或使用者使用舊版 WebView 已安裝的版本。

解決方案

  • 進一步縮小導致 WebView 封鎖 建議您在遊戲中加入記錄後,每次載入網頁時 或封閉的容器
    • 您可以使用 BacktraceCrashlytics 報表服務
    • 分析資料並找到問題後,請嘗試停用 不利於廣告供應商
    • 附上記憶體記錄,確保問題與記憶體無關。
  • 提醒使用者透過 Google Play 更新 WebView。從 Android 5.0 轉移 (API 級別 21) 以上版本,WebView 已移至 APK。因此, 會獨立於 Android 平台更新查看「WebView」的版本 仍在使用中,請依序前往 [設定] > [設定]>應用程式 >Android 系統 WebView 來查看頁面底部的版本。
,瞭解如何調查及移除這項存取權。
顯示 WebView 版本的應用程式資訊畫面。
圖 1.查看 WebView 版本。

Unity 暫停

UnityPlayerActivity 收到 onPause() 呼叫時,下列鏈結的 作業開始:

  1. UnityPlayerActivity 會通知 Unity 執行階段引擎,該活動 已暫停
  2. Unity 會呼叫導入MonoBehaviour OnApplicationPause 事件。
  3. Unity 會停止其元件和模組,例如音效播放、轉譯、 包括遊戲迴圈和動畫
  4. 確認 Unity Android Player (UAP) 和引擎 ,UAP 會等待 4 秒,讓引擎停止。
  5. 如果這項作業超過 5 秒,系統會觸發 ANR。

堆疊追蹤

"main" tid=1 Timed Waiting
jdk.internal.misc.Unsafe.park (Native method)
java.util.concurrent.locks.LockSupport.parkNanos (LockSupport.java:234)
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos (AbstractQueuedSynchronizer.java:1079)
java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos (AbstractQueuedSynchronizer.java:1369)
java.util.concurrent.Semaphore.tryAcquire (Semaphore.java:415)
com.unity3d.player.UnityPlayer.pauseUnity (UnityPlayer.java:833)
com.unity3d.player.UnityPlayer.pause (UnityPlayer.java:796)
com.unity3d.player.UnityPlayerActivity.onPause (UnityPlayerActivity.java:117)
android.app.Activity.performPause (Activity.java:8517)
android.app.Instrumentation.callActivityOnPause (Instrumentation.java:1618)
android.app.ActivityThread.performPauseActivityIfNeeded (ActivityThread.java:5061)
android.app.ActivityThread.performPauseActivity (ActivityThread.java:5022)
android.app.ActivityThread.handlePauseActivity (ActivityThread.java:4974)
android.app.servertransaction.PauseActivityItem.execute (PauseActivityItem.java:48)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:179)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:97)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2303)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:201)
android.os.Looper.loop (Looper.java:288)
android.app.ActivityThread.main (ActivityThread.java:7884)
java.lang.reflect.Method.invoke (Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)

圖 3. 因未發布的區間而造成 ANR。

解決方案

請讓 C# 遊戲程式碼在執行期間不會過長 暫停或繼續活動

  • 分析遊戲,檢查 OnApplicationPause 是否昂貴 作業。您可以使用 Stopwatch
  • 避免 I/O 作業或同步網路要求。
  • 使用Thread Task。Unity 2023.1 支援簡化版 使用 C# 的非同步程式設計模型 asyncawait 個關鍵字。

已封鎖 UnitySendMessage

Java Unity 外掛程式和 SDK 使用 JNI 將資料傳送至 C# 遊戲層。 不過,由於原生用戶端的 同步處理日常安排 (例如互斥鎖),造成 ANR 因鎖定爭用情形而造成 ANR。

堆疊追蹤

圖 4 中的 ANR 是由於 C# 程式碼中呼叫的長時間作業所致 Java 外掛程式。Unity 引擎使用「非優先順序繼承」 Mutex,以確保正確執行。

libc.so NonPI::MutexLockWithTimeout(pthread_mutex_internal_t*, bool, timespec const*) + 604
com.unity3d.player.UnityPlayer.nativeUnitySendMessage (Native method)
com.unity3d.player.UnityPlayer.UnitySendMessage (UnityPlayer.java:665)

圖 4.因鎖定爭用而產生的 ANR。

原因

問題在於當應用程式正在傳送多封郵件 就會重新啟用。訊息無法在遊戲時傳送,因此已排入佇列 都是在背景執行系統會在 就會繼續播放。

在暫停期間,您通常會將遊戲資訊儲存在 伺服器;例如記錄玩家在遊戲中的位置 就能在遊戲繼續後返回同一個位置。

工作負載,加上其他第三方程式碼建立專屬工作負載 可能導致裝置的資源超載,尤其是主執行緒。主要 執行緒會執行應用程式的使用者介面,通常是 ANR 的主要位置。所以 任何新增的工作負載都會增加發生 ANR 的機率。

解決方案

在應用程式暫停期間,請務必備妥所有程式碼動作。 請嘗試將使用者的狀態儲存至本機裝置記憶體當然,也別忘了 您是否能在暫停期間以外完成這些操作。

幾種做法

  • 將處理訊息的 C# 作業移至執行緒 除主執行緒外。
    • 如果您的程式碼不會依賴 Unity 的主執行緒結構定義,請使用 Task 用於通訊,而不是訊息。
  • 遊戲暫停時,請勿使用外掛程式傳送多則訊息。
    • 當遊戲在背景執行時,引擎無法傳送訊息。
    • 只在不影響遊戲的情況下傳送最新資料狀態給遊戲 功能。

安裝參照網址

Play Install Referrer 是一組不重複的字串,系統會在每次有人造訪 Play 商店時 使用者點按廣告這是 Android 專屬的廣告追蹤 ID。一次 應用程式安裝時,應用程式會將安裝參照網址傳送給歸因合作夥伴 與安裝來源相符 (轉換歸因)。

堆疊追蹤

圖 5 顯示使用 Facebook SDK 執行以下動作的遊戲的 ANR 堆疊追蹤: 擷取安裝歸因。

圖 5. 包含 Binder 呼叫的 Android Vitals 報告。

原因

這個 ANR 原因是繫結器呼叫速度緩慢。不過,問題的根本原因 而無需存取 SDK 原始碼即可決定

解決方案

如要解決這類問題,您需要與 SDK 開發人員或 的消費者大量上網尋找可行的解決方案,查看是否推出 SDK 版本對其他人解決了 ANR 問題 推出策略

Google 提供結合使用資料的 SDK 索引頁面 並擷取透過程式碼偵測作業收集到的資訊, 提供有助你決定是否採用、 保留或移除應用程式中的 SDK

其他資源

如要進一步瞭解 ANR,請參閱下列資源: