
Cuando una app de Android se siente lenta, con tirones o animaciones a trompicones (desactivar las animaciones del sistema), casi siempre hay un culpable oculto en segundo plano: la latencia y el temido jank. Android ofrece varias herramientas de diagnóstico, pero una de las más potentes y flexibles es perfetto, combinada con el clásico comando dumpsys y fuentes de datos como ftrace, atrace o heapprofd. Entender bien cómo usarlas te permite pasar de la sensación vaga de “mi app va rara” a tener números, trazas y causas concretas.
En este artículo vamos a desgranar, con calma pero sin rodeos, cómo funciona perfetto en Android, qué modos de uso tiene, qué fuentes de datos puede activar y cómo se complementa con otros comandos clave como dumpsys gfxinfo, dumpsys meminfo o dumpsys batterystats. La idea es que tengas una visión completa de todo lo que puedes medir y cómo aprovecharlo para optimizar latencias, eliminar jank y de paso mejorar memoria, red y consumo de batería.
Qué es Perfetto y por qué es tan útil para latencia y jank
perfetto es una herramienta de trazas de rendimiento integrada en Android que se invoca normalmente desde el ordenador mediante Android Debug Bridge (ADB) con comandos del estilo adb shell perfetto .... Su misión es recolectar información de bajo nivel sobre lo que está ocurriendo en el dispositivo: actividades del kernel, anotaciones de usuario, uso de memoria, estadísticas de procesos, etc., todo ello en un formato de traza que luego puedes analizar con visores como la web de perfetto.dev.
Perfetto se alimenta de varias “fuentes de datos” especializadas, entre las que destacan:
ftrace, que captura eventos del kernel (planificación de hilos, sistema de archivos, etc.).atrace, centrado en anotaciones desde el espacio de usuario para servicios y aplicaciones.heapprofd, orientado al muestreo de uso de memoria nativa en servicios y apps.
Mediante la combinación adecuada de estas fuentes, puedes registrar exactamente la información que necesitas para perseguir problemas de latencia en la IU, fotogramas que se saltan, picos de CPU o bloqueos por E/S relacionados con el almacenamiento UFS.

Sintaxis básica de Perfetto y modos de funcionamiento
Perfetto se puede usar en dos grandes modos: ligero y normal. Ambos se llaman desde ADB, pero cambian mucho la forma de configurar qué se traza y cómo se guarda.
La idea general es siempre la misma: ejecutar un comando adb shell perfetto indicando duración, tamaño de buffers, fuentes de datos y archivo de salida de la traza. El fichero resultante se genera normalmente siguiendo el formato de protocolo trace.proto del AOSP, que después puedes abrir en las herramientas de análisis de Perfetto.
Opciones generales al invocar Perfetto
Independientemente del modo (ligero o normal), hay una serie de banderas comunes que controlan cómo se ejecuta la captura, qué se hace con el archivo generado y cómo se integra con sistemas de alerta o subida remota:
--backgroundo-d: hace queperfettosalga de la interfaz de línea de comandos y continúe grabando en segundo plano.--background-waito-D: similar a la anterior, pero espera hasta 30 segundos a que todas las fuentes de datos confirmen que han arrancado. El código de salida será 0 si todo va bien y distinto de 0 si hay error o timeout.--alert-id,--config-id,--config-uidy--subscription-id: identificadores que enlazan la traza con alertas o configuraciones de disparo definidas en el sistema, útiles en escenarios de monitorización automatizada.--out OUT_FILEo-o OUT_FILE: ruta completa donde se guardará el fichero de traza, o-si prefieres que vaya astdout. Generalmente se usa un directorio como/data/misc/perfetto-traces.--upload: al finalizar la captura, entrega el archivo de traza al paquete especificado por el mensajeIncidentReportConfigen la configuración de proto.--no-guardrailsy--reset-guardrails: controlan los mecanismos de seguridad y limitación de recursos cuando se activa la subida automática (--upload), pensados para pruebas y no tanto para producción.--rsave-for-bugreport: si la captura tiene unbugreport_scoremayor que 0, guarda la traza en un archivo y muestra la ruta al terminar, de cara a adjuntarlo fácilmente en informes de errores.--queryy--query-raw: consultan el estado del servicio de trazas. La primera da una salida legible, la segunda devuelve el contenido protocodificado detracing_service_state.proto.--helpo-h: imprime la ayuda integrada de la herramienta.
Modo ligero de Perfetto: rápido y similar a systrace
El modo ligero de Perfetto está pensado para trazas rápidas, muy parecido a cómo se usaba históricamente systrace. Permite seleccionar solo un subconjunto básico de fuentes: esencialmente atrace y ftrace, y es útil junto a apps para optimizar el rendimiento.
La sintaxis típica en modo ligero es algo así:
adb shell perfetto ... --out FILE
Entre las opciones específicas más relevantes del modo ligero encontramos:
--time TIMEo-t TIME: duración de la traza en segundos, minutos u horas. Por ejemplo,--time 1mcaptura durante un minuto. Si no se indica nada, se usan 10 segundos por defecto.--buffer SIZEo-b SIZE: tamaño del buffer circular en memoria. El valor predeterminado suele ser algo como--buffer 32mb.--size SIZEo-s SIZE: límite máximo del tamaño del fichero en disco. Si no se configura, Perfetto puede grabar solo en el buffer de memoria.--appo-a: nombre del paquete de la app Android para usar en anotaciones deatrace.
Tras estas banderas se listan “especificadores de eventos”, que determinan qué categorías o eventos se van a registrar:
ATRACE_CAT: categorías deatraceque quieres habilitar (por ejemplo,wmpara el WindowManager). Un comando típico sería:adb shell perfetto --out FILE wm.FTRACE_GROUP/FTRACE_NAME: eventos concretos deftrace, comosched/sched_switch. Podrías ejecutar:adb shell perfetto --out FILE sched/sched_switch.
Modo normal de Perfetto: máximo control y más fuentes
El modo normal de Perfetto es mucho más potente y configurable. En lugar de pasar categorías sueltas, se le entrega un archivo de configuración (un proto) que describe en detalle qué fuentes de datos activar, cómo muestrear, qué buffers usar, etc.
La sintaxis habitual para el modo normal es:
adb shell perfetto --config CONFIG_FILE --out FILE
Las banderas específicas clave en este modo son:
--config CONFIG_FILEo-c CONFIG_FILE: ruta al archivo de configuración que sigue el esquema detrace_config.protoen AOSP. Dentro de este proto se usan elementos comoTraceConfigyDataSourceConfig(definido endata_source_config.proto) para seleccionar y parametrizar las fuentes de datos.--txt: indica que el fichero de configuración está en formato de textopbtxten lugar de binario. Muy cómodo para prototipar localmente, pero no se recomienda como formato definitivo en producción.
Fuentes de datos compatibles con Perfetto
La verdadera fuerza de Perfetto está en las distintas fuentes que puede habilitar. Cada una se configura desde el proto a través de un bloque de DataSourceConfig, y según el dispositivo, la versión de Android y el kernel, tendrás más o menos opciones disponibles.

Eventos de kernel con ftrace
La fuente ftrace permite a Perfetto capturar eventos internos del kernel, lo cual es oro puro cuando quieres entender por qué un hilo no se está planificando a tiempo o qué está bloqueando la CPU en un momento dado.
Para activar ftrace desde la configuración hay que definir el campo ftrace_config dentro de DataSourceConfig, seleccionando qué eventos específicos queremos rastrear. Algunos ejemplos habituales relacionados con programación de procesos son:
sched/sched_switchsched/sched_wakeupsched/sched_wakeup_newsched/sched_process_execsched/sched_process_exitsched/sched_process_forksched/sched_process_freesched/sched_process_hangsched/sched_process_wait
También se pueden habilitar eventos del sistema de archivos y anotaciones de atrace, de forma que una misma traza recoja tanto la parte de kernel como eventos de más alto nivel. La lista de eventos reales dependerá siempre del dispositivo y su kernel, así que conviene consultar los protocolos de configuración correspondientes.
Estadísticas de procesos y sistema
Otra fuente muy práctica es la de estadísticas de procesos y del propio sistema. Permite obtener contadores periódicos del uso de recursos tanto globales como por proceso individual, ideal para correlacionar picos de CPU o memoria con momentos concretos de jank y con aplicaciones en segundo plano.
Para utilizarla hay que configurar los campos process_stats_config y sys_stats_config dentro de DataSourceConfig. Los datos que se obtienen incluyen, entre otros, información de tiempo de CPU, uso de memoria, y más métricas que pueden variar según el dispositivo y la versión del sistema operativo.
Perfiles de memoria nativa con heapprofd
heapprofd es la pieza clave cuando necesitas entender el uso de memoria nativa de tu aplicación o servicios del sistema. Funciona mediante muestreo, generando perfiles que indican qué partes del código están reservando memoria.
Para encender heapprofd en una traza de Perfetto hay que rellenar el apartado heapprofd_config de DataSourceConfig. El resultado son ProfilePackets con la información de pilas de llamadas, incluyendo marcos Java cuando están disponibles. Es una manera potente de cazar fugas nativas o patrones de asignación ineficientes.
La documentación pública en perfetto.dev profundiza en cómo configurar estos perfiles, filtrar por procesos concretos, ajustar la frecuencia de muestreo, etc., lo que te permite adaptar el coste de la instrumentación al nivel de detalle que necesitas.
Otras fuentes de datos adicionales
Además de las anteriores, hay más fuentes disponibles dependiendo del dispositivo y la versión de Android. Algunas están orientadas a energía, otras a red o a métricas más específicas del framework. Para verlas en detalle hay que revisar los distintos esquemas de configuración de las data sources de Perfetto publicados en AOSP.
En cualquier caso, el patrón se repite siempre: eliges la fuente, configuras su bloque DataSourceConfig en el proto de TraceConfig y lanzas la traza con perfetto. Después, analizas el archivo resultante con las herramientas de visualización.
dumpsys: el complemento perfecto para medir latencias y rendimiento
Aunque Perfetto es la estrella para trazas de bajo nivel, la herramienta veterana dumpsys sigue siendo imprescindible cuando quieres diagnósticos de alto nivel, agrupados por servicio del sistema: entrada, gráfico, red, batería, memoria, etc.
dumpsys se ejecuta en el dispositivo Android y se invoca desde ADB con comandos como adb shell dumpsys. Si lo ejecutas sin parámetros, vuelca información de todos los servicios del sistema, algo que suele ser excesivo. Lo normal es especificar el servicio concreto que te interesa para centrarse solo en esa parte.
Sintaxis general del comando dumpsys
La forma genérica de llamar a dumpsys es:
adb shell dumpsys | -c | -h]
Algunos usos comunes serían:
adb shell dumpsys: vuelca todos los servicios (muy verboso).adb shell dumpsys input: estado del sistema de entrada (teclados, pantallas táctiles, etc.).adb shell dumpsys -l: lista todos los servicios disponibles.
Entre las opciones de línea de comandos principales destacan:
-t timeout: tiempo máximo en segundos que se le da adumpsyspara completar la operación (por defecto, 10s).--help: ayuda de la herramienta genérica.-l: listado de servicios del sistema.--skip services: indica uno o varios servicios que quieres excluir de la salida cuando no especifiques ninguno concreto.service: servicio concreto que quieres inspeccionar, con argumentos opcionales. Si dudas, muchos servicios aceptan-hpara mostrar su propia ayuda, por ejemploadb shell dumpsys procstats -h.-c: hace que ciertos servicios devuelvan datos en un formato más apto para consumo por scripts o herramientas.-h: en algunos servicios, imprime ayuda adicional específica.
Diagnósticos de entrada: toques, teclados y latencias de eventos
Para problemas de latencia relacionados con la entrada táctil o de teclado, el servicio clave es input. Con adb shell dumpsys input obtienes un volcado del estado de los dispositivos de entrada y del flujo de eventos desde que se generan hasta que llegan a las ventanas.
La salida incluye tres bloques lógicos importantes: el estado del Event Hub, el estado de InputReader y el estado de InputDispatcher. Cada uno te ayuda a detectar fallos en una parte del recorrido del evento.
Event Hub: dispositivos disponibles y su configuración
El “Event Hub State” lista todos los dispositivos de entrada que el sistema conoce, con información como la ruta de dispositivo, la clase, los ficheros de keylayout, keychars y configuración, además del identificador de teclado integrado (BuiltInKeyboardId).
Al revisar esta sección conviene comprobar:
- Que todos los dispositivos físicos esperados aparecen correctamente listados.
- Que cada uno tiene asignado su archivo de diseño de teclas, mapa de caracteres y fichero de configuración; si faltan o tienen errores de sintaxis, no se cargarán y la experiencia de entrada se resentirá.
- Que el campo
Classestenga los bits adecuados, mapeados a constantes comoINPUT_DEVICE_CLASS_TOUCH_MTenEventHub.h. - Que
BuiltInKeyboardIdsea-2cuando no hay teclado integrado, o coincida con el ID del teclado interno en caso contrario. Si ves que no es-2y debería serlo, probablemente falte un mapa de caracteres especial para algún teclado de funciones, que debería contener solotype SPECIAL_FUNCTION.
InputReader: cómo se interpretan los eventos de entrada
InputReader se encarga de “traducir” los eventos de bajo nivel del kernel a algo que el framework pueda entender: coordenadas táctiles, presión, tamaño de toque, etc. En su volcado verás la configuración detallada de cada dispositivo (por ejemplo, una pantalla táctil concreta) y las últimas acciones realizadas.
En el caso de pantallas táctiles es crucial revisar:
- Los rangos de X e Y (mínimos, máximos, precisión, tolerancias).
- Los parámetros de calibración (escalas de tamaño, presión, orientación, etc.).
- El tamaño de la superficie (anchura y altura en píxeles).
- Los factores de traducción y escalado, que determinan cómo se mapean las coordenadas crudas al espacio de pantalla.
Al final de esta sección también se listan parámetros globales como el intervalo de toques, los umbrales de velocidad del puntero o las configuraciones de gestos (tiempo de doble toque, distancia mínima, etc.), que afectan de forma directa a la sensación de fluidez.
InputDispatcher: envío de eventos a ventanas y ANR
InputDispatcher maneja el envío de los eventos de entrada a las distintas ventanas. Su estado muestra qué ventana está enfocada, cuáles son táctiles, cómo están las colas de entrada y si hay algún ANR (Application Not Responding) en curso.
En la práctica, esta sección permite comprobar:
- Qué ventana estaba recibiendo los toques en el momento de hacer el
dumpsys. - Si hay eventos pendientes o colas bloqueadas que puedan estar aumentando la latencia percibida.
- Cómo se distribuyen las conexiones de entrada entre distintas ventanas y si alguna está saturando su cola.
Una comprobación sencilla pero muy reveladora es tocar la pantalla, lanzar inmediatamente adb shell dumpsys input y ver si la línea de TouchStates identifica correctamente la ventana que has tocado. Si no es así, hay algo raro en la gestión de foco o en el mapeo de regiones táctiles.
Medición de rendimiento de la IU con gfxinfo y framestats
Cuando la preocupación principal es el jank en animaciones y scroll, el servicio gfxinfo es tu amigo. A través de dumpsys gfxinfo puedes obtener datos sobre los fotogramas renderizados para una app concreta.
El comando básico para una app concreta es:
adb shell dumpsys gfxinfo package-name
Si añades la opción framestats, el diagnóstico se vuelve todavía más detallado:
adb shell dumpsys gfxinfo package-name framestats
Con esto obtendrás estadísticas de latencia fotograma a fotograma de las animaciones recientes, lo que ayuda mucho a localizar transiciones o pantallas concretas donde se dispara el tiempo de renderizado. Esta información se puede integrar en pruebas automatizadas o macrobenchmarks para vigilar regresiones entre versiones de la app.
Diagnósticos de red con dumpsys netstats
Para entender si la latencia de la IU está relacionada con red lenta o picos de tráfico, el servicio netstats resulta muy útil. Recoge estadísticas de uso de red desde que el dispositivo arrancó.
El comando típico con más detalle es:
adb shell dumpsys netstats detail
La salida se organiza en varias secciones:
- Interfaces activas e interfaces UID activas, donde suelen coincidir nombres como
wlan0y su identificador de red. - Estadísticas “Dev” y “Xt”, que muestran históricos con bucket de tiempo (por ejemplo, en tramos de una hora) y campos como bytes recibidos (
rb), paquetes recibidos (rp), bytes transmitidos (tb), etc. - Estadísticas por UID, donde puedes desglosar el consumo de red de una app concreta, diferenciando móvil y Wi‑Fi.
Para localizar el UID de tu app, se usa algo como:
adb shell dumpsys package your-package-name | grep userId
Una vez sepas el valor de userId, puedes buscar en la salida de netstats las líneas con uid=ese_valor y ver, por ejemplo, cuántos bytes y paquetes ha usado en cada periodo de dos horas, y si estaba en primer plano (set=DEFAULT) o en segundo plano (set=BACKGROUND).
Uso de batería y energía con batterystats
La latencia y el jank no solo se arreglan con más rendimiento; a veces conviene mirar también cómo afectan las optimizaciones al consumo energético. dumpsys batterystats da un informe muy amplio sobre uso de batería por UID y por componente.
El comando base para este servicio es:
adb shell dumpsys batterystats options
Si quieres centrarte en una app concreta desde la última carga, se utiliza:
adb shell dumpsys batterystats --charged package-name
La salida habitual incluye:
- Historial de eventos relacionados con la batería.
- Estadísticas globales del dispositivo.
- Estimaciones de uso energético por UID y por componentes del sistema.
- Tiempo de uso de red móvil por app y paquete.
- Estadísticas globales de UID del sistema y de apps.
Formato checkin (CSV) para análisis automatizado
Si necesitas procesar los datos de batería con scripts o herramientas externas, puedes generar una salida “para máquinas” con:
adb shell dumpsys batterystats --checkin
Este formato presenta cada observación en una línea CSV, con un identificador de sección que determina cómo interpretar el resto de campos. Algunos ejemplos de secciones son:
vers: versiones de checkin, parcel y plataforma.uid: relación UID – nombre de paquete.apk,pr,sr,vib,fg, etc.: uso de procesos, sensores, vibrador, tiempo en primer plano, sincronizaciones, jobs, etc.ntygn: estadísticas de red (bytes y paquetes móviles/Wi‑Fi, tiempos activos, etc.).bt,dc,lv: datos de batería como tiempos, niveles y descargas.wfl,gwfl,gble: información específica de Wi‑Fi y Bluetooth, incluyendo tiempos y consumo estimado en mAh.
En versiones recientes de Android (6.0 en adelante), el uso de energía de Wi‑Fi, radio móvil y Bluetooth se reporta como elementos pwi con etiquetas dedicadas (wifi, blue, cell), mientras que en versiones antiguas se agrupaba en la sección m (miscelánea).
Inspección de memoria a lo largo del tiempo con procstats
Si sospechas que el jank viene de fugas de memoria o de apps pesadas en segundo plano, dumpsys procstats te permite ver cómo se comporta tu aplicación a lo largo del tiempo: cuánto ha estado activa, en qué estado y con qué consumo de memoria.
Un uso típico es pedir estadísticas de las últimas horas, por ejemplo:
adb shell dumpsys procstats --hours 3
La salida resume para cada app el porcentaje de tiempo que ha estado viva, junto con valores de PSS, USS y RSS en forma de mínimo, promedio y máximo, junto con el número de muestras tomadas. También muestra un resumen de memoria por tipo de proceso (kernel, nativo, persistente, top, servicios, procesos en caché, etc.).
Esta visión agregada ayuda a detectar patrones como aplicaciones que permanecen demasiado tiempo en estados en segundo plano, o que mantienen un PSS medio o máximo muy elevado, posibles candidatas a optimización o incluso a estar causando presión de memoria que degrada el rendimiento del sistema.
Instantánea detallada de memoria con meminfo
Cuando necesitas una foto fija muy granular del uso de memoria de un proceso concreto, la herramienta es dumpsys meminfo. Con ella puedes ver cómo se reparte la RAM entre montones nativos, Dalvik/ART, mapas de código, buffers gráficos, etc.
La sintaxis básica es:
adb shell dumpsys meminfo package_name|pid
La opción -d amplía la información para Dalvik/ART, mostrando detalles internos como el espacio de objetos grandes (.LOS), sobrecarga del GC, caché del JIT, espacio de Zygote, etc. Con -h puedes ver todas las banderas disponibles.
Las columnas clave a observar suelen ser Pss Total y Private Dirty, que reflejan respectivamente el uso de RAM ajustado por compartición y la cantidad de memoria privada modificada que se liberará solo al destruir el proceso. En ocasiones también son interesantes Private Clean y Heap Alloc. Si detectas consumos anómalos, revisa cómo liberar memoria RAM para mitigarlos.
Algunas categorías relevantes en la tabla:
Native HeapyDalvik Heap: uso de memoria de montones nativo y de la VM.Heap Allocmuestra lo que los asignadores creen reservado, que puede ser superior a PSS por el efecto de Zygote y memoria compartida..so mmap,.dex mmap,.oat mmapy.art mmap: RAM usada por código nativo y bytecode, incluidas las imágenes de ART y sus espacios compartidos..Heap,.LOS,.GC,.JITCache,.Zygote,.NonMoving,.IndirectRef(con-d): desglosan aún más el uso interno de la memoria gestionada por ART.Unknown: páginas que no se pudieron clasificar en categorías anteriores, a menudo asignaciones nativas vistas a través de ASLR.
La línea TOTAL agrupa el PSS total del proceso, que se puede comparar con el PSS de otros procesos y con la RAM disponible. Private Dirty + Private Clean indican la memoria que se liberará al matar el proceso.
Además, al final del informe se listan contadores de objetos de alto nivel como número de ViewRootImpl, AppContexts o Activities, lo que ayuda a detectar fugas típicas de contextos o actividades retenidas por referencias estáticas o por vistas/drawables que siguen apuntando a ellas.
Conviene recordar que una View o un Drawable también mantienen referencia a la Activity de la que salen, así que conservarlos de forma indebida puede implicar fugas de toda la actividad y sus recursos asociados.
Combinando las trazas detalladas de Perfetto con los diagnósticos de dumpsys (entrada, gráficos, memoria, red y batería) se consigue una visión de 360 grados sobre cómo se comporta una app Android: desde cuándo se programa un hilo hasta cuántos milisegundos tarda en pintar un frame o cuánta memoria y energía consume de más. Usar estas herramientas de forma habitual en el desarrollo y las pruebas marca la diferencia entre una app que “más o menos funciona” y otra que se percibe realmente fluida, estable y eficiente incluso en dispositivos modestos al optimizar Android.
