このガイドでは、SDV プラットフォームで実行されるサービスとアプリケーションをデバッグするための重要なツールと手法の概要について説明します。
デバイスに接続する
デバイスに接続して操作するための主なツールは、Android Debug Bridge(adb)です。adb がシステムのパスにあることを確認します。
ネットワークを使用して接続する
デバイスが同じネットワーク上にあり、その IP アドレスがわかっている場合は、イーサネットで接続できます。システムは adb にネットワーク接続のみを使用します。
# Connect to the device using its IP address and default port
adb connect <device_ip_address>:5555
複数のデバイスに接続する
1 台のワークステーションから複数のデバイスを管理するには、異なる IP アドレスを介してデバイスに接続します。1 つのホストで複数の VM を実行する場合は、デバイスごとに異なるポートを割り当てる必要があります。これには、各 SDV デバイスの adb デーモンを、一意のポート(最初のデバイスは 5555、2 番目のデバイスは 5556 など)でリッスンするように構成する必要があります。また、これらのポートを異なるゲストに転送するようにホストを構成することもできます。
# Connect to the first device
adb connect <device_1_ip_address>:5555
# Connect to a second device
adb connect <device_2_ip_address>:5555
# Connect to a second VM on first device on different port
adb connect <device_1_ip_address>:5556
# List all connected devices to verify
adb devices
後続の adb コマンドを実行するときに、-s フラグと完全なアドレス(ip:port)を使用して、特定のデバイスをターゲットに設定できます。
# Run a shell command on the second VM on first device in the above example
adb -s <device_1_ip_address>:5556 shell
ログを表示
サービスが失敗したり、予期しない動作をしたりした場合は、まずログを確認します。
logcat(Android ログ)を使用する
logcat には、システム サービス、エージェント、サービス バンドルのログが表示されます。
# View all logs in real-time
adb logcat
# Filter logs by a specific tag (e.g., the name of your service)
adb logcat -s MyServiceTag
# Filter logs by priority (V: Verbose, D: Debug, I: Info, W: Warn, E: Error, F: Fatal)
# This shows only Error and Fatal messages for a specific tag
adb logcat MyServiceTag:E *:S
# Clear old logs before viewing new ones
adb logcat -c && adb logcat
# Show all logs and return
adb logcat -d
# Color logs by level
adb logcat -v color
# Show timestamps as time since boot
adb logcat -v monotonic
dmesg(カーネルログ)を使用する
dmesg は、Linux カーネルのログを表示します。これは、次のデバッグに不可欠です。
- ハードウェアとドライバの問題
- カーネル パニック
- SELinux 拒否(
avc: denied)- logcat にも表示されます。
# View all kernel messages
adb shell dmesg
# Follow kernel messages in real-time
adb shell dmesg -w
Cuttlefish のログにアクセスする
Cuttlefish 仮想デバイスで実行する場合は、ホストマシンのファイル システムからログファイルに直接アクセスできます。これは、adb が使用できない場合に特に便利です。Cuttlefish を起動すると、すべてのデバッグパスが出力されます。また、実行中のすべてのインスタンスについて、cvd fleet を使用してデバッグパスを検索することもできます。
- Logcat(Android ログ):
cuttlefish/instances/cvd-1/logs/logcat - カーネルログ:
cuttlefish/instances/cvd-1/logs/kernel.log - Cuttlefish ランチャーのログ:
cuttlefish/instances/cvd-1/logs/launcher.log(Cuttlefish 環境自体のデバッグに便利)
cat、less、tail -f などの標準のコマンドライン ツールを使用して、これらのファイルをリアルタイムで表示できます。
シェルとファイル システムを操作する
シェルアクセスを取得して、デバイス上で直接コマンドを実行し、プロセス ステータスを確認して、ファイル システムを操作します。
# Open an interactive shell on the device
adb shell
# From within the shell, you can check running processes
ps -A
# Or check the status of a specific service managed by init
getprop init.svc.<service_name>
ファイル システム オペレーションを実行する
adb push と adb pull を使用して、ホストマシンとデバイス間でファイルを移動します。これを使用して、テスト スクリプトのデプロイ、構成の更新、クラッシュ ダンプの取得を行います。
# Push a file from your computer to the device
adb push my_local_file.txt /data/local/tmp/
# Pull a file from the device to your computer
adb pull /data/tombstones/tombstone_00 .
アプリケーションをデバッグする(C++/Rust)
アプリケーションは、オンラインでもオフラインでもデバッグできます。
lldb を使用してライブデバッグを行う
lldb を使用してサービスをリアルタイムでデバッグする手順は次のとおりです(Android Studio for Platform からデバッガをアタッチするには、デバッグとテストとプラットフォーム コードのデバッグをご覧ください)。
root 権限で
adbを再起動します(ポート転送に必要)。adb rootバイナリにデバッグ シンボルがある場合は、
out/target/product/[SDV_FLAVOR]/symbols/[PARTITION]/bin/[EXECUTABLE]からストリップされていないバージョンを push します。たとえば、system_extとsdv_core_cfからrpcagentをアップロードするには、次のコマンドを実行します。adb push out/target/product/sdv_core_cf/symbols/system_ext/bin/rpcagent /data/local/tmplldbclient.py簡易スクリプトを使用して LLDB クライアントに接続します。# Run and connect a binary on device, run on host: lldbclient.py -r /data/local/tmp/rpcagent # Connect to an existing process with PID 2759 lldbclient.py -p 2759このスクリプトは
lldbにリモートで接続します。使用可能なすべてのフラグを確認するには、lldbclient.py --helpを実行します。
クラッシュ ダンプ(tombstone)を分析する
サービスがクラッシュすると、/data/tombstones/ にトゥームストーン ファイルが生成されます。このファイルには、スタック トレース、メモリマップ、その他の重要な情報が含まれています。
tombstone ファイルを pull し、シンボル対応ツール(lldb や専用スクリプトなど)を使用して、ストリップされていないバージョンのバイナリで分析します。
パフォーマンスを分析
SDV は、パフォーマンス測定用の複数のツールをサポートしています。
CPU とメモリの使用状況を確認する
top: 実行中のプロセスを CPU 使用率順に並べ替えてリアルタイムで表示します。adb shell top -m 10 # Show top 10 processesprocrank: 特定のプロセスまたはシステム全体のメモリ使用量の詳細な内訳を提供します。adb shell procrank
サービスの状態に dumpsys を使用する
dumpsys は、Android システム サービスの内部状態をクエリするための強力なツールです。
# List all available services
adb shell dumpsys -l
# Dump the state of a specific service or agent
adb shell dumpsys <service_name>
パフォーマンス分析に torq を使用する
torq は、Android でのプロファイリングとトレースのタスクを簡素化するコマンドライン ツールです。これにより、システム パフォーマンス分析中に Simpleperf、Perfetto、その他の一般的なタスクを実行できます。
トレースに Perfetto を使用する
Perfetto は、Android でシステム全体のトレースを行うための標準ツールです。Perfetto を使用すると、システム イベント、アプリレベルのトレース ポイント、パフォーマンス カウンタを記録し、タイムラインに可視化できます。
主な手順:
- C++ または Rust コードにトレースポイントを追加します。
- C++:
TRACE_EVENTマクロで Perfetto SDK を使用します。 - Rust:
tracingクレートを使用します。これは、Perfetto と互換性のある ATrace イベントを出力します。
- C++:
- textproto 構成ファイルを作成して、データソース(
ftrace、track_eventなど)、カテゴリ、タグを指定します。 - 構成ファイルで
record_android_traceスクリプト(external/perfetto/tools/record_android_trace)を使用して、デバイスからトレースをキャプチャします。 - 生成されたトレース ファイルを Perfetto ウェブ UI で開き、システムの動作を分析し、ボトルネックを特定して、サービスの相互作用を把握します。
計測、構成、収集の詳細な手順については、トレースを使用してシステム パフォーマンスに関する分析情報を取得するをご覧ください。
プロファイリングに Simpleperf を使用する
Simpleperf は、Linux perf と同様に、Android でのパフォーマンス プロファイリングに使用できる多用途のコマンドライン ツールです。
一般的なユースケース:
- CPU プロファイリング: CPU 時間を最も多く消費している関数を特定します。
- CPU 以外の分析: スレッドがスリープ状態またはブロックされている理由を分析します。
- ハードウェア カウンタ: ハードウェア パフォーマンス カウンタにアクセスします。
コマンドの例:
# Go to simpleperf scripts
cd system/extras/simpleperf/scripts
# Profile system for 20 seconds and record call graph
./app_profiler.py --system_wide -r "--call-graph fp --duration 20"
# Record a profile for a specific process (PID 1)
./app_profiler.py --pid 1 -r "--call-graph fp --duration 5"
# Pull the profile data
adb pull /data/local/tmp/perf.data .
# Generate a report with symbol resolution
./report_html.py --add_source_code --source_dirs $ANDROID_BUILD_TOP --add_disassembly -o report.html
Simpleperf には、他にも多くのイベントとオプションが用意されています。包括的なドキュメントについては、Simpleperf ガイドをご覧ください。
SELinux 拒否
症状: サービスが起動しない、ファイルにアクセスできない、機能を使用できない、dmesg または logcat に avc: denied メッセージが表示される。
[ 123.456] avc: denied { read } for pid=789 comm="my_service" name="some_file" dev="sda1" ino=123 scontext=u:r:my_service_t:s0 tcontext=u:object_r:some_file_t:s0 tclass=file permissive=0
クイック デバッグ(開発のみ)
SELinux の適用を一時的に無効にして、問題が解決するかどうかを確認できます。これにより、問題の原因が SELinux ポリシールールの欠落であることが確認されます。
# Disabling SELinux requires root permission
adb root
# Set SELinux to permissive mode
adb shell setenforce 0
# Check the current mode (should return "Permissive")
adb shell getenforce
修正: 拒否メッセージの Android ソースツリーの audit2allow ツール。これにより、デバイスの SELinux 構成に追加する正しい .te ポリシールールが生成されます。