adb a fondo
El modelo cliente servidor demonio, instalar y mover archivos, logcat con filtros que sirven, y el shell para simular condiciones adversas y grabar la pantalla.
adb es la herramienta que convierte un teléfono en un objeto de estudio. Con ella dejas de observar la aplicación desde fuera y pasas a intervenir en el dispositivo: instalas, lees registros, extraes bases de datos, apagas la red, agotas la batería, vacías la memoria y grabas la consecuencia. Casi todo lo que Android Studio muestra con botones es una llamada a adb por debajo, y conocer la orden directa te da precisión, automatización y un diagnóstico que ningún panel gráfico ofrece.
- Entender el modelo de tres piezas de
adby por qué a veces hay que reiniciarlo. - Instalar, desinstalar y mover ficheros entre anfitrión y dispositivo, incluso datos privados.
- Filtrar
logcatcon precisión quirúrgica en lugar de leer un torrente. - Simular condiciones adversas desde
shelly capturar la evidencia en vídeo.
El modelo: cliente, servidor y demonio
Cada vez que escribes adb algo no hablas con el teléfono: hablas con un servidor local que se arranca solo la primera vez, escucha en el puerto 5037 y multiplexa las conexiones con todos los dispositivos. En el otro extremo, adbd corre dentro del dispositivo. Esta arquitectura explica dos comportamientos desconcertantes: que un dispositivo se quede colgado en el listado hasta que reinicias el servidor, y que dos herramientas distintas puedan compartir la misma conexión sin pisarse.
adb devices -l # modelo, producto y estado de cada uno
adb -s emulator-5554 shell # elegir destinatario por numero de serie
export ANDROID_SERIAL=RF8N20 # o fijarlo para toda la sesion
adb -d shell # el unico dispositivo USB
adb -e shell # el unico emulador
adb kill-server && adb start-server
adb wait-for-device # util en scripts antes de actuar
adb root # solo en compilaciones userdebug o emuladores sin Play
unauthorized significa que falta aceptar la huella RSA en la pantalla del teléfono. offline suele ser un demonio a medio arrancar o un cable con mal contacto. no permissions en Linux es una regla de udev ausente. Ninguno de los tres se arregla reinstalando nada.
Instalar y mover archivos
La instalación tiene más matices de los que parece, sobre todo desde que el formato de distribución dejó de ser un único archivo para pasar a ser un conjunto de fragmentos por densidad, idioma y arquitectura.
adb install -r app-debug.apk # reinstalar conservando datos
adb install -t app-debug.apk # permitir una compilacion de pruebas
adb install --user 0 app.apk # instalar en un perfil concreto
adb install-multiple base.apk split_config.arm64_v8a.apk split_config.es.apk
adb uninstall -k com.ejemplo.app # conservar datos y cache
adb shell pm clear com.ejemplo.app # borrar datos sin desinstalar
adb shell pm list packages -3 # solo las aplicaciones de terceros
adb shell pm path com.ejemplo.app # donde vive el apk instalado
adb shell pm grant com.ejemplo.app android.permission.CAMERA
adb shell pm revoke com.ejemplo.app android.permission.CAMERA
Para los ficheros hay dos direcciones y un caso especial que resuelve un problema real. adb push y adb pull mueven cualquier cosa en el almacenamiento accesible, pero el directorio privado de una aplicación no lo es. Ahí entra run-as, que ejecuta una orden con la identidad de un paquete depurable:
adb push datos.json /sdcard/Download/
adb pull /sdcard/Download/informe.csv .
# extraer la base de datos privada de una app depurable sin corromperla
adb exec-out run-as com.ejemplo.app cat databases/app.db > app.db
adb shell run-as com.ejemplo.app ls -l databases/
La diferencia entre shell y exec-out es la que separa un fichero binario intacto de uno corrupto: shell abre un pseudoterminal que traduce saltos de línea, y exec-out entrega el flujo crudo. Para cualquier cosa que no sea texto, exec-out es obligatorio.
logcat con filtros que sirven
Leer logcat sin filtrar es leer el registro de todo el sistema operativo. La productividad depende por completo de aprender a acotar. La forma clásica combina pares de etiqueta y prioridad, terminando con *:S para silenciar el resto.
adb logcat -v threadtime # formato recomendado: pid, tid, hora
adb logcat MiTag:D OtraTag:W "*:S" # solo dos etiquetas, silencio el resto
adb logcat --pid=$(adb shell pidof -s com.ejemplo.app) # solo mi proceso
adb logcat -e "timeout|retry" # filtrar por expresion regular
adb logcat -b crash -d # volcar el buffer de fallos y salir
adb logcat -b main,system,events -t 200 # ultimas 200 lineas de tres buffers
adb logcat -c # limpiar antes de reproducir un fallo
adb logcat -G 16M # ampliar el buffer circular
Los buffers son anillos de tamaño fijo: cuando se llenan, lo antiguo se pierde. Por eso la secuencia correcta para investigar un fallo es siempre limpiar, reproducir y volcar, no al revés. El buffer crash merece atención propia porque conserva las excepciones no capturadas aunque el proceso haya muerto, y el buffer events registra transiciones del sistema —arranques de actividad, muertes de proceso, decisiones del gestor de tareas— que son justamente lo que necesitas cuando el problema no está en tu código sino en cómo el sistema trata a tu aplicación.
shell: simular condiciones y grabar
Aquí es donde adb deja de ser un cable y se convierte en un laboratorio. Todo lo que sigue son experimentos reproducibles sobre un sistema vivo.
# ciclo de vida y arranque en frio, sin tocar el telefono
adb shell am force-stop com.ejemplo.app
adb shell am start -n com.ejemplo.app/.MainActivity
adb shell am start -a android.intent.action.VIEW -d "app://ruta/42"
# red: quitarla y devolverla
adb shell svc wifi disable
adb shell svc data disable
# bateria y ahorro de energia
adb shell dumpsys battery unplug
adb shell dumpsys battery set level 5
adb shell dumpsys battery reset
# doze y trabajo en segundo plano
adb shell dumpsys deviceidle force-idle
adb shell dumpsys deviceidle unforce
# presion de memoria y muerte del proceso
adb shell am send-trim-memory com.ejemplo.app RUNNING_CRITICAL
adb shell am kill com.ejemplo.app
# animaciones y entrada sintetica
adb shell settings put global window_animation_scale 0
adb shell input tap 540 1200
adb shell input text "hola"
adb shell monkey -p com.ejemplo.app -v 500
# evidencia
adb exec-out screencap -p > captura.png
adb shell screenrecord --time-limit 30 --size 720x1280 /sdcard/v.mp4
adb pull /sdcard/v.mp4 .
flowchart LR A[Sintoma reportado] --> B[adb logcat -c] B --> C[Reproducir con am start o input] C --> D[adb logcat -b crash,main -d] D --> E[Aislar el proceso con pidof] E --> F[Extraer estado con run-as y exec-out] F --> G[Grabar con screenrecord como evidencia] style A fill:#f38ba8,color:#11111b style G fill:#a6e3a1,color:#11111b
La frase más cara del desarrollo Android es “no he podido reproducirlo”. Casi siempre es falsa: lo que ocurre es que el error depende de una condición que en la mesa del desarrollador nunca se da —la red se cayó a mitad de una petición, el sistema mató el proceso mientras el usuario estaba en otra aplicación, la batería entró en ahorro de energía y difirió el trabajo programado, la memoria se agotó y el sistema recicló la actividad— y esas condiciones no aparecen esperando a que aparezcan. Hay que provocarlas. Ese es el salto conceptual que cambia la práctica: dejas de ser un observador que espera que el fallo se manifieste y pasas a ser un experimentador que construye la situación exacta donde la hipótesis se pone a prueba. Cada orden de la sección anterior es una variable que puedes manipular de forma independiente y repetible, y esa repetibilidad es lo que convierte un fallo esporádico en un fallo determinista, que es la única clase de fallo que se puede arreglar con confianza. El beneficio secundario es aún mayor: todo lo que puedes provocar desde una línea de órdenes lo puedes escribir en un script, y todo lo que está en un script puede ejecutarse en integración continua antes de cada fusión. Así es como una técnica de depuración manual se convierte en una red de seguridad automática. La disciplina que hay detrás es antigua y no es de Android: aislar la variable, provocar la condición, observar el resultado, registrar la evidencia. adb es simplemente el instrumento que te permite aplicarla a un dispositivo del que, por lo demás, no controlas casi nada.
- Limpia el buffer, arranca tu aplicación con
am start, y captura solo las líneas de tu proceso usandopidof. Guarda la sesión en un fichero. - Extrae la base de datos privada de una compilación de depuración con
exec-out run-asy ábrela en tu ordenador. Repite conshelly comprueba que se corrompe. - Simula la pérdida de red en mitad de una carga de datos y documenta qué ve el usuario. Arregla lo que encuentres.
- Fuerza
deviceidley comprueba si tu trabajo programado sobrevive. Después mata el proceso conam killy verifica la restauración de estado. - Escribe un script que instale, conceda permisos, lance una pantalla concreta, ejecute una secuencia de
inputy grabe el resultado en vídeo. - Reduce el buffer con
-Ga un tamaño pequeño, reproduce un fallo largo y observa cómo se pierde la evidencia. Extrae la lección.