ProfilingManager obsługuje przechwytywanie profili na podstawie wyzwalaczy systemowych. System zarządza procesem nagrywania i przekazuje wynikowy profil do Twojej aplikacji.
Aktywatory są powiązane ze zdarzeniami o kluczowym znaczeniu dla wydajności. Profile rejestrowane przez system zawierają szczegółowe informacje do debugowania dotyczące kluczowych ścieżek użytkowników powiązanych z tymi wyzwalaczami.
Przechwytywanie danych historycznych
Wiele wyzwalaczy wymaga analizy danych historycznych prowadzących do zdarzenia. Sygnał jest często konsekwencją problemu, a nie jego główną przyczyną. Jeśli rozpoczniesz profilowanie dopiero po wystąpieniu reguły, główna przyczyna może już być niedostępna.
Na przykład długo trwająca operacja w wątku interfejsu powoduje błąd Aplikacja nie odpowiada (ANR). Zanim system wykryje błąd ANR i powiadomi o nim aplikację, operacja może się już zakończyć. Rozpoczęcie profilowania w tym momencie nie uwzględnia rzeczywistego blokowania.
Dokładne przewidywanie, kiedy wystąpią niektóre czynniki uruchamiające, jest niemożliwe, co uniemożliwia ręczne uruchomienie profilu z wyprzedzeniem.
Dlaczego warto korzystać z rejestrowania opartego na wyzwalaczach?
Głównym powodem używania wyzwalaczy profilowania jest rejestrowanie danych dotyczących nieprzewidywalnych zdarzeń, w przypadku których aplikacja nie może rozpocząć nagrywania ręcznie przed ich wystąpieniem. Aktywatory profilowania mogą służyć do:
- Debugowanie problemów z wydajnością: diagnozowanie błędów ANR, wycieków pamięci i innych problemów ze stabilnością.
- Optymalizuj główne ścieżki użytkownika: analizuj i ulepszaj ścieżki, np. uruchamianie aplikacji.
- Poznawanie zachowań użytkowników: uzyskuj statystyki dotyczące zdarzeń, np. zamykania aplikacji przez użytkowników.
Konfigurowanie aktywatora
Poniższy kod pokazuje, jak zarejestrować wywołanie TRIGGER_TYPE_APP_FULLY_DRAWN i zastosować do niego ograniczenie liczby wywołań.
Kotlin
fun recordWithTrigger() { val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java) val triggers = ArrayList<ProfilingTrigger>() val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN) .setRateLimitingPeriodHours(1) triggers.add(triggerBuilder.build()) val mainExecutor: Executor = Executors.newSingleThreadExecutor() val resultCallback = Consumer<ProfilingResult> { profilingResult -> if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.resultFilePath ) setupProfileUploadWorker(profilingResult.resultFilePath) } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage ) } } profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback) profilingManager.addProfilingTriggers(triggers)
Java
public void recordWithTrigger() { ProfilingManager profilingManager = getApplicationContext().getSystemService( ProfilingManager.class); List<ProfilingTrigger> triggers = new ArrayList<>(); ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN); triggerBuilder.setRateLimitingPeriodHours(1); triggers.add(triggerBuilder.build()); Executor mainExecutor = Executors.newSingleThreadExecutor(); Consumer<ProfilingResult> resultCallback = new Consumer<ProfilingResult>() { @Override public void accept(ProfilingResult profilingResult) { if (profilingResult.getErrorCode() == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.getResultFilePath()); setupProfileUploadWorker(profilingResult.getResultFilePath()); } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.getErrorCode() + " errormsg=" + profilingResult.getErrorMessage()); } } }; profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback); profilingManager.addProfilingTriggers(triggers);
Kod wykonuje te czynności:
- Get the manager (Pobierz menedżera): pobiera usługę
ProfilingManager. - Zdefiniuj aktywator: tworzy
ProfilingTriggerdlaTRIGGER_TYPE_APP_FULLY_DRAWN. To zdarzenie występuje, gdy aplikacja zgłosi, że zakończyła uruchamianie i jest interaktywna. - Ustawianie limitów częstotliwości: stosuje 1-godzinny limit częstotliwości do tego konkretnego wyzwalacza (
setRateLimitingPeriodHours(1)). Zapobiega to rejestrowaniu przez aplikację więcej niż 1 profilu uruchamiania na godzinę. - Zarejestruj odbiorcę: wywołuje
registerForAllProfilingResults, aby zdefiniować wywołanie zwrotne, które obsługuje wynik. To wywołanie zwrotne otrzymuje ścieżkę zapisanego profilu za pomocą parametrugetResultFilePath(). - Add triggers: rejestruje listę reguł w
ProfilingManagerza pomocąaddProfilingTriggers. - Uruchom zdarzenie: wywołuje funkcję
reportFullyDrawn(), która wysyła zdarzenieTRIGGER_TYPE_APP_FULLY_DRAWNdo systemu, co powoduje uruchomienie zbierania profilu. Zakłada się, że w tle działa śledzenie systemowe i dostępny jest limit ogranicznika częstotliwości. Ten opcjonalny krok pokazuje pełny proces, ponieważ w przypadku tego aktywatora aplikacja musi wywołaćreportFullyDrawn().
Pobieranie śladu
System zapisuje profile oparte na wyzwalaczach w tym samym katalogu co inne profile. Nazwa pliku ze śladami wywołanymi ma format:
profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>
Możesz pobrać plik za pomocą ADB. Aby na przykład pobrać ślad systemowy zarejestrowany za pomocą przykładowego kodu za pomocą ADB, możesz użyć tego polecenia:
adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace
Szczegółowe informacje o wizualizacji tych śladów znajdziesz w artykule Pobieranie i analizowanie danych profilowania.
Jak działa śledzenie w tle
Aby rejestrować dane sprzed wywołania, system operacyjny okresowo uruchamia śledzenie w tle. Jeśli podczas aktywnego śledzenia w tle wystąpi wyzwalacz, na który zarejestrowana jest Twoja aplikacja, system zapisze profil śledzenia w katalogu aplikacji. Profil będzie zawierać informacje o zdarzeniach, które doprowadziły do wywołania.
Po zapisaniu profilu system powiadamia aplikację za pomocą wywołania zwrotnego podanego w registerForAllProfilingResults. To wywołanie zwrotne podaje ścieżkę do przechwyconego profilu, do którego można uzyskać dostęp, wywołując ProfilingResult#getResultFilePath().
Aby zmniejszyć wpływ na wydajność urządzenia i czas pracy baterii, system nie śledzi w tle w sposób ciągły. Zamiast tego stosuje metodę próbkowania. System losowo rozpoczyna śledzenie w tle w określonym przedziale czasu (o minimalnym i maksymalnym czasie trwania). Losowe rozmieszczenie tych śladów zwiększa zasięg wyzwalania.
Profile wywoływane przez system mają zdefiniowany przez system maksymalny rozmiar, więc używają bufora pierścieniowego. Gdy bufor jest pełny, nowe dane śledzenia zastępują najstarsze dane. Jak widać na rysunku 1, zarejestrowany ślad może nie obejmować całego czasu trwania nagrywania w tle, jeśli bufor się zapełni. Zamiast tego przedstawia on najnowszą aktywność prowadzącą do wywołania.
Wdrażanie ograniczeń liczby żądań w przypadku poszczególnych wyzwalaczy
Triggery o wysokiej częstotliwości mogą szybko wyczerpać limit ogranicznika szybkości aplikacji. Aby lepiej zrozumieć ogranicznik szybkości, zapoznaj się z artykułem Jak działa ogranicznik szybkości. Aby zapobiec wyczerpaniu limitu przez jeden typ wyzwalacza, możesz wdrożyć ograniczenie liczby wywołań dla poszczególnych wyzwalaczy.
ProfilingManager obsługuje ograniczenie liczby wywołań zależne od wywoływacza zdefiniowane przez aplikację. Dzięki temu możesz dodać kolejną warstwę ograniczania na podstawie czasu oprócz istniejącego ogranicznika szybkości. Użyj interfejsu API setRateLimitingPeriodHours, aby ustawić konkretny czas oczekiwania na aktywator. Po upływie okresu oczekiwania możesz ponownie wywołać to działanie.
Debugowanie aktywatorów lokalnie
Ślady w tle są uruchamiane w losowych momentach, więc lokalne debugowanie wyzwalaczy jest trudne. Aby wymusić śledzenie w tle na potrzeby testowania, użyj tego polecenia ADB:
adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>
To polecenie wymusza rozpoczęcie ciągłego śledzenia w tle dla określonego pakietu, co umożliwia każdemu aktywatorowi zbieranie profilu, jeśli zezwala na to ogranicznik szybkości.
Możesz też włączyć inne opcje debugowania, np. wyłączyć ogranicznik szybkości podczas debugowania lokalnego. Więcej informacji znajdziesz w artykule Polecenia debugowania do profilowania lokalnego.