Debugowanie SDV

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

Łączenie się 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ę przez sieć

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 się z kilkoma urządzeniami

Aby zarządzać kilkoma 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, np. 5555 na pierwszym urządzeniu i 5556 na drugim. Możesz też skonfigurować hosta tak, aby przekazywał 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

Gdy uruchamiasz kolejne polecenia 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świetlanie logów

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

Używanie 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 (logi jądra)

dmesg wyświetla logi z jądra systemu Linux. Jest to niezbędne do debugowania tych elementów:

  • Problemy ze sprzętem i sterownikami
  • Błędy jądra
  • 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

Dostęp do logów w Cuttlefish

Gdy uruchamiasz urządzenie wirtualne Cuttlefish, możesz bezpośrednio uzyskiwać dostęp do plików dziennika z systemu plików maszyny hosta. Jest to szczególnie przydatne, jeśli adb jest niedostępny. Gdy uruchamiasz Cuttlefish, wyświetla on wszystkie ścieżki debugowania. Możesz je też sprawdzić za pomocą polecenia cvd fleet w przypadku wszystkich uruchomionych instancji.

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

Do wyświetlania tych plików w czasie rzeczywistym możesz używać standardowych narzędzi wiersza poleceń, takich jak cat, less czy 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 maszyną hosta a urządzeniem. Użyj tej opcji, aby wdrożyć skrypty testowe, zaktualizować konfigurację lub pobrać zrzuty awarii:

# 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

lldb to domyślny debugger w Android Studio, który jest często preferowany w przypadku nowoczesnego programowania w C++ i Rust.

Wykonaj te czynności konfiguracyjne:

  1. Uruchom ponownie adb, aby zezwolić na uprawnienia roota (wymagane do przekazywania). Użyj tej opcji, aby skonfigurować przekierowanie portów. Na hoście uruchom:

    adb root
    
  2. Jeśli plik binarny ma symbole debugowania, prześlij wersję bez usuwania. Wersję bez usuwania znajdziesz w out/target/product/[SDV_FLAVOR]/symbols/[PARTITION]/bin/[EXECUTABLE]. Aby na przykład przesłać 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
    

    Teraz wersja bez usuwania znajduje się w /data/local/tmp.

  3. Połącz się z klientem LLDB za pomocą skryptu pomocniczego 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 lldb zdalnie. Aby wyświetlić wszystkie dostępne flagi, uruchom lldbclient.py. Aby połączyć go z lldb, zapoznaj się z dokumentacją IDE.

Analizowanie zrzutów awarii (tombstones)

Gdy usługa ulegnie awarii, w katalogu /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 obsługującego symbole (np. lldb lub specjalnego skryptu), aby przeanalizować go za pomocą wersji binarnej bez usuwania.

Analizowanie wydajności

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

Sprawdzanie wykorzystania procesora i pamięci

  • top: wyświetla w czasie rzeczywistym uruchomione procesy posortowane według wykorzystania procesora.

    adb shell top -m 10  # Show top 10 processes
    
  • procrank: zawiera szczegółowe informacje o wykorzystaniu 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 w 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 w całym systemie Android. 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 pakietu tracing, który emituje zdarzenia ATrace zgodne z Perfetto.
  2. Utwórz plik konfiguracyjny 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 konfiguracyjnym , aby przechwycić ślad z urządzenia.
  4. Otwórz wygenerowany plik śledzenia w interfejsie Perfetto Web, 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 śledzenia do uzyskiwania informacji o wydajności systemu.

Używanie Simpleperf do profilowania

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

Typowe przypadki użycia:

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

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 wiele innych zdarzeń i opcji. Szczegółową dokumentację znajdziesz w przewodniku Simpleperf.

Odmowy SELinux

Objaw: usługa nie uruchamia się, nie może uzyskać dostępu do pliku ani użyć funkcji, a w dmesg lub logcat widzisz 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 SELinux, aby sprawdzić, czy problem został rozwiązany. Potwierdza to, że problem jest spowodowany brakiem reguły zasad 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 w komunikacie o odmowie. Wygeneruje to prawidłową regułę zasad .te, którą należy dodać do konfiguracji SELinux urządzenia.