No Android 16 (nível 36 da API) e versões mais recentes, o ProfilingManager permite capturar
perfis automaticamente em resposta a acionadores do sistema, como erros de O app não está
respondendo (ANR), falhas de falta de memória (OutOfMemoryError) ou eventos de inicialização
do app. Como não é possível prever quando muitos desses eventos vão ocorrer
em campo, não é prático iniciar uma gravação manualmente com antecedência. Com
a criação de perfil baseada em gatilhos, o sistema gerencia a captura e entrega o
perfil resultante ao app para que você possa:
- Depurar problemas de estabilidade: diagnostique ANRs imprevisíveis e vazamentos de memória.
- Otimizar as jornadas ideais do usuário (CUJs, na sigla em inglês): analise fluxos como a inicialização do app (
TRIGGER_TYPE_COLD_STARTeTRIGGER_TYPE_APP_FULLY_DRAWN). - Entender o comportamento do usuário: inspecione eventos como saídas do app iniciadas pelo usuário.
Para ver a lista completa de gatilhos disponíveis, consulte ProfilingTrigger.
Tipos de gatilho
Os acionadores diferem na forma como o sistema captura o perfil quando o evento ocorre.
Acionadores que usam o trace em segundo plano
Muitos acionadores, como um ANR, são consequência de um problema anterior. Iniciar um rastreamento somente depois que o sistema detecta o ANR não mostra o trabalho de bloqueio que o causou. Para capturar a atividade que levou ao evento, os gatilhos a seguir salvam um snapshot do rastreamento em segundo plano ativo do sistema. Se nenhum rastreamento em segundo plano estiver em execução quando o evento ocorrer, nenhum perfil será coletado:
TRIGGER_TYPE_ANR(nível 36 da API)TRIGGER_TYPE_APP_FULLY_DRAWN(nível 36 da API)TRIGGER_TYPE_APP_REQUEST_RUNNING_TRACE(nível 36.1 da API)TRIGGER_TYPE_KILL_FORCE_STOP(nível 36.1 da API)TRIGGER_TYPE_KILL_RECENTS(nível 36.1 da API)TRIGGER_TYPE_KILL_TASK_MANAGER(nível 36.1 da API)TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE(nível 37 da API)
Acionadores que iniciam uma nova captura
Os gatilhos a seguir não dependem do trace em segundo plano. Em vez disso, o sistema inicia uma nova captura de perfil quando o evento ocorre:
TRIGGER_TYPE_COLD_START(nível 37 da API)TRIGGER_TYPE_OOM(nível 37 da API)
Gatilhos em que o comportamento de captura varia de acordo com a anomalia
Para os seguintes acionadores de anomalias, o tipo de perfil capturado (salvar um snapshot do trace em segundo plano ativo ou iniciar uma nova captura) e o comportamento de limitação de taxa dependem da anomalia específica detectada pelo sistema:
TRIGGER_TYPE_ANOMALY(nível 37 da API)TRIGGER_TYPE_APP_COMPAT(nível 37 da API)
Configurar um gatilho
O código a seguir demonstra como se registrar para o
acionador TRIGGER_TYPE_APP_FULLY_DRAWN e definir um período de espera nele.
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(); }); }
O código executa as seguintes etapas:
- Acessar o gerenciador: recupera o serviço
ProfilingManager. - Definir um gatilho: cria um
ProfilingTriggerparaTRIGGER_TYPE_APP_FULLY_DRAWN. Esse evento ocorre quando o app chamareportFullyDrawn()durante uma inicialização a frio iniciada por atividade para informar que concluiu a inicialização e está interativo. - Definir um período de espera do acionador: aplica um período de espera de 1 hora a esse
acionador específico usando
setRateLimitingPeriodHours, além do limitador de taxa do sistema. Esse período de espera impede que o app registre mais de um perfil de inicialização por hora. - Registrar listener: chama
registerForAllProfilingResultspara definir o callback que processa o resultado. Esse callback recebe o caminho do perfil salvo porgetResultFilePath(). - Adicionar gatilhos: registra a lista de gatilhos com
ProfilingManagerusandoaddProfilingTriggers. - Evento de disparo: publica um callback de frame
Choreographerque chamareportFullyDrawn()quando o próximo frame é desenhado, o que emite o eventoTRIGGER_TYPE_APP_FULLY_DRAWNpara o sistema, acionando uma coleta de perfil, supondo que um rastro em segundo plano do sistema esteja em execução e que a cota do limitador de taxa esteja disponível. Para que esse acionador ocorra, verifique se o app chamareportFullyDrawn().
Ciclo de vida do gatilho
Os acionadores registrados persistem após as reinicializações do app e do sistema. Não é necessário
registrar novamente os acionadores sempre que o app é iniciado ou após uma reinicialização
do sistema. Depois que você registra os acionadores usando addProfilingTriggers, o
sistema os mantém automaticamente para o app até que você os remova ou o
app seja desinstalado.
Quando cancelar o registro de acionadores
Como os acionadores registrados persistem nas reinicializações do app e do sistema,
pular addProfilingTriggers em inicializações subsequentes não interrompe os acionadores
registrados em uma sessão anterior. Para interromper a captura de perfis de eventos específicos
ou de todos os eventos, chame explicitamente removeProfilingTriggersByType ou
clearProfilingTriggers.
Cancele o registro de acionadores nas seguintes situações:
- Segmentar coortes ou reverter flags remotas: é possível segmentar a criação de perfis em coortes usando a Configuração remota ou flags de teste A/B. Sempre que um dispositivo sair da coorte de amostra ou uma flag for desativada, cancele o registro dos acionadores.
- Finalizar uma campanha de depuração: depois de coletar perfis suficientes para diagnosticar um problema ou enviar uma correção, remova o gatilho. O cancelamento da inscrição de acionadores desnecessários preserva o armazenamento do dispositivo e a cota do limitador de taxa do app para outras solicitações de criação de perfil.
Ciclo de vida do callback
Ao contrário das solicitações de criação de perfil direta, os perfis baseados em acionadores só mostram resultados para
um listener global registrado com registerForAllProfilingResults. No
callback, chame ProfilingResult.getTriggerType para identificar qual
acionador iniciou a captura e chame
ProfilingResult.getResultFilePath para localizar o arquivo de perfil salvo. Para
detalhes sobre nomes de arquivos de perfil de acionador, extração de arquivos com adb e upload
de resultados em segundo plano, consulte Recuperar e fazer upload de perfis.
Embora os acionadores persistam nas reinicializações do app e do sistema, o callback de resultado
não. Registre o callback em um Executor em segundo plano após a conclusão da inicialização do app (para não desacelerar a inicialização a frio) para receber perfis nos dois cenários a seguir:
- Enquanto o app está em execução: para acionadores que não interrompem ou travam o
app, o sistema invoca o callback no
Executorfornecido quando o acionador ocorre e o perfil é salvo. Após o encerramento do app: para acionadores que geralmente envolvem ou precedem o encerramento do app (como
TRIGGER_TYPE_ANR,TRIGGER_TYPE_OOMouTRIGGER_TYPE_KILL_RECENTS) ou se o app for interrompido antes da conclusão da captura, o sistema vai salvar o perfil em segundo plano e colocar o resultado em fila nas reinicializações do app e do sistema. O sistema retém os resultados não entregues na fila por até sete dias e os entrega na próxima vez que o app for executado e chamarregisterForAllProfilingResults.
Como funciona o rastreamento em segundo plano
Para equilibrar a sobrecarga de criação de perfil com a captura de artefatos úteis, o sistema não executa traces em segundo plano continuamente. Em vez disso, ele faz amostragens periodicamente, iniciando traces em segundo plano em intervalos aleatórios.
Os rastreamentos em segundo plano acionados pelo sistema usam um buffer circular com um tamanho máximo definido pelo sistema. Quando o buffer é preenchido, os novos dados de trace substituem os mais antigos. Como mostrado na Figura 1, quando um acionador registrado é disparado enquanto um trace em segundo plano está ativo e a cota do limitador de taxa está disponível, o sistema salva o snapshot do buffer circular que contém a atividade mais recente que levou ao acionador.
Definir um período de espera específico para o acionador
Os acionadores de alta frequência podem consumir rapidamente a cota do limitador de taxa do app.
Para evitar que um único tipo de gatilho esgote sua cota, use
setRateLimitingPeriodHours para adicionar um período de espera mínimo por gatilho
além do limitador de taxa do sistema.
Depurar gatilhos localmente
Como os traces em segundo plano são executados em intervalos aleatórios na produção, o teste
de acionadores localmente exige que você force um trace em segundo plano contínuo e ignore
o limitador de taxa no nível do sistema para seu pacote (qualquer período de espera por acionador definido
com setRateLimitingPeriodHours ainda se aplica, e
rate_limiter.disabled se aplica apenas a chamadas requestProfiling
orientadas pelo app).
Para que os comandos adb forcem os traces em segundo plano, simulem acionadores na
linha de comando e inspecionem o estado do serviço, consulte Forçar a ativação de traces em segundo plano para
testes de acionadores em Comandos de depuração para criação de perfil local.