Debugowanie SDV

Ten przewodnik zawiera omówienie podstawowych narzędzi i technik debugowania usług i aplikacji działających na platformie SDV.

Połącz z urządzeniem

Podstawowym narzędziem do łączenia się z urządzeniem i interakcji z nim jest Android Debug Bridge (adb). Sprawdź, czy adb znajduje się w ścieżce systemowej.

Łączenie się z siecią

Jeśli urządzenie jest w tej samej sieci i znasz jego adres IP, możesz połączyć się przez Ethernet. Nasz system używa wyłącznie połączeń sieciowych do adb:

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

Łączenie z wieloma urządzeniami

Aby zarządzać wieloma urządzeniami z jednej stacji roboczej, możesz połączyć się z nimi za pomocą różnych adresów IP. Jeśli na jednym hoście uruchamiasz kilka maszyn wirtualnych, musisz przypisać do każdego urządzenia inne porty. Wymaga to skonfigurowania demona adb na każdym urządzeniu SDV, aby nasłuchiwał na unikalnym porcie, na przykład 5555 w przypadku pierwszego urządzenia i 5556 w przypadku drugiego. Możesz też skonfigurować hosta tak, aby przekierowywał te porty do różnych gości:

# 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

Podczas uruchamiania kolejnych poleceń adb możesz kierować je na konkretne urządzenie, używając flagi -s z pełnym adresem (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

Wyświetl logi

Jeśli usługa nie działa lub zachowuje się nieoczekiwanie, najpierw sprawdź logi.

Korzystanie z logcat (logi Androida)

logcat wyświetla logi z usług systemowych, agentów i pakietów usług:

# 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

Używanie dmesg (dzienników jądra)

dmesg wyświetla logi z jądra systemu Linux. Jest to kluczowe w przypadku debugowania:

  • Problemy ze sprzętem i sterownikami
  • Błędy kernel panic
  • Odmowy SELinux (avc: denied) – wyświetlane też w logcat
# View all kernel messages
adb shell dmesg

# Follow kernel messages in real-time
adb shell dmesg -w

Uzyskiwanie dostępu do logów w Cuttlefish

Gdy uruchamiasz aplikację na urządzeniu wirtualnym Cuttlefish, możesz uzyskać bezpośredni dostęp do plików dziennika z systemu plików maszyny hosta. Jest to szczególnie przydatne, gdy usługa adb jest niedostępna. Po uruchomieniu Cuttlefish wyświetla wszystkie ścieżki debugowania. Możesz je też sprawdzić za pomocą polecenia cvd fleet we wszystkich uruchomionych instancjach.

  • Logcat (logi Androida): cuttlefish/instances/cvd-1/logs/logcat
  • Dzienniki jądra: cuttlefish/instances/cvd-1/logs/kernel.log
  • Dzienniki programu uruchamiającego Cuttlefish: cuttlefish/instances/cvd-1/logs/launcher.log (przydatne do debugowania samego środowiska Cuttlefish)

Aby wyświetlać te pliki w czasie rzeczywistym, możesz użyć standardowych narzędzi wiersza poleceń, takich jak cat, less lub tail -f.

Interakcja z powłoką i systemem plików

Uzyskaj dostęp do powłoki, aby uruchamiać polecenia bezpośrednio na urządzeniu, sprawdzać stan procesu i poruszać się po systemie plików:

# 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>

Wykonywanie operacji na systemie plików

Użyj poleceń adb push i adb pull, aby przenosić pliki między komputerem hosta a urządzeniem. Użyj tego, aby wdrożyć skrypty testowe, zaktualizować konfigurację lub pobrać zrzuty awaryjne:

# 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 .

Debugowanie aplikacji (C++/Rust)

Aplikacje możesz debugować online lub offline.

Używanie lldb do debugowania na żywo

Aby debugować usługę w czasie rzeczywistym za pomocą lldb, wykonaj te czynności (aby dołączyć debuger z Android Studio for Platform, zapoznaj się z artykułami Debugowanie i testowanie oraz Debugowanie kodu platformy):

  1. Uruchom ponownie adb z uprawnieniami roota (wymaganymi do przekierowania portów):

    adb root
    
  2. Jeśli plik binarny zawiera symbole debugowania, prześlij nieoczyszczoną wersję z out/target/product/[SDV_FLAVOR]/symbols/[PARTITION]/bin/[EXECUTABLE]. Aby na przykład przesłać plik rpcagent z system_ext i sdv_core_cf, uruchom:

    adb push out/target/product/sdv_core_cf/symbols/system_ext/bin/rpcagent /data/local/tmp
    
  3. Połącz się z klientem LLDB za pomocą skryptu lldbclient.py:

    # 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
    

    Ten skrypt łączy się zdalnie z lldb. Aby zobaczyć wszystkie dostępne flagi, uruchom polecenie lldbclient.py --help.

Analizowanie zrzutów awaryjnych (nagrobków)

Gdy usługa ulegnie awarii, w /data/tombstones/ zostanie wygenerowany plik tombstone. Plik zawiera zrzut stosu, mapę pamięci i inne ważne informacje.

Pobierz plik tombstone, a następnie użyj narzędzia rozpoznającego symbole (takiego jak lldb lub specjalny skrypt), aby przeanalizować go za pomocą nieoczyszczonej wersji pliku binarnego.

Przeanalizuj wydajność

SDV obsługuje wiele narzędzi do pomiaru wydajności.

Sprawdzanie wykorzystania procesora i pamięci

  • top: wyświetla w czasie rzeczywistym listę uruchomionych procesów posortowanych według wykorzystania procesora.

    adb shell top -m 10  # Show top 10 processes
    
  • procrank: zawiera szczegółowe zestawienie wykorzystania pamięci przez konkretny proces lub cały system.

    adb shell procrank
    

Używanie dumpsys do sprawdzania stanu usługi

dumpsys to zaawansowane narzędzie do wysyłania zapytań o stan wewnętrzny dowolnej usługi systemowej Androida.

# List all available services
adb shell dumpsys -l

# Dump the state of a specific service or agent
adb shell dumpsys <service_name>

Używanie torq do analizy wydajności

torq to narzędzie wiersza poleceń, które upraszcza zadania profilowania i śledzenia na Androidzie. Umożliwia uruchamianie Simpleperf, Perfetto i innych typowych zadań podczas analizy wydajności systemu.

Używanie Perfetto do śledzenia

Perfetto to standardowe narzędzie do śledzenia całego systemu na Androidzie. Perfetto umożliwia rejestrowanie zdarzeń systemowych, punktów śledzenia na poziomie aplikacji i liczników wydajności oraz wizualizowanie ich na osi czasu.

Najważniejsze kroki:

  1. Dodaj punkty śledzenia w kodzie C++ lub Rust:
    • C++: użyj pakietu Perfetto SDK z makrami TRACE_EVENT.
    • Rust: użyj crate tracing, który emituje zdarzenia ATrace zgodne z Perfetto.
  2. Utwórz plik konfiguracji textproto, aby określić źródła danych (np. ftrace, track_event), kategorie i tagi.
  3. Użyj skryptu record_android_trace (external/perfetto/tools/record_android_trace) z plikiem konfiguracji, aby przechwycić ślad z urządzenia.
  4. Otwórz wygenerowany plik logu czasu w interfejsie internetowym Perfetto, aby przeanalizować zachowanie systemu, zidentyfikować wąskie gardła i zrozumieć interakcje między usługami.

Szczegółowe instrukcje dotyczące instrumentacji, konfiguracji i zbierania danych znajdziesz w artykule Używanie logów czasu do uzyskiwania statystyk dotyczących wydajności systemu.

Używanie Simpleperf do profilowania

Simpleperf to wszechstronne narzędzie wiersza poleceń do profilowania wydajności na Androidzie, podobne do narzędzia perf w systemie Linux.

Częste przypadki użycia:

  • Profilowanie procesora: identyfikowanie funkcji, które zużywają najwięcej czasu pracy procesora.
  • Analiza poza procesorem: analiza przyczyn uśpienia lub zablokowania wątków.
  • Liczniki sprzętowe: dostęp do liczników wydajności sprzętu.

Przykładowe polecenia:

# 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 oferuje znacznie więcej zdarzeń i opcji. Szczegółowe informacje znajdziesz w przewodniku po Simpleperf.

Odmowy SELinux

Objawy: usługa nie uruchamia się, nie może uzyskać dostępu do pliku lub nie może użyć funkcji, a w dmesg lub logcat pojawia się komunikat 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

Szybkie debugowanie (tylko na potrzeby programowania)

Możesz tymczasowo wyłączyć egzekwowanie zasad SELinux, aby sprawdzić, czy problem został rozwiązany. Potwierdza to, że problem jest spowodowany brakiem reguły zasady 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

Rozwiązanie: użyj narzędzia audit2allow z drzewa źródłowego Androida, aby przeanalizować komunikat o odmowie. Spowoduje to wygenerowanie prawidłowej reguły zasad .te, którą należy dodać do konfiguracji SELinux urządzenia.