Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

アプリのデバッグ

Android Studio はデバッガを備えており、以下の処理などを行うことができます。

  • デバイスを選択して、アプリをデバッグする。
  • Java、Kotlin、C / C++ のコード内にブレークポイントを設定する。
  • ランタイムにおける変数の検査や式の評価を行う。

このページでは、デバッガ操作の基本的な手順について説明します。詳細については、IntelliJ IDEA デバッグ ドキュメントをご覧ください。

デバッグを有効にする

デバッグを開始する前に、以下のように準備する必要があります。

  • 使用しているデバイスでデバッグを有効にします。

    エミュレータを使用している場合は、デフォルトで有効になっています。ただし、接続されているデバイスについては、デバイスの開発者向けオプションでデバッグを有効化する必要があります。

  • デバッグ可能なビルド バリアントを実行します。

    ビルド構成内に debuggable true を含むビルド バリアントを使用する必要があります。通常は、各 Android Studio プロジェクトに含まれているデフォルトの「debug」バリアントを選択するだけで済みます(ただし、build.gradle ファイル内には表示されません)。新しいデバッグ可能なビルドタイプを定義する場合は、ビルドタイプに「debuggable true」を追加する必要があります。

    android {
        buildTypes {
            customDebugType {
                debuggable true
                ...
            }
        }
    }
    

    このプロパティは、C / C++ コードを含むモジュールにも適用されます(jniDebuggable プロパティは使用されなくなりました)。

    アプリが依存しているライブラリ モジュールについてもデバッグを行う場合は、デバッグ シンボルを維持するため、そのライブラリも debuggable true を指定してパッケージ化する必要があります。アプリ プロジェクトのデバッグ可能バリアントでライブラリ モジュールのデバッグ可能バリアントを確実に受け取れるようにするには、必ずライブラリの非デフォルト バージョンを公開するようにしてください。

デバッグを開始する

デバッグ セッションを開始する手順は次のとおりです。

  1. アプリコード内にブレークポイントを設定します。
  2. ツールバーで、対象デバイスのプルダウン メニューからアプリをデバッグするデバイスを選択します。

    対象デバイスのプルダウン メニュー

    構成済みのデバイスがない場合は、USB 経由でデバイスを接続するか、AVD を作成して Android Emulator を使用する必要があります。

  3. ツールバーの [Debug] ボタン をクリックします。

    「run」から「debug」に切り替えてよいか尋ねるダイアログが表示された場合、アプリがすでにデバイス上で稼働していることを示しており、デバッグを開始する際にアプリが再起動されます。アプリ インスタンスを稼働したままにしたい場合は、[Cancel Debug] をクリックして、代わりに、実行中のアプリにデバッガをアタッチします。

    その他の場合は、Android Studio で APK がビルドされます。その APK は、デバッグ鍵で署名された後に、選択したデバイスにインストールされ、実行されます。プロジェクトに C / C++ コードを追加した場合は、ネイティブ コードのデバッグのために、[Debug] ウィンドウ内に LLDB デバッガも実行されます。

  4. [Debug] ウィンドウが開かない場合は、[View] > [Tool Windows] > [Debug] を選択(またはツール ウィンドウ バーで [Debug] をクリック)して、[Debugger] タブをクリックします(図 1 を参照)。

    図 1. 現在のスレッドと変数のオブジェクト ツリーが表示されている [Debugger] ウィンドウ

実行中のアプリにデバッガをアタッチする

アプリがすでにデバイス上で稼働している場合は、以下の手順により、アプリを再起動せずにデバッグを開始できます。

  1. [Attach debugger to Android process] ボタン をクリックします。
  2. [Choose Process] ダイアログで、デバッガをアタッチするプロセスを選択します。

    エミュレータやユーザーに root 権限のあるデバイスを使用している場合は、[Show all processes] をオンにすると、すべてのプロセスが表示されます。

    [Debugger] プルダウン メニューから、別のデバッグタイプを選択できます。デフォルトでは、Android Studio は Auto デバッグタイプを使用して、プロジェクトに含まれているコードの種類(Java または C / C++)に応じて最適なデバッガ オプションを選択します。

  3. [OK] をクリックします。

    [Debug] ウィンドウが表示されます。

注: Android Studio のデバッガとガベージ コレクタは緩く統合されています。Android 仮想マシンでは、デバッガが切断されるまで、デバッガが認識しているオブジェクトに対してガベージ コレクションは行われません。これにより、デバッガが接続されている間、時間とともにオブジェクトが蓄積される可能性があります。たとえば、実行中のスレッドがデバッガに認識されている場合、それに関連付けられた Thread オブジェクトは、スレッドが終了してもデバッガが切断されるまでガベージ コレクションの対象になりません。

デバッガタイプを変更する

Java / Kotlin コードをデバッグする場合と C / C++ コードをデバッグする場合では、異なるデバッガツールが必要となるため、Android Studio デバッガでは、使用するデバッガタイプを選択できるようになっています。デフォルトでは、Android Studio はプロジェクト内で検出された言語に基づいて、使用するデバッガを決定します(Auto デバッガタイプを使用します)。別のデバッガを使用する場合は、[Run] > [Edit Configurations] をクリックして表示されるデバッグ設定や、[Run] > [Attach debugger to Android process] をクリックして表示されるダイアログで、手動で選択できます。

利用できる主なデバッグタイプは次のとおりです。

Auto
デバッグするコードに最適なオプションが Android Studio により自動的に選択されるようにする場合にこのデバックタイプを指定します。たとえば、プロジェクトに C / C++ コードが含まれている場合は、自動的に Dual デバッグタイプが使用されます。そうでない場合は、Java デバッグタイプが使用されます。
Java
Java または Kotlin で記述されたコードのみをデバッグする場合にこのデバックタイプを指定します。Java デバッガでは、ネイティブ コード内に設定したブレークポイントやウォッチは無視されます。
Native(C / C++ コードが含まれている場合のみ)
LLDB のみを使用してコードをデバッグする場合にこのデバックタイプを指定します。このデバッグタイプを使用した場合、Java デバッガのセッション ビューは利用できません。デフォルトでは、LLDB はネイティブ コードだけを検証し、Java コード内のブレークポイントを無視します。Java コードもデバッグする場合は、Auto または Dual デバッグタイプに切り替えます。

ネイティブ デバッグは、次の要件を満たすデバイスでのみ動作します。

  • デバイスが run-as をサポートしている。

    デバイスが run-as をサポートしているかどうかを確認するには、デバイスに接続されている ADB シェルで次のコマンドを実行します。

    run-as your-package-name pwd
    

    your-package-name はアプリのパッケージ名に置き換えてください。デバイスが run-as をサポートしていれば、コマンドはエラーなしで返されます。

  • デバイスで ptrace が有効になっている。

    ptrace が有効になっているかどうかを確認するには、デバイスに接続されている ADB シェルで次のコマンドを実行します。

    sysctl kernel.yama.ptrace_scope
    

    ptrace が有効な場合、コマンドは値 0 または unknown key エラーを出力します。ptraceが有効でない場合は、0 以外の値を出力します。

Dual(C / C++ コードが含まれている場合のみ)
Java とネイティブ コードの両方のデバッグを切り替えながら行う場合にこのデバックタイプを指定します。 Java デバッガと LLDB の両方がアプリプロセス(1 つは Java デバッガ用、もう 1 つは LLDB 用)にアタッチされます。そのため、アプリの再起動やデバッグ構成の変更を必要とすることなく、Java コードとネイティブ コードの両方のブレークポイントを検査できます。

図 2 のように、[Debug] ウィンドウのタイトルの右側に、2 つのタブが表示されます。 タブが 2 つあるのは、アプリに Java コードと C++ コードの両方が含まれているためであり、1 つのタブはネイティブ コードのデバッグ用で、もう 1 つのタブ(「-java」付き)は Java コードのデバッグ用になります。

図 2. ネイティブ コードをデバッグするためのタブと Java コードをデバッグするためのタブ

注: コンパイラによって最適化されたネイティブ コードをデバッグすると、「This function was compiled with optimizations enabled. Some debugger features may not be available」という警告メッセージが表示される場合があります。-O フラグなどの最適化フラグを使用した場合、コンパイル結果のコードには、コンパイラにより実行効率化のための変更が加えられます。最適化されたコンパイル結果のコードは元のソースコードにマッピングするのが困難なため、デバッガから想定外の情報や誤った情報が返される可能性があります。 そのため、ネイティブ コードをデバッグする際は、コンパイラの最適化を無効にする必要があります。

システムログを使用する

アプリのデバッグ中は、システムログにシステム メッセージが表示されます。このメッセージには、デバイス上で実行されているアプリの情報が含まれています。システムログを使用してアプリをデバッグする場合は、アプリの開発段階で、確実にコードからログメッセージが書き込まれ、例外のスタック トレースが出力されるようにしてください。

コードを使用してログメッセージを書き込む

コードを使用してログメッセージを書き込むには、 Log クラスを使用します。ログメッセージを活用すると、アプリを操作しているときのシステム デバッグ出力を収集して、実行フローを把握できます。また、ログメッセージから、アプリ内のエラーを発見することもできます。ロギングの詳細については、ログの出力と確認をご覧ください。

アクティビティを開始する際に以前の状態情報が利用できるかどうかを判定するために、ログメッセージを追加する方法を、次のサンプルコードに示します。

Kotlin

import android.util.Log
...
private val TAG: String = MyActivity::class.java.simpleName
...
class MyActivity : Activity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        if (savedInstanceState != null) {
            Log.d(TAG, "onCreate() Restoring previous state")
            /* restore state */
        } else {
            Log.d(TAG, "onCreate() No saved state available")
            /* initialize app */
        }
    }
}

Java

import android.util.Log;
...
public class MyActivity extends Activity {
    private static final String TAG = MyActivity.class.getSimpleName();
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
       ...
       if (savedInstanceState != null) {
            Log.d(TAG, "onCreate() Restoring previous state");
            /* restore state */
        } else {
            Log.d(TAG, "onCreate() No saved state available");
            /* initialize app */
        }
    }
}

開発中に、コードを使用して例外を検出し、スタック トレースをシステムログに書き込むことができます。

Kotlin

fun someOtherMethod() {
    try {
        ...
    } catch (e : SomeException) {
        Log.d(TAG, "someOtherMethod()", e)
    }
}

Java

void someOtherMethod() {
    try {
        ...
    } catch (SomeException e) {
        Log.d(TAG, "someOtherMethod()", e);
    }
}

注: アプリを公開する準備ができたら、デバッグ ログメッセージとスタック トレース出力の呼び出しをコードから削除します。そのためには、DEBUG フラグをセットして、条件ステートメント内にデバッグ ログメッセージを配置します。

システムログを表示する

[Logcat] ウィンドウで、デバッグ メッセージや各種システム メッセージの表示やフィルタを行えます。 たとえば、ガベージ コレクションが発生したときのメッセージや、Log クラスを使用してアプリに追加したメッセージを表示できます。

Logcat を使用するには、デバッグを開始して、下部にあるツールバーで [Logcat] タブを選択します(図 3 を参照)。

図 3. [Logcat] ウィンドウとフィルタ設定

Logcat とフィルタ オプションの詳細については、Logcat を使用したログの出力と確認をご覧ください。

ブレークポイントを利用する

Android Studio は、さまざまなデバッグ アクションをトリガーするいくつかのタイプのブレークポイントをサポートしています。最も一般的なタイプは、コード内の指定行でアプリの実行を一時停止する行ブレークポイントです。実行が一時停止しているときに、変数や式を検証し、1 行ずつ実行を続けることで、ランタイム エラーの原因を特定することができます。

行ブレークポイントを追加するには:

  1. 実行を一時停止するコード行を特定し、その行の左側の余白をクリックするか、その行にキャレットを置いて Ctrl+F8(Mac では command+F8)キーを押します。
  2. アプリがすでに稼働している場合、アプリをアップデートしてブレークポイントを追加する必要はなく、[Attach debugger to Android process]()をクリックするだけで済みます。そうでない場合は、[Debug]()をクリックして、デバッグを開始します。

図 3. ブレークポイントを設定すると行の横に赤い丸が表示される

コードの実行がブレークポイントに達するとアプリは一時停止状態になります。その後、[Debugger] タブのツールを使用して、アプリの状態を確認できます。

  • 変数のオブジェクト ツリーを検査するには、[Variables] ビューで、そのツリーを展開します。[Variables] ビューが表示されていない場合は、[Restore Variables View]()をクリックします。

  • 現在の実行ポイントで式を評価するには、[Evaluate Expression]()をクリックします。

  • 次のコード行に進む(メソッドには入らない)には、[Step Over]()をクリックします。

  • メソッド呼び出しの 1 行目に進むには、[Step Into]()をクリックします。

  • 現在のメソッドを抜けて次の行に進むには、[Step Out]()をクリックします。

  • アプリの通常の実行を続けるには、[Resume Program]()をクリックします。

プロジェクトでネイティブ コードを使用している場合は、デフォルトで Auto デバッグタイプが選択され、Java デバッガと LLDB の両方が 2 つの異なるプロセスとしてアプリにアタッチされます。そのため、アプリの再起動や設定の変更を行うことなく、Java と C / C++ のブレークポイントの検査を切り替えることができます。

注: Android Studio で C / C++ コード内のブレークポイントを検出するには、Auto、Native、Dual など、LLDB をサポートするデバッグタイプを使用する必要があります。デバッグ構成を編集することにより、Android Studio で使用するデバッグタイプを変更できます。各デバッグタイプの詳細については、他のデバッグタイプを使用するのセクションをご覧ください。

Android Studio が対象デバイスにアプリをデプロイすると、デバッガ プロセスごとのタブやデバッグ セッション ビューを備えた [Debug] ウィンドウが開きます(図 4 を参照)。

図 4. LLDB を使用してネイティブ コードをデバッグする

  1. LLDB デバッガが C / C++ コード内のブレークポイントに到達すると、Android Studio によって自動的に [<モジュール名>] タブに切り替わります。[Frames] ペイン、[Variables] ペイン、[Watches] ペインも利用できます。各パネルは、Java コードをデバッグする場合と同じように機能します。LLDB セッション ビューでは [Threads] ペインは利用できませんが、[Frames] ペインのプルダウン リストを使用することで、アプリプロセスにアクセスできます。各パネルについて詳しくは、ウィンドウ フレームをデバッグする変数を検証するをご覧ください。

    注: ネイティブ コード内のブレークポイントを検査している間、アプリの Java バイトコードを実行する仮想マシンは一時停止状態になります。そのため、ネイティブ コード内のブレークポイントを検証している間は、Java デバッガを操作することや、Java デバッガ セッションから状態情報を取得することができません。

  2. Java デバッガが Java コード内のブレークポイントに到達すると、Android Studio の表示は自動的に [<モジュール名>-java] タブに切り替わります。
  3. LLDB を使用してデバッグしているときに LLDB セッション ビュー内で LLDB ターミナルを使用すると、コマンドライン オプションを LLDB に渡すことができます。アプリの毎回のデバッグで、アプリプロセスにデバッガをアタッチする直前または直後に LLDB に実行させたい特定のコマンドがある場合は、そのコマンドをデバッグ構成に追加しておくと便利です。

C / C++ コードをデバッグする際、「ウォッチポイント」と呼ばれる特別なタイプのブレークポイントを設定できます。ウォッチポイントを使用すると、アプリで特定のメモリブロックを操作したときに、アプリプロセスを一時停止させることができます。詳細については、ウォッチポイントを追加する方法についてのセクションをご覧ください。

ブレークポイントを表示、設定する

すべてのブレークポイントを表示してブレークポイント設定を指定するには、[Debug] ウィンドウの左側にある [View Breakpoints]()をクリックします。[Breakpoints] ウィンドウを表示します(図 5 を参照)。

図 5. 現在のすべてのブレークポイントをリスト表示し、各ブレークポイントの動作設定を表示する [Breakpoints] ウィンドウ

[Breakpoints] ウィンドウの左側のリストで、各ブレークポイントの有効 / 無効を切り替えることができます。ブレークポイントを無効にすると、そのブレークポイントにヒットしてもアプリは一時停止しません。リストからブレークポイントを選択すると、その設定を行えます。一度ブレークポイントを無効にしておいて、別のブレークポイントにヒットした後に最初のブレークポイントを有効化するように設定することもできます。また、ヒット後にブレークポイントを無効にするかどうかも設定できます。例外用のブレークポイントを設定するには、ブレークポイント リストで [Exception Breakpoints] を選択します。

ウィンドウ フレームをデバッグする

[Debugger] ウィンドウの [Frames] ペインでは、現在のブレークポイントにヒットした原因となったスタック フレームを検査できます。このパネルでは、スタック フレームに移動して調査でき、また Android アプリ内のスレッドリストを検査することもできます。スレッドを選択するには、スレッド セレクタ プルダウンを使用して、対象のスタック フレームを表示します。フレーム内の要素をクリックすると、エディタ内にソースが開きます。また、スレッド表示方法のカスタマイズや、スタック フレームのエクスポートも可能です。詳細については、ウィンドウ フレーム ガイドをご覧ください。

変数を検査する

[Debugger] ウィンドウの [Variables] ペインでは、アプリがブレークポイントで停止したとき、[Frames] ペインでフレームを選択して変数を検査できます。[Variables] ペインでは、静的な方法で、または選択したフレーム内で利用可能な変数を使用してその時点の式を評価できます。

[Watches] ペインも同様の機能を備えています。ただし、[Watches] ペインに追加した式は、デバッグ セッション間で保持されます。頻繁にアクセスする変数やフィールド、現在のデバッグ セッションに有用な状態情報を提供する変数やフィールドにはウォッチを設定します。[Variables] ペインや [Watches] ペインの表示については、図 6 をご覧ください。

[Watches] リストに変数や式を追加するには:

  1. デバッグを開始します。
  2. [Watches] パネルで、[Add]()をクリックします。
  3. 表示されたテキスト ボックスにウォッチの対象にする変数または式の名前を入力して、Enter キーを押します。

[Watches] リストから項目を削除するには、項目を選択して、[Remove]()をクリックします。

[Watches] リスト内の項目を選択して、[Up]()または [Down]()をクリックすると、リスト内の要素を並べ替えることができます。

図 6. [Debugger] ウィンドウの [Variables] ペインと [Watches] ペイン

ウォッチポイントを追加する

C / C++ コードをデバッグする際、「ウォッチポイント」と呼ばれる特別なタイプのブレークポイントを設定できます。ウォッチポイントを使用すると、アプリで特定のメモリブロックを操作したときに、アプリプロセスを一時停止させることができます。たとえば、あるメモリブロックに 2 つのポインタを設定し、そのメモリブロックにウォッチポイントを割り当てた場合、いずれかのポインタを使用してそのメモリブロックにアクセスすると、ウォッチポイントがトリガーされます。

Android Studio では、ランタイムに特定の変数を選択してウォッチポイントを作成できますが、LLDB でのウォッチポイントの割り当ては、変数そのものに対してではなく、その変数に割り当てられたメモリブロックに対して行われます。これは、変数を [Watches] ペインに追加することとは異なります。変数をこのペインに追加した場合は、変数の値をモニタリングすることはできますが、メモリ内の値が読み取られた場合や、変更された場合にアプリプロセスを一時停止させることはできません。

注: アプリプロセスで関数が終了し、ローカル変数に割り当てられていたメモリが解放されたら、その変数に対するウォッチポイントを再度割り当てる必要があります。

ウォッチポイントを設定するには、次の要件を満たす必要があります。

  • ターゲットの実機またはエミュレータの CPU が x86 または x86_64 であること。デバイスの CPU が ARM の場合は、メモリ内の変数のアドレス境界を、32 ビット プロセッサでは 4 バイトの倍数、64 ビット プロセッサでは 8 バイトの倍数にそろえること。ネイティブ コード内で変数をこのようにそろえるには、次のように、変数宣言で __attribute__((aligned(num_bytes))) を指定します。
    // For a 64-bit ARM processor
    int my_counter __attribute__((aligned(8)));
    
  • 割り当て済みのウォッチポイントが 3 つ以下であること。x86 または x86_64 のターゲット デバイスの場合、Android Studio がサポートするウォッチポイントの数は最大で 4 つです。他のデバイスの場合は、サポートされるウォッチポイントの数がそれよりも少ない可能性があります。

注: 32 ビット ARM ABI を使用してアプリをデバッグする場合、ウォッチポイントを追加したり、コード内の変数にカーソルを合わせて値を調べたりとすると、クラッシュすることがあります。回避策として、64 ビット ARM、x86、または x86_64 のバイナリを使用してデバッグしてください。この問題は、今後の Android Studio リリースで修正される予定です。

上記の要件を満たしている場合は、次の手順でウォッチポイントを追加できます。

  1. ブレークポイントでアプリが一時停止しているときに、LLDB セッション ビューの [Variables] ペインに移動します。
  2. トラッキングするメモリブロックを占有している変数を右クリックして、[Add Watchpoint] を選択します。ウォッチポイントを設定するためのダイアログが表示されます(図 7 を参照)。

    図 7. メモリの変数にウォッチポイントを追加する

  3. 以下のオプションを使用して、ウォッチポイントを設定します。
    • Enabled: しばらくこのウォッチポイントを無視するように Android Studio に指示する場合は、このオプションのチェックボックスをオフにします。ウォッチポイントは引き続き Android Studio 内に保存されるため、それ以降もそのデバッグ セッションで使用できます。
    • Suspend: デフォルトでは、ウォッチポイントに割り当てられたメモリブロックがアクセスされると、アプリプロセスは一時停止します。 この処理を変える場合は、このオプションのチェックボックスをオフにします。オフにすると、追加オプションが表示され、システムがウォッチポイントを処理する際の動作をカスタマイズできるようになります。追加オプションには、[Log message to console] と [Remove [the watchpoint] when hit] があります。
    • Access Type: 変数に割り当てられたメモリブロックに対してアプリから [Read] または [Write] を試行したときに、ウォッチポイントをトリガーするかどうかを選択します。読み取りと書き込みのいずれでもウォッチポイントをトリガーするには、[Any] を選択します。
  4. [Done] をクリックします。

すべてのウォッチポイントを表示し、ウォッチポイント設定を指定するには、[Debug] ウィンドウの左側にある [View Breakpoints]()をクリックします。[Breakpoints] ダイアログを表示します(図 8 を参照)。

図 8. 現在のすべてのウォッチポイントをリスト表示し、各ウォッチポイントの動作設定を表示する [Breakpoints] ダイアログ

ウォッチポイントを追加した後、[Debug] ウィンドウの左側にある [Resume Program]()をクリックすると、アプリプロセスを再開できます。デフォルトでは、ウォッチポイントを設定したメモリブロックに対してアプリからアクセスしようとすると、アプリプロセスが一時停止状態になり、アプリで最後に実行されたコード行の横にウォッチポイント アイコン が表示されます(図 9 を参照)。

図 9. ウォッチポイントがトリガーされる直前にアプリで実行されたコード行が表示される

リソース値の表示と表示形式の変更

デバッグモードでは、Java コード内の変数について、リソース値の表示と別の表示形式の選択を行うことができます。[Variables] タブを表示してフレームを選択し、次の手順を行います。

  1. [Variables] リストで、リソース行の任意の場所を右クリックして、プルダウン リストを表示します。
  2. プルダウン リストから [View as] を選択して、使用する形式を選択します。

    使用できる形式は、選択したリソースのデータタイプによって異なります。 以下のようなオプションが 1 つまたは複数表示されます。

    • Class: クラスの定義を表示します。
    • toString: 文字列形式を表示します。
    • Object: オブジェクト(クラスのインスタンス)の定義を表示します。
    • Array: 配列形式で表示します。
    • Timestamp: yyyy-mm-dd hh:mm:ss 形式で日時を表示します。
    • Auto: データタイプに基づいて Android Studio が最適な形式を選択します。
    • Binary: 0 と 1 を使用して 2 進値を表示します。
    • MeasureSpec: 親から、選択された子に渡された値です (MeasureSpec. を参照)。
    • Hex: 16 進値として表示します。
    • Primitive: プリミティブ型を使用して数値として表示します。
    • Integer: Integer 型の数値を表示します。

カスタム形式(データタイプ レンダラ)を作成するには:

  1. リソース値を右クリックします。
  2. [View as] を選択します。
  3. [Create] を選択します。[Java Type Renderers] ダイアログが表示されます。
  4. Java Type Renderers の手順に沿って設定します。