Ya sea que captures un perfil controlado por la app o un perfil basado en activadores,
ProfilingManager guarda el archivo completado en el dispositivo y entrega un
ProfilingResult a tu devolución de llamada registrada. Llama a ProfilingResult.getResultFilePath para obtener la ruta de acceso del perfil guardado:
- Durante las pruebas locales: Extrae el archivo a tu computadora con
adb. - En producción: Pasa la ruta de acceso a un trabajo de
WorkManagerque comprima y suba el perfil a tu servidor.
Cómo recuperar perfiles de un dispositivo
En esta sección, se describe dónde almacena ProfilingManager los perfiles en el dispositivo, cómo funciona la limpieza automática de archivos y cómo extraer archivos de forma local con adb.
Ubicaciones de archivos y formatos de nombres
ProfilingManager guarda los perfiles ocultados en el directorio de almacenamiento específico de la app en /data/user/0/<app>/files/profiling/. El formato del nombre de archivo depende de cómo se capturó el perfil:
Perfiles controlados por apps:
profile_<tag>_<datetime>_uid-<uid>.<profile-type-ext>Si no se proporcionó ninguna etiqueta cuando se solicitó el perfil, se omite
<tag>_:profile_<datetime>_uid-<uid>.<profile-type-ext>.Perfiles basados en activadores:
profile_trigger-type-<trigger_type>_<datetime>_uid-<uid>.<profile-type-ext>
En la que:
<app>es el nombre del paquete de tu app.<tag>son los primeros 20 caracteres alfanuméricos (y guiones) de la etiqueta proporcionada por el emisor configurada consetTago pasada arequestProfiling, convertida a minúsculas con cualquier carácter fuera dea-z,0-9y-quitados.<trigger_type>es el código de constante de número entero para el activador deProfilingTrigger. Siempre llama aProfilingResult.getTriggerTypeen el código en lugar de analizar el nombre del archivo.<datetime>es la fecha y la hora en que se registró el perfil (yyyy-MM-dd-HH-mm-ss-SSS).<uid>es el ID de usuario de Linux de tu app (incluido en las versiones recientes del móduloProfiling).<profile-type-ext>es la extensión de archivo para el tipo de perfil capturado:.perfetto-tracepara los registros del sistema.perfetto-java-heap-dumppara volcados de montón de Java.perfetto-heap-profilepara perfiles del montón.perfetto-stack-samplepara perfiles de muestreo de pila
Almacenamiento y limpieza en el dispositivo
Para liberar almacenamiento del dispositivo de inmediato, borra cada archivo de perfil en tu trabajador de carga inmediatamente después de una carga exitosa (debido a que la limpieza automática solo se ejecuta cuando ProfilingManager entrega resultados a tu app, los archivos no subidos pueden permanecer en el disco si tu app deja de registrar devoluciones de llamada después de finalizar una campaña). Como resguardo en las versiones recientes del módulo Profiling,
ProfilingManager también borra automáticamente los archivos entregados en el
directorio de almacenamiento específico de la app que tengan más de 5 días de antigüedad cuando se entregan
resultados nuevos.
Sube perfiles en producción con WorkManager
Debido a que los archivos de perfil pueden tener un tamaño de varios megabytes, programa las cargas de producción en segundo plano cuando el dispositivo esté en una red no medida (Wi-Fi), se esté cargando y esté inactivo.
Antes de subirlo, comprime el archivo de perfil (por ejemplo, con
GZIPOutputStream o ZipOutputStream). Los perfiles de protobuf de Perfetto y los volcados de montón de Java
se comprimen de forma significativa, lo que reduce el ancho de banda de la red y los costos de almacenamiento
del backend.
Cómo agregar dependencias de WorkManager
ProfilingManager es independiente de la nube, por lo que puedes programar la carga de perfiles
en cualquier backend con WorkManager. Agrega la biblioteca WorkManager a tu archivo build.gradle.kts:
Kotlin
dependencies { implementation("androidx.work:work-runtime:2.12.0") }
Groovy
dependencies { implementation 'androidx.work:work-runtime:2.12.0' }
Cómo programar un trabajo de carga
Cuando tu app reciba un ProfilingResult, programa el trabajo de carga. En el siguiente ejemplo, se omite la solicitud de generación de perfiles inicial. Para ver un ejemplo de solicitud completo, consulta Cómo registrar un seguimiento del sistema.
Kotlin
class TraceUploadWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { // Perform your uploading work here Log.d("ProfileTest", "Uploading trace: " + inputData.getString("PROFILE_PATH")) return Result.success() } } fun setupProfileUploadWorker(profileFilepath: String?) { val workMgr = WorkManager.getInstance(applicationContext) val workRequestBuilder = OneTimeWorkRequest.Builder(TraceUploadWorker::class) val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .build() workRequestBuilder.setConstraints(constraints) val inputDataBuilder = Data.Builder() inputDataBuilder.putString("PROFILE_PATH", profileFilepath) workRequestBuilder.setInputData(inputDataBuilder.build()) workMgr.enqueue(workRequestBuilder.build()) }
Java
public static class TraceUploadWorker extends Worker { public TraceUploadWorker( @androidx.annotation.NonNull Context context, @androidx.annotation.NonNull WorkerParameters workerParams) { super(context, workerParams); } @androidx.annotation.NonNull @Override public Result doWork() { // Perform your uploading work here Log.d("ProfileTest", "Uploading trace: " + getInputData().getString("PROFILE_PATH")); return Result.success(); } } public void setupProfileUploadWorker(String profileFilepath) { WorkManager workMgr = WorkManager.getInstance(getApplicationContext()); OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder( TraceUploadWorker.class); Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .build(); workRequestBuilder.setConstraints(constraints); Data.Builder inputDataBuilder = new Data.Builder(); inputDataBuilder.putString("PROFILE_PATH", profileFilepath); workRequestBuilder.setInputData(inputDataBuilder.build()); workMgr.enqueue(workRequestBuilder.build()); }
Explicación del código
En el ejemplo anterior, se realizan los siguientes pasos:
- Define el trabajador: Crea una clase
TraceUploadWorkerque extiendaWorker. ImplementadoWorkpara verificar que el archivo de perfil aún exista, comprimirlo y subirlo con tu SDK de backend o cliente HTTP, y borrar el archivo local una vez que se complete la carga. - Programa el trabajo:
- Crea un
OneTimeWorkRequestpara tu trabajador. - Establece restricciones: Usa
setRequiredNetworkType(NetworkType.UNMETERED),setRequiresDeviceIdle(true)ysetRequiresCharging(true)para que la carga solo se ejecute cuando el dispositivo esté conectado a Wi-Fi, cargándose y en estado inactivo. - Pasa datos: Usa
setInputDatapara pasar la ruta de acceso del perfil degetResultFilePathal trabajador. - Enqueue: Envía la solicitud a
WorkManagerllamando aWorkManager.enqueue.
- Crea un
Próximos pasos
Después de recuperar o subir perfiles, visualízalos en la IU de Perfetto, consulta perfiles individuales con PerfettoSQL, analiza seguimientos de forma masiva o analiza perfiles con IA. Para obtener orientación sobre cómo configurar una canalización de análisis escalable del lado del servidor, consulta Implementa Bigtrace en Kubernetes.