ANR をデバッグする

Unity ゲームの ANR の解決は体系的なプロセスです。

図 1. Unity ゲームの ANR を解決する手順。

レポート サービスを統合する

Android VitalsFirebase CrashlyticsBacktrace(認定 Unity パートナー)などのレポート サービスを使用すると、ゲームのエラーを大規模にロギングして分析できます。開発サイクルの早い段階で、レポート サービスの SDK をゲームに統合します。ゲームのニーズと予算に最適なレポート サービスについて分析します。

レポート サービスによって、ANR をキャプチャする方法が異なります。2 つ目のレポート サービスを追加して、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# スクリプトのクラス名(赤色でハイライト表示)で、その後に関数名(緑色でハイライト表示)が続きます。Finally は、IL2CPP コンバータが生成した完全な名前です(オレンジ色でハイライト表示されています)。

図 3. Backtrace からプロジェクトのコールスタックをテストする。

次の手順でゲームコードを検査します。

  • C# プロジェクトに不審なコードがないか確認します。通常、C# の未処理例外は ANR やアプリのクラッシュを引き起こしません。それでも、さまざまな状況でコードが正しく実行されるようにしてください。コードがサードパーティ エンジン モジュールを使用しているかどうかを確認し、最近のリリースでエラーが発生したかどうかを分析します。また、Unity を最近更新したかどうかや、エラーが特定のデバイスでのみ発生するかどうかも確認します。
  • ゲームを Android Studio プロジェクトとしてエクスポートします。ゲームの変換された C# ソースコードに完全にアクセスできるため、ANR の原因となっている関数を見つけることができます。C++ コードは C# コードとは非常に異なり、コード変換で問題が発生することはほとんどありません。問題が見つかった場合は、Unity にサポート チケットを提出してください。
  • ゲームのソースコードを確認し、OnApplicationFocus() コールバックと OnApplicationPause() コールバックで実行されているロジックが適切にクリーンアップされていることを確認します。
    • Unity エンジンには、実行を一時停止するためのタイムアウトがあります。これらのコールバックでワークロードが過剰になると、ANR が発生する可能性があります。
    • コードの一部にログやパンくずリストを追加して、データ分析を強化します。
  • Unity Profiler を使用してゲームのパフォーマンスを調査します。アプリのプロファイリングは、ANR の原因となっている可能性のあるボトルネックを特定するのにも役立ちます。
  • メインスレッドで長時間の I/O オペレーションを特定するには、厳格モードを使用するのが効果的です。
  • Android Vitals または他のレポート サービスの履歴を分析し、エラーが発生する頻度が最も高いゲームのリリース バージョンを確認します。バージョン管理履歴でソースコードを確認し、リリース間のコード変更を比較します。疑わしいものが見つかった場合は、変更や修正案を個別にテストします。
  • ANR が最も多く発生しているデバイスと Android バージョンの Google Play ANR レポート履歴を確認します。デバイスやバージョンが古い場合、ゲームの収益性に影響しない限り、無視しても問題ありません。特定のユーザー グループがゲームをプレイできなくなるため、データを慎重に検討してください。詳細については、配信ダッシュボードをご覧ください。
  • ゲームのソースコードを見直して、問題の原因となる可能性のあるコードを呼び出していないことを確認します。たとえば、finish は、正しく使用しないと破壊的になる可能性があります。Android 開発の詳細については、Android デベロッパー ガイドをご覧ください。
  • データを確認してゲームビルドを Android Studio にエクスポートしたら、C コードと C++ コードを扱います。そのため、Unity の標準ソリューション以外のツール(Android Memory ProfilerAndroid CPU Profilerperfetto など)を最大限に活用できるようになります。

Unity エンジン コード

Unity エンジン側で ANR が発生しているかどうかを確認するには、スタック トレース内の libUnity.so または libMain.so を確認します。見つかった場合は、次の手順を行います。

  • まず、コミュニティ チャネル(Unity フォーラムUnity ディスカッション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 が使用されますが、独自の実装ではより細かく制御でき、より関連性の高い情報を含めることができます。