En esta página, se muestra cómo registrar un seguimiento del sistema con la API de ProfilingManager.
ProfilingManager también puede registrar otros tipos de perfiles. Este proceso es similar al registro de un seguimiento del sistema, pero cada tipo usa un compilador diferente. Los perfiles compatibles y sus compiladores son los siguientes:
Seguimientos del sistema: Se registran con
SystemTraceRequestBuilder, que son útiles para el análisis de latencia y la depuración general del rendimiento.Volcados de montón: Se registran con
JavaHeapDumpRequestBuilder, que son útiles para la detección y la optimización de fugas de memoria.Perfiles de montón: Se registran con
HeapProfileRequestBuilder, que son útiles para la optimización de la memoria.Perfiles de pila de llamadas: Se registran con
StackSamplingRequestBuilder, que son útiles para comprender la ejecución del código y el análisis de latencia.
Cómo agregar dependencias
Para obtener la mejor experiencia con la API de ProfilingManager, agrega las siguientes bibliotecas de Jetpack a tu archivo build.gradle.kts.
Kotlin
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.1") implementation("androidx.core:core:1.19.0") }
Groovy
dependencies { implementation 'androidx.tracing:tracing:2.0.1' implementation 'androidx.core:core:1.19.0' }
Cómo registrar un seguimiento del sistema
Después de agregar las dependencias necesarias, usa el siguiente código para registrar un seguimiento del sistema. En este ejemplo, se muestra cómo iniciar una sesión de generación de perfiles desde un elemento componible mientras se administran de forma segura las operaciones pesadas fuera del subproceso principal.
Kotlin
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Composable
fun ProfiledScreen(modifier: Modifier = Modifier) {
// Use the application context: requestProfiling resolves the ProfilingManager
// system service from it, so there's no reason to hand it a short-lived Activity.
val appContext = LocalContext.current.applicationContext
val scope = rememberCoroutineScope()
Button(
onClick = {
// Run the orchestration off the main thread. Profiling a heavy operation
// on the UI thread would freeze the UI (ANR) and distort the very metrics
// you're trying to capture.
//
// Note: this scope is tied to composition. If the user leaves this screen
// mid-session, the coroutine is cancelled and stopSignal.cancel() might not
// run, but setDurationMs() acts as a safety net and ends the trace.
scope.launch(Dispatchers.Default) {
val callbackExecutor = Dispatchers.IO.asExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
Log.d("ProfileTest", "Result file: ${profilingResult.resultFilePath}")
} else {
// errorMessage explains the failure (e.g., rate limiting); keep it.
Log.e(
"ProfileTest",
"Profiling failed errorCode=${profilingResult.errorCode} " +
"errorMessage=${profilingResult.errorMessage}"
)
}
}
val stopSignal = CancellationSignal()
val requestBuilder = SystemTraceRequestBuilder().apply {
setCancellationSignal(stopSignal)
setTag("FOO") // Caller-supplied tag for identification.
setDurationMs(60000) // Hard cap: ends the session if cancel() never fires.
setBufferFillPolicy(BufferFillPolicy.RING_BUFFER)
setBufferSizeKb(32768)
}
// 1. Start the session. This is asynchronous system IPC. The tracing
// engine takes a moment to start and allocate buffers.
requestProfiling(appContext, requestBuilder.build(), callbackExecutor, resultCallback)
// 2. The API exposes no "profiling started" signal, so pad with a short,
// best-effort delay before running the code you care about. This is
// approximate. Increase it on slower or heavily loaded devices.
delay(STARTUP_PADDING_MS)
// 3. The session is already recording every thread in your app. This slice
// doesn't scope what's captured. It just labels this region of the
// timeline so heavyOperation() is easier to find. trace { } closes the
// section even if the block throws.
trace("MyApp:HeavyOperation") {
heavyOperation()
}
// 4. Stop recording. Until this fires or the setDurationMs() cap is
// reached (whichever comes first), the session keeps capturing app-wide
// activity.
stopSignal.cancel()
}
}
) {
Text("Run & Profile Heavy Operation")
}
}
// Best-effort wait for the system trace engine to initialize before profiling.
// There is no deterministic start callback; tune this for your target devices.
private const val STARTUP_PADDING_MS = 100L
fun heavyOperation() {
// Background computations to profile.
}
Java
void heavyOperation() {
// Computations you want to profile
}
void sampleRecordSystemTrace() {
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());
}
}
};
CancellationSignal stopSignal = new CancellationSignal();
SystemTraceRequestBuilder requestBuilder = new SystemTraceRequestBuilder();
requestBuilder.setCancellationSignal(stopSignal);
requestBuilder.setTag("FOO");
requestBuilder.setDurationMs(60000);
requestBuilder.setBufferFillPolicy(BufferFillPolicy.RING_BUFFER);
requestBuilder.setBufferSizeKb(32768);
Profiling.requestProfiling(getApplicationContext(), requestBuilder.build(), mainExecutor,
resultCallback);
// Wait some time for profiling to start.
Trace.beginSection("MyApp:HeavyOperation");
heavyOperation();
Trace.endSection();
// Once the interesting code section is profiled, stop profile
stopSignal.cancel();
}
El código de muestra configura y administra la sesión de generación de perfiles siguiendo estos pasos:
Configura el ejecutor. Crea un
Executorpara definir el subproceso que recibirá los resultados de la generación de perfiles. La generación de perfiles se realiza en segundo plano. El uso de un ejecutor de subprocesos que no sea de la IU ayuda a evitar errores de aplicación no responde (ANR) si agregas más procesamiento a la devolución de llamada más adelante.Controla los resultados de la generación de perfiles. Crea un objeto
Consumer<ProfilingResult>. El sistema usa este objeto para enviar los resultados de la generación de perfiles deProfilingManagera tu app.Compila la solicitud de generación de perfiles. Crea un
SystemTraceRequestBuilderpara configurar tu sesión de generación de perfiles. Este compilador te permite personalizar la configuración de seguimiento deProfilingManager. La personalización del compilador es opcional; si no lo haces, el sistema usa la configuración predeterminada.- Define una etiqueta. Usa
setTag()para agregar una etiqueta al nombre del seguimiento. Esta etiqueta te ayuda a identificar el seguimiento. - Opcional: Establece la duración. Usa
setDurationMs()para especificar cuánto tiempo se generará el perfil en milisegundos. Por ejemplo,60000establece un seguimiento de 60 segundos. El seguimiento finaliza automáticamente después de la duración especificada siCancellationSignalno se activa antes. - Elige una política de búfer. Usa
setBufferFillPolicy()para definir cómo se almacenan los datos de seguimiento.BufferFillPolicy.RING_BUFFERsignifica que, cuando el búfer está lleno, los datos nuevos reemplazan a los más antiguos, lo que mantiene un registro continuo de la actividad reciente. - Establece un tamaño de búfer. Usa
setBufferSizeKb()para especificar un tamaño de búfer para el seguimiento que puedes usar para controlar el tamaño del archivo de seguimiento de salida.
- Define una etiqueta. Usa
Opcional: Administra el ciclo de vida de la sesión. Crea un
CancellationSignal. Este objeto te permite detener la sesión de generación de perfiles cuando quieras, lo que te brinda un control preciso sobre su duración.Inicia y recibe resultados. Cuando llamas a
requestProfiling(),ProfilingManagerinicia una sesión de generación de perfiles en segundo plano. Una vez que se completa la generación de perfiles, envía elProfilingResulta tu métodoresultCallback#accept. Si la generación de perfiles finaliza correctamente, theProfilingResultproporciona la ruta de acceso en la que se guardó el seguimiento en tu dispositivo a través deProfilingResult#getResultFilePath. Puedes obtener este archivo de forma programática o, para la generación de perfiles local, ejecutandoadb pull <trace_path>desde tu computadora.Agrega puntos de seguimiento personalizados. Puedes agregar puntos de seguimiento personalizados en el código de tu app. En el ejemplo de código anterior, el
trace("MyApp:HeavyOperation") { ... }bloque crea un segmento personalizado en el perfil generado.