ANR 디버그

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

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

보고 서비스 통합

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

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

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

기호 분석

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

그림 2. Crashlytics에서 빌드 ID를 표시하며 libil2cpp.so 기호가 누락되었습니다.

기호 빌드 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 프로젝트에 정의된 어셈블리 이름을 따릅니다. 그렇지 않은 경우 파일 이름은 기본 어셈블리-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 토론, Stackoverflow)을 검색합니다.
  • 아무것도 발견되지 않으면 버그를 신고하여 문제를 해결합니다. 엔진의 엔지니어가 오류를 더 잘 이해하고 해결할 수 있도록 기호화된 스택 트레이스를 제공합니다.
  • 최신 Unity LTS에서 문제와 관련된 개선사항이 있는지 확인하세요. 이 경우 해당 버전을 사용하도록 게임을 업그레이드하세요. (이 솔루션은 일부 개발자에게만 제공될 수 있습니다.)
  • 코드에서 기본값 대신 맞춤 Activity를 사용하는 경우 자바 코드를 검토하여 활동이 문제를 일으키지 않는지 확인합니다.

서드 파티 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을 사용하지만 자체 구현에서는 보다 세밀하게 제어할 수 있으며 보다 관련성 높은 정보를 포함할 수 있습니다.