调试 SDV

本指南简要介绍了用于调试在 SDV 平台上运行的服务和应用的基本工具和技术。

连接到设备

用于连接到设备并与之交互的主要工具是 Android 调试桥 (adb)。验证 adb 是否位于系统的路径中。

使用网络连接

如果设备位于同一网络中,并且您知道其 IP 地址,则可以通过以太网进行连接。我们的系统仅使用网络连接来运行 adb:

# Connect to the device using its IP address and default port
adb connect <device_ip_address>:5555

连接到多台设备

如需从单个工作站管理多台设备,您可以通过不同的 IP 地址连接到这些设备。如果您在单个主机上运行多个虚拟机,则需要为每个设备分配不同的端口。这需要将每个 SDV 设备上的 adb 守护程序配置为监听唯一端口,例如,第一个设备监听 5555,第二个设备监听 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 等标准命令行工具实时查看这些文件。

与 shell 和文件系统交互

获取 shell 访问权限,以便直接在设备上运行命令、检查进程状态和浏览文件系统:

# 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 附加调试程序,请参阅调试和测试以及调试平台代码):

  1. 使用 root 权限重启 adb(端口转发需要):

    adb root
    
  2. 如果二进制文件具有调试符号,请从 out/target/product/[SDV_FLAVOR]/symbols/[PARTITION]/bin/[EXECUTABLE] 推送未剥离的版本。例如,如需从 system_ext 和 sdv_core_cf 上传 rpcagent,请运行以下命令:

    adb push out/target/product/sdv_core_cf/symbols/system_ext/bin/rpcagent /data/local/tmp
    
  3. 使用 lldbclient.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 文件,然后使用符号感知工具(例如 lldb 或专用脚本)通过未剥离的二进制文件版本对其进行分析。

分析性能

SDV 支持多种性能测量工具。

检查 CPU 和内存用量

  • top:提供按 CPU 使用率排序的正在运行进程的实时视图。

    adb shell top -m 10  # Show top 10 processes
    
  • procrank:提供特定进程或整个系统的内存用量的详细细分。

    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 可让您记录系统事件、应用级跟踪点和性能计数器,并在时间轴上直观呈现。

关键步骤:

  1. 在 C++ 或 Rust 代码中添加跟踪点:
    • C++:将 Perfetto SDK 与 TRACE_EVENT 宏搭配使用。
    • Rust:使用 tracing crate,它会发出与 Perfetto 兼容的 ATrace 事件。
  2. 创建一个 textproto 配置文件,以指定数据源(例如 ftrace、track_event)、类别和标记。
  3. 将 record_android_trace 脚本 (external/perfetto/tools/record_android_trace) 与配置文件搭配使用,以从设备中捕获跟踪记录。
  4. 在 Perfetto Web 界面中打开生成的跟踪文件,以分析系统行为、识别瓶颈并了解服务交互。

如需详细了解插桩、配置和收集,请参阅使用跟踪功能深入了解系统性能。

使用 Simpleperf 进行性能分析

Simpleperf 是一款功能多样的命令行工具,用于在 Android 上进行性能分析,类似于 Linux perf。

常见使用情形:

  • 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 工具。这会生成正确的 .te 政策规则,以添加到设备的 SELinux 配置中。