SDV 디버그

이 가이드에서는 SDV 플랫폼에서 실행되는 서비스 및 애플리케이션을 디버깅하는 데 필요한 기본 도구와 기법을 간략하게 설명합니다.

기기에 연결

기기에 연결하고 기기와 상호작용하는 기본 도구는 Android 디버그 브리지 (adb) 입니다. adb가 시스템 경로에 있는지 확인합니다.

네트워크를 사용하여 연결

기기가 동일한 네트워크에 있고 IP 주소를 알고 있는 경우 이더넷으로 연결할 수 있습니다. Google 시스템은 adb에 네트워크 연결만 사용합니다.

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

여러 기기에 연결

단일 워크스테이션에서 여러 기기를 관리하려면 서로 다른 IP 주소를 통해 기기에 연결하면 됩니다. 단일 호스트에서 여러 VM을 실행하는 경우 각 기기에 서로 다른 포트를 할당해야 합니다. 이렇게 하려면 각 SDV 기기에서 고유한 포트(예: 첫 번째 기기의 경우 5555, 두 번째 기기의 경우 5556)에서 수신 대기하도록 adb 데몬을 구성해야 합니다. 호스트가 이러한 포트를 서로 다른 게스트로 전달하도록 구성할 수도 있습니다.

# 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 명령어를 실행할 때 전체 주소 (ip:port)와 함께 -s 플래그를 사용하여 특정 기기를 타겟팅할 수 있습니다.

# 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 pushadb 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 스튜디오의 기본 디버거이며 최신 C++ 및 Rust 개발에 자주 사용됩니다.

다음 설정 단계를 따르세요.

  1. 루트 권한 (전달에 필요)을 허용하도록 adb를 다시 시작합니다. 이를 사용하여 포트 전달을 설정합니다. 호스트에서 다음을 실행합니다.

    adb root
    
  2. 바이너리에 디버깅 기호가 있는 경우 스트립되지 않은 버전을 푸시합니다. 스트립되지 않은 버전은 out/target/product/[SDV_FLAVOR]/symbols/[PARTITION]/bin/[EXECUTABLE]에서 찾을 수 있습니다. 예를 들어 system_extsdv_core_cf에서 rpcagent를 업로드하려면 다음을 실행합니다.

    adb push out/target/product/sdv_core_cf/symbols/system_ext/bin/rpcagent /data/local/tmp
    

    이제 스트립되지 않은 버전이 /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를 실행합니다. lldb에 연결하려면 IDE 문서를 참고하세요.

크래시 덤프 (tombstone) 분석

서비스가 비정상 종료되면 /data/tombstones/tombstone 파일이 생성됩니다. 파일에는 스택 트레이스, 메모리 맵, 기타 중요한 정보가 포함됩니다.

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++: TRACE_EVENT 매크로와 함께 Perfetto SDK를 사용합니다.
    • Rust: Perfetto와 호환되는 ATrace 이벤트를 내보내는 tracing crate를 사용합니다.
  2. 데이터 소스 (예: ftrace, track_event), 카테고리, 태그를 지정하는 textproto 구성 파일을 만듭니다.
  3. 구성 파일과 함께 record_android_trace 스크립트 (external/perfetto/tools/record_android_trace)를 사용하여 기기에서 트레이스를 캡처합니다.
  4. Perfetto 웹 UI에서 생성된 추적 파일을 열어 시스템 동작을 분석하고, 병목 현상을 식별하고, 서비스 상호작용을 파악합니다.

계측, 구성, 수집에 관한 자세한 안내는 추적을 사용하여 시스템 성능에 관한 통계 얻기를 참고하세요.

프로파일링에 Simpleperf 사용

Simpleperf는 Linux perf와 유사한 Android의 성능 프로파일링을 위한 다목적 명령줄 도구입니다.

일반적인 사용 사례:

  • CPU 프로파일링: CPU 시간을 가장 많이 소비하는 함수를 식별합니다.
  • Off-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 거부

증상: 서비스가 시작되지 않거나, 파일에 액세스하지 못하거나, 기능을 사용하지 못하고 avc: denied 메시지가 dmesg 또는 logcat에 표시됩니다.

[ 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
cvd create --guest_enforce_security=false

수정: 거부 메시지의 Android 소스 트리의 audit2allow 도구입니다. 이렇게 하면 기기의 SELinux 구성에 추가할 올바른 .te 정책 규칙이 생성됩니다.