일반적인 Unity 게임 ANR

Unity ANR은 다양한 이유로 발생합니다. 가장 일반적인 ANR의 원인은 다음과 같습니다. Android 및 Unity 구성요소의 오용과 이러한 구성요소의 커뮤니케이션 오류입니다.

WebView

WebView는 웹페이지를 표시하는 Android 클래스입니다. 서드 파티 SDK (예: 광고)는 WebView를 사용하여 동적 웹 콘텐츠를 표시합니다. UnityPlayerActivity 이외의 활동에서 ANR은 서드 파티가 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에서 버전을 확인하고 페이지 하단에서 버전을 확인합니다.
를 통해 개인정보처리방침을 정의할 수 있습니다. <ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">WebView 버전을 보여주는 앱 정보 화면</ph>
그림 1. WebView 버전을 확인하세요.

Unity 일시중지

UnityPlayerActivityonPause() 호출을 수신하면 다음 체인 다음 시점에 시작됩니다.

  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이 발생할 수 있습니다.

스택 트레이스

그림 4의 ANR은 Java 플러그인입니다. Unity 엔진은 비우선순위 상속을 사용하여 뮤텍스를 호출하여 올바르게 실행되도록 합니다.

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 설치 리퍼러는 앱이 Play 설치 또는 삭제될 때마다 Play 스토어로 전송되는 사용자가 광고를 클릭할 때 Android 전용 광고 추적 식별자입니다. 한 번 설치되면 앱은 설치 리퍼러를 기여 분석 파트너에게 전송합니다. 소스를 설치와 일치 (전환에 기여)합니다.

스택 트레이스

그림 5는 Facebook SDK를 사용하여 설치 기여 분석을 가져옵니다.

그림 5. 바인더 호출이 포함된 Android vitals 보고서

원인

느린 바인더 호출로 인해 ANR이 발생했습니다. 하지만 근본 원인은 SDK 소스 코드에 대한 액세스 권한이 없어도 결정됩니다

해결 방법

이러한 유형의 문제를 해결하려면 SDK 개발자 또는 잠재적 솔루션을 찾기 위해 온라인 검색을 많이 하고 있고, 다른 SDK의 ANR을 해결하거나 살펴보겠습니다

Google에서 사용 데이터를 통합한 SDK 색인 페이지를 제공합니다. 수집된 정보를 사용하여 Google Play 앱에서 특성과 신호를 제공하여 제품이 채택할지 판단하는 데 유지하거나 앱에서 SDK를 삭제할 수 있습니다.

추가 리소스

ANR에 관한 자세한 내용은 다음 리소스를 참고하세요.