ANR 디버그

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

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

보고 서비스 통합

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

보고 서비스마다 ANR을 캡처하는 방법이 다릅니다. 두 번째 보고 서비스를 포함하여 ANR을 수정하는 데 도움이 되는 유효한 데이터를 얻을 가능성을 높입니다.

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

기호 분석

보고 서비스의 보고서를 분석하고 스택 트레이스가 사람이 읽을 수 있는 형식인지 확인합니다. 자세한 내용은 Symbolicate Android Unity 게임의 비정상 종료 및 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 엔진 코드

ANR이 Unity 엔진 측에서 발생하는지 알아보려면 스택 트레이스에서 libUnity.so 또는 libMain.so를 확인합니다. 이러한 항목을 찾으면 다음 단계를 따르세요.

  • 먼저 커뮤니티 채널 (Unity 포럼, Unity 토론, Stackoverflow)을 검색합니다.
  • 아무것도 찾지 못하면 버그를 신고하여 문제를 해결합니다. 엔진 엔지니어가 오류를 더 잘 이해하고 해결할 수 있도록 기호화된 스택 트레이스를 제공합니다.
  • 최신 Unity LTS에서 문제와 관련된 개선사항이 있는지 확인합니다. 그렇다면 게임을 업그레이드하여 해당 버전을 사용합니다. (이 솔루션은 일부 개발자에게만 가능할 수 있습니다.)
  • 코드가 기본 Activity 대신 맞춤 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를 사용하지만 자체 구현을 사용하면 더 세밀하게 제어하고 더 관련성 높은 정보를 포함할 수 있습니다.