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
封鎖 建議您在遊戲中加入記錄後,每次載入網頁時 或封閉的容器- 您可以使用 Backtrace 或 Crashlytics 報表服務
- 分析資料並找到問題後,請嘗試停用 不利於廣告供應商
- 附上記憶體記錄,確保問題與記憶體無關。
- 提醒使用者透過 Google Play 更新
WebView
。從 Android 5.0 轉移 (API 級別 21) 以上版本,WebView
已移至 APK。因此, 會獨立於 Android 平台更新查看「WebView
」的版本 仍在使用中,請依序前往 [設定] > [設定]>應用程式 >Android 系統 WebView 來查看頁面底部的版本。
Unity 暫停
當 UnityPlayerActivity
收到 onPause()
呼叫時,下列鏈結的
作業開始:
UnityPlayerActivity
會通知 Unity 執行階段引擎,該活動 已暫停- Unity 會呼叫導入
MonoBehaviour
OnApplicationPause
事件。 - Unity 會停止其元件和模組,例如音效播放、轉譯、 包括遊戲迴圈和動畫
- 確認
Unity Android Player
(UAP) 和引擎 ,UAP 會等待 4 秒,讓引擎停止。 - 如果這項作業超過 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# 的非同步程式設計模型async
和await
個關鍵字。
已封鎖 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
用於通訊,而不是訊息。
- 如果您的程式碼不會依賴 Unity 的主執行緒結構定義,請使用
- 遊戲暫停時,請勿使用外掛程式傳送多則訊息。
- 當遊戲在背景執行時,引擎無法傳送訊息。
- 只在不影響遊戲的情況下傳送最新資料狀態給遊戲 功能。
安裝參照網址
Play Install Referrer 是一組不重複的字串,系統會在每次有人造訪 Play 商店時 使用者點按廣告這是 Android 專屬的廣告追蹤 ID。一次 應用程式安裝時,應用程式會將安裝參照網址傳送給歸因合作夥伴 與安裝來源相符 (轉換歸因)。
堆疊追蹤
圖 5 顯示使用 Facebook SDK 執行以下動作的遊戲的 ANR 堆疊追蹤: 擷取安裝歸因。
原因
這個 ANR 原因是繫結器呼叫速度緩慢。不過,問題的根本原因 而無需存取 SDK 原始碼即可決定
解決方案
如要解決這類問題,您需要與 SDK 開發人員或 的消費者大量上網尋找可行的解決方案,查看是否推出 SDK 版本對其他人解決了 ANR 問題 推出策略
Google 提供結合使用資料的 SDK 索引頁面 並擷取透過程式碼偵測作業收集到的資訊, 提供有助你決定是否採用、 保留或移除應用程式中的 SDK
其他資源
如要進一步瞭解 ANR,請參閱下列資源: