ANR 디버그

Unity 게임에서 ANR을 해결하는 것은 체계적인 프로세스입니다.

그림 1. Unity 게임에서 ANR을 해결하는 단계

보고 서비스 통합

Android vitals, Firebase Crashlytics, Backtrace (인증된 Unity 파트너)와 같은 보고 서비스는 대규모로 게임의 오류 로깅 및 분석을 제공합니다. 개발 주기 초기에 보고 서비스 SDK를 게임에 통합합니다. 게임 요구사항과 예산에 가장 적합한 보고 서비스를 분석합니다.

보고 서비스마다 ANR을 캡처하는 방법이 다릅니다. 두 번째 보고 서비스를 포함하여 ANR 수정 결정을 뒷받침하는 유효한 데이터를 얻을 가능성을 높이세요.

보고 SDK를 통합해도 게임 성능이나 APK 크기에 영향을 미치지 않습니다.

기호 분석

보고 서비스의 보고서를 분석하고 스택 트레이스가 사람이 읽을 수 있는 형식인지 확인합니다. 자세한 내용은 Unity 게임의 Android 비정상 종료 및 ANR 기호화를 참고하세요.

그림 2. 빌드 ID를 표시하고 libil2cpp.so 기호가 누락된 Crashlytics

기호 빌드 ID를 확인하는 방법

보고 시스템에 누락된 빌드 ID가 표시되지만 빌드 기계 저장소에 빌드 기호가 여전히 있는 경우 기호의 빌드 ID를 확인한 후 보고 서비스에 업로드할 수 있습니다. 그렇지 않으면 기호 파일을 업로드하려면 새 빌드가 필요합니다.

Windows 또는 macOS:

  1. 스크립팅 백엔드에 따라 기호 폴더로 이동합니다 (해결 방법 참고).
    1. 다음 명령어를 사용합니다 (Windows의 경우 Cygwin을 사용하여 readelf 유틸리티를 실행).
    2. 텍스트 출력을 필터링하는 데 Grep 사용은 선택사항입니다.
    3. 빌드 ID 찾기
readelf -n libil2cpp.so | grep 'Build ID'
Build ID: b42473fb7449e44e0182dd1f580c99bab0cd8a95

게임 코드 검사

스택 트레이스에 libil2cpp.so 라이브러리의 함수가 표시되면 C++로 변환된 C# 코드에서 오류가 발생한 것입니다. libil2cpp.so 라이브러리에는 게임 코드뿐만 아니라 플러그인과 패키지도 있습니다.

C++ 파일 이름은 Unity 프로젝트에 정의된 어셈블리 이름을 따릅니다. 그렇지 않으면 파일 이름에 기본 Assembly-C# 이름이 지정됩니다. 예를 들어 그림 3은 조합 정의 파일에 정의된 이름인 Game.cpp 파일 (파란색으로 강조 표시됨)의 오류를 보여줍니다. Logger은 C# 스크립트의 클래스 이름 (빨간색으로 강조 표시됨)이며 그 뒤에 함수 이름 (녹색으로 강조 표시됨)이 옵니다. 마지막으로 IL2CPP 변환기가 생성한 전체 이름 (주황색으로 강조표시됨)입니다.

그림 3. Backtrace에서 프로젝트 호출 스택을 테스트합니다.

다음을 수행하여 게임 코드를 검사합니다.

  • C# 프로젝트에서 의심스러운 코드를 검사합니다. 일반적으로 C#의 처리되지 않은 예외는 ANR이나 애플리케이션 비정상 종료를 일으키지 않습니다. 그렇더라도 다양한 상황에서 코드가 제대로 실행되는지 확인합니다. 코드가 서드 파티 엔진 모듈을 사용하는지 확인하고 최근 출시에서 오류가 발생했는지 분석합니다. 또한 최근에 Unity를 업데이트했는지 또는 오류가 특정 기기에서만 발생하는지 검토하세요.
  • 게임을 Android 스튜디오 프로젝트로 내보냅니다. 게임의 변환된 C# 소스 코드에 완전히 액세스하면 ANR을 유발하는 함수를 찾을 수 있습니다. C++ 코드는 C# 코드와 매우 다르게 보이며 코드 변환에는 문제가 거의 없습니다. 항목을 찾으면 Unity에 지원 티켓을 제출하세요.
  • 게임 소스 코드를 검토하고 OnApplicationFocus()OnApplicationPause() 콜백에서 실행되는 로직이 적절하게 정리되었는지 확인합니다.
    • Unity 엔진에는 실행을 일시중지하는 제한 시간이 있습니다. 이러한 콜백에 과도한 워크로드가 발생하면 ANR이 발생할 수 있습니다.
    • 코드의 일부에 로그 또는 탐색경로를 추가하여 데이터 분석을 개선합니다.
  • Unity 프로파일러를 사용하여 게임 성능을 조사합니다. 또한 앱을 프로파일링하면 ANR을 일으킬 수 있는 병목 현상을 식별하는 데 도움이 될 수 있습니다.
  • 기본 스레드에서 긴 I/O 작업을 식별하는 좋은 방법은 엄격 모드를 사용하는 것입니다.
  • Android vitals 또는 다른 보고 서비스 기록을 분석하고 오류가 가장 많이 발생하는 게임의 출시 버전을 확인합니다. 버전 제어 기록에서 소스 코드를 검토하고 출시 간에 코드 변경사항을 비교합니다. 의심스러운 사항이 발견되면 각 변경사항 또는 잠재적 해결책을 개별적으로 실험합니다.
  • ANR이 가장 많이 발생하는 기기 및 Android 버전의 Google Play ANR 보고 기록을 검토합니다. 기기나 버전이 오래되어도 게임의 수익성에 영향을 미치지 않는다면 무시해도 괜찮을 가능성이 높습니다. 특정 사용자 그룹이 더 이상 게임을 플레이할 수 없으므로 데이터를 주의 깊게 살펴보세요. 자세한 내용은 배포 대시보드를 참고하세요.
  • 게임 소스 코드를 검토하여 문제를 일으킬 수 있는 코드를 호출하지 않는지 확인합니다. 예를 들어 finish는 올바르게 사용되지 않으면 파괴적일 수 있습니다. Android 개발에 관한 자세한 내용은 Android 개발자 가이드를 참고하세요.
  • 데이터를 검토하고 게임 빌드를 Android 스튜디오로 내보낸 후에는 C 및 C++ 코드를 다루게 되므로 Android 메모리 프로파일러, Android CPU 프로파일러, perfetto와 같은 Unity의 표준 솔루션 외에도 다양한 도구를 최대한 활용할 수 있습니다.

Unity 엔진 코드

Unity 엔진 측에서 ANR이 발생하는지 확인하려면 스택 트레이스에서 libUnity.so 또는 libMain.so를 확인하세요. 찾으면 다음 단계를 따르세요.

  • 먼저 커뮤니티 채널 (Unity 포럼, Unity Discussions, Stackoverflow)을 검색합니다.
  • 아무것도 찾을 수 없는 경우 버그를 신고하여 문제를 해결하세요. 엔진 엔지니어가 오류를 더 잘 이해하고 해결할 수 있도록 기호화된 스택 트레이스를 제공합니다.
  • 최신 Unity LTS에서 문제와 관련된 사항이 개선되었는지 확인합니다. 이 경우 해당 버전을 사용하도록 게임을 업그레이드합니다. 이 솔루션은 일부 개발자에게만 가능할 수 있습니다.
  • 코드에서 기본값 대신 맞춤 Activity를 사용하는 경우 Java 코드를 검토하여 활동이 문제를 일으키지 않는지 확인합니다.

서드 파티 SDK

  • 모든 서드 파티 라이브러리가 최신 상태이고 최신 Android 버전의 비정상 종료 또는 ANR에 관한 보고서가 없는지 확인합니다.
  • Unity 포럼으로 이동하여 이후 버전에서 오류가 이미 해결되었는지 또는 Unity 또는 커뮤니티 회원이 해결 방법을 제공했는지 확인합니다.
  • Google Play ANR 보고서를 검토하고 Google에서 아직 오류를 식별하지 않았는지 확인합니다. Google은 일부 ANR을 인지하고 있으며 문제를 해결하기 위해 적극적으로 노력하고 있습니다.

시스템 라이브러리

시스템 라이브러리는 일반적으로 개발자가 제어할 수 없지만 ANR의 상당한 비율을 차지하지는 않습니다. 라이브러리 개발자에게 문의하거나 로그를 추가하여 문제를 파악하는 것 외에는 시스템 라이브러리 ANR을 해결하기가 어렵습니다.

종료 이유

ApplicationExitInfo는 ANR 원인을 파악하기 위한 Android API입니다. 게임에서 Unity 6 이상을 사용하는 경우 ApplicationExitInfo를 직접 호출할 수 있습니다. 이전 Unity 버전의 경우 자체 플러그인을 구현하여 Unity에서 ApplicationExitInfo 호출을 사용 설정해야 합니다.

Crashlytics도 ApplicationExitInfo를 사용합니다. 하지만 자체 구현을 사용하면 더 세부적으로 제어하고 더 관련성 높은 정보를 포함할 수 있습니다.