Su Android 16 (livello API 36) e versioni successive, ProfilingManager ti consente di acquisire
i profili automaticamente in risposta ad attivatori di sistema, come errori di tipo L'applicazione non
risponde (ANR), arresti anomali per out of memory (OutOfMemoryError) o eventi di avvio
dell'app. Poiché non puoi prevedere quando si verificheranno molti di questi eventi sul campo, non è pratico avviare manualmente una registrazione in anticipo. Con la profilazione basata su trigger, il sistema gestisce l'acquisizione e fornisce il profilo risultante alla tua app in modo che tu possa:
- Esegui il debug dei problemi di stabilità: diagnostica ANR imprevedibili e perdite di memoria.
-
TRIGGER_TYPE_COLD_STARTTRIGGER_TYPE_APP_FULLY_DRAWN - Comprendi il comportamento degli utenti: esamina eventi come le uscite dall'app avviate dagli utenti.
Per l'elenco completo dei trigger disponibili, consulta ProfilingTrigger.
Tipi di trigger
I trigger differiscono nel modo in cui il sistema acquisisce il profilo quando si verifica l'evento.
Trigger che utilizzano la traccia in background
Molti trigger, come un ANR, sono la conseguenza di un problema precedente. L'avvio di una traccia solo dopo che il sistema ha rilevato l'ANR non tiene conto del lavoro di blocco che l'ha causato. Per acquisire l'attività che precede l'evento, i seguenti trigger salvano uno snapshot della traccia in background attiva del sistema. Se non è in esecuzione alcuna traccia in background quando si verifica l'evento, non viene raccolto alcun profilo:
TRIGGER_TYPE_ANR(livello API 36)TRIGGER_TYPE_APP_FULLY_DRAWN(livello API 36)TRIGGER_TYPE_APP_REQUEST_RUNNING_TRACE(livello API 36.1)TRIGGER_TYPE_KILL_FORCE_STOP(livello API 36.1)TRIGGER_TYPE_KILL_RECENTS(livello API 36.1)TRIGGER_TYPE_KILL_TASK_MANAGER(livello API 36.1)TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE(livello API 37)
Trigger che avviano una nuova acquisizione
I seguenti trigger non dipendono dalla traccia in background. Invece, il sistema avvia una nuova acquisizione del profilo quando si verifica l'evento:
TRIGGER_TYPE_COLD_START(livello API 37)TRIGGER_TYPE_OOM(livello API 37)
Trigger in cui il comportamento di acquisizione varia in base all'anomalia
Per i seguenti trigger di anomalie, il tipo di profilo acquisito (salvataggio di uno snapshot della traccia in background attiva o avvio di una nuova acquisizione) e il comportamento di limitazione di frequenza dipendono dall'anomalia specifica rilevata dal sistema:
TRIGGER_TYPE_ANOMALY(livello API 37)TRIGGER_TYPE_APP_COMPAT(livello API 37)
Configura un trigger
Il codice seguente mostra come registrarsi per l'attivatore TRIGGER_TYPE_APP_FULLY_DRAWN e impostare un periodo di attesa.
Kotlin
@RequiresApi(Build.VERSION_CODES.BAKLAVA) fun recordWithTrigger() { val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java) ?: return val triggers = ArrayList<ProfilingTrigger>() val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN) .setRateLimitingPeriodHours(1) triggers.add(triggerBuilder.build()) val callbackExecutor: 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(callbackExecutor, resultCallback) profilingManager.addProfilingTriggers(triggers) Choreographer.getInstance().postFrameCallback { frameTimeNanos -> // This will cause the TRIGGER_TYPE_APP_FULLY_DRAWN to be emitted. reportFullyDrawn() } }
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 callbackExecutor = 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(callbackExecutor, resultCallback); profilingManager.addProfilingTriggers(triggers); Choreographer.getInstance().postFrameCallback((f) -> { // This will cause the TRIGGER_TYPE_APP_FULLY_DRAWN to be emitted. reportFullyDrawn(); }); }
Il codice esegue questi passaggi:
- Recupera il gestore: recupera il servizio
ProfilingManager. - Definisci un trigger: crea un
ProfilingTriggerperTRIGGER_TYPE_APP_FULLY_DRAWN. Questo evento si verifica quando l'app chiamareportFullyDrawn()durante un avvio a freddo avviato dall'attività per segnalare che ha terminato l'avvio ed è interattiva. - Imposta un periodo di attesa per l'attivatore: applica un periodo di attesa di 1 ora a questo attivatore specifico utilizzando
setRateLimitingPeriodHoursoltre al limitatore di frequenza del sistema. Questo periodo di attesa impedisce all'app di registrare più di un profilo di avvio all'ora. - Registra il listener: chiama
registerForAllProfilingResultsper definire il callback che gestisce il risultato. Questo callback riceve il percorso del profilo salvato tramitegetResultFilePath(). - Aggiungi trigger: registra l'elenco di trigger con
ProfilingManagerutilizzandoaddProfilingTriggers. - Attiva evento: pubblica un callback del frame
Choreographerche chiamareportFullyDrawn()una volta disegnato il frame successivo, che emette l'eventoTRIGGER_TYPE_APP_FULLY_DRAWNal sistema, attivando una raccolta di profili supponendo che sia in esecuzione una traccia in background del sistema e che sia disponibile la quota del limitatore di frequenza. Affinché questo trigger si verifichi, assicurati che la tua app chiamireportFullyDrawn().
Ciclo di vita dei trigger
I trigger registrati rimangono invariati dopo i riavvii dell'app e del sistema. Non è necessario registrare nuovamente i trigger ogni volta che l'app viene avviata o dopo un riavvio del sistema: una volta registrati i trigger utilizzando addProfilingTriggers, il sistema li gestisce automaticamente per la tua app finché non li rimuovi o l'app non viene disinstallata.
Quando annullare la registrazione dei trigger
Poiché i trigger registrati persistono tra i riavvii dell'app e del sistema,
se salti addProfilingTriggers nei lanci successivi, i trigger
registrati in una sessione precedente non vengono interrotti. Per interrompere l'acquisizione dei profili per eventi specifici o per tutti gli eventi, chiama esplicitamente removeProfilingTriggersByType o clearProfilingTriggers.
Annulla la registrazione degli attivatori nelle seguenti situazioni:
- Targeting di coorti o rollback di flag remoti: potresti segmentare la profilazione tra coorti utilizzando la configurazione remota o i flag di test A/B. Ogni volta che un dispositivo lascia la coorte campionata o un flag viene disattivato, annulla la registrazione degli attivatori.
- Completamento di una campagna di debug: una volta raccolti abbastanza profili per diagnosticare un problema o applicare una correzione, rimuovi l'attivatore. Annullando la registrazione dei trigger non necessari, preservi lo spazio sul dispositivo e la quota del limitatore di frequenza della tua app per altre richieste di profilazione.
Ciclo di vita del callback
A differenza delle richieste di profilazione diretta, i profili basati su trigger forniscono risultati solo a un listener globale registrato con registerForAllProfilingResults. Nel
callback, chiama ProfilingResult.getTriggerType per identificare quale
trigger ha avviato l'acquisizione e chiama
ProfilingResult.getResultFilePath per individuare il file del profilo salvato. Per
maggiori dettagli sui nomi file dei profili di attivazione, sul recupero dei file con adb e sul caricamento
dei risultati in background, consulta Recupera e carica i profili.
Sebbene i trigger vengano mantenuti durante i riavvii dell'app e del sistema, il callback dei risultati non viene mantenuto. Registra il callback su un Executor in background dopo il completamento dell'avvio dell'app (in modo da non rallentare l'avvio a freddo) per ricevere i profili in entrambi i seguenti scenari:
- Mentre l'app è in esecuzione: per i trigger che non arrestano o non causano l'arresto anomalo dell'app, il sistema richiama il callback sul
Executorfornito quando si verifica il trigger e il profilo viene salvato. Dopo la chiusura dell'app: per i trigger che spesso coinvolgono o precedono la chiusura dell'app (come
TRIGGER_TYPE_ANR,TRIGGER_TYPE_OOMoTRIGGER_TYPE_KILL_RECENTS) o se l'app si arresta prima del completamento dell'acquisizione, il sistema salva il profilo in background e mette in coda il risultato tra i riavvii dell'app e del sistema. Il sistema conserva i risultati in coda non recapitati per un massimo di 7 giorni e li recapita alla successiva esecuzione dell'app e alla chiamata diregisterForAllProfilingResults.
Come funziona il tracciamento in background
Per bilanciare l'overhead di profilazione con l'acquisizione di artefatti utili, il sistema non esegue continuamente tracce in background. Invece, campiona periodicamente avviando tracce in background a intervalli casuali.
Le tracce in background attivate dal sistema utilizzano un buffer circolare con una dimensione massima definita dal sistema. Quando il buffer si riempie, i nuovi dati di traccia sovrascrivono i dati più vecchi. Come mostrato nella Figura 1, quando un trigger registrato si attiva mentre è attiva una traccia in background e la quota del limitatore di frequenza è disponibile, il sistema salva lo snapshot del buffer circolare contenente l'attività più recente che ha portato al trigger.
Imposta un periodo di attesa specifico per l'attivatore
Gli attivatori ad alta frequenza possono consumare rapidamente la quota del limitatore di frequenza della tua app.
Per evitare che un singolo tipo di trigger esaurisca la quota, utilizza
setRateLimitingPeriodHours per aggiungere un periodo di attesa minimo per trigger
oltre al limitatore di frequenza del sistema.
Esegui il debug dei trigger in locale
Poiché le tracce in background vengono eseguite a intervalli casuali in produzione, l'attivazione dei trigger localmente richiede l'esecuzione forzata di una traccia in background continua e l'elusione del limitatore di frequenza a livello di sistema per il tuo pacchetto (viene comunque applicato qualsiasi cooldown per trigger impostato con setRateLimitingPeriodHours e rate_limiter.disabled si applica solo alle chiamate requestProfiling basate sull'app).
Per i comandi adb per forzare le tracce in background, simulare i trigger dalla riga di comando e ispezionare lo stato del servizio, consulta Forza l'attivazione delle tracce in background per i test dei trigger in Comandi di debug per la profilazione locale.