← Volver al listado de tecnologías

Capítulo 2: Conceptos Básicos y Arquitectura de ADB

Por: Artiko
adbarquitecturadaemonadbdservidorclienteprotocolousbwifi

Capítulo 2: Conceptos Básicos y Arquitectura de ADB

Este capítulo explora en profundidad cómo funciona ADB internamente, su arquitectura de tres componentes, los protocolos de comunicación y los diferentes modos de conexión disponibles.

🎯 Objetivos del Capítulo

Al finalizar este capítulo comprenderás:

🏗️ Arquitectura de ADB

Los Tres Componentes

1. Cliente ADB:
   - Ubicación: Tu computadora
   - Función: Interfaz de línea de comandos
   - Puerto: Se conecta al servidor en 5037
   - Ejemplos: adb shell, adb install, adb push

2. Servidor ADB (adb server):
   - Ubicación: Tu computadora (proceso en background)
   - Función: Gestiona comunicación cliente-dispositivo
   - Puerto: Escucha en TCP 5037
   - Proceso: adb.exe (Windows) o adb (Unix)

3. Daemon ADB (adbd):
   - Ubicación: Dispositivo Android
   - Función: Ejecuta comandos en el dispositivo
   - Puerto: 5555 (WiFi) o USB
   - Proceso: /system/bin/adbd

Diagrama de Comunicación

┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│   Cliente   │      │   Servidor  │      │   Daemon    │
│     ADB     │◄────►│     ADB     │◄────►│    (adbd)   │
│   (CLI)     │ TCP  │  (PC:5037)  │ USB/ │  (Android)  │
└─────────────┘      └─────────────┘ WiFi └─────────────┘
     Tu PC               Tu PC            Tu Dispositivo

Flujo de Comunicación Detallado

// Cuando ejecutas: adb shell ls /sdcard

// 1. Cliente verifica servidor
client.checkServer() {
  try {
    connect("localhost:5037")
  } catch {
    startServer()  // Auto-inicia si no está corriendo
  }
}

// 2. Cliente envía comando al servidor
client.sendCommand("host:transport-usb")
client.sendCommand("shell:ls /sdcard")

// 3. Servidor reenvía al daemon
server.forwardToDevice(deviceId, "shell:ls /sdcard")

// 4. Daemon ejecuta en dispositivo
adbd.execute("ls /sdcard")

// 5. Respuesta viaja de vuelta
adbd → server → client → pantalla

🖥️ El Servidor ADB

Ciclo de Vida del Servidor

# Estado inicial: servidor no está corriendo
$ adb devices
* daemon not running; starting now at tcp:5037
* daemon started successfully

# El servidor ahora está escuchando
$ netstat -an | grep 5037
tcp  0  0  127.0.0.1:5037  0.0.0.0:*  LISTEN

# Verificar proceso
$ ps aux | grep adb
user  12345  0.0  0.1  adb fork-server server

# Detener servidor manualmente
$ adb kill-server

# El servidor se auto-inicia cuando es necesario
$ adb devices  # Auto-inicia el servidor

Configuración del Servidor

# Puerto personalizado
export ADB_SERVER_PORT=5038
adb -P 5038 start-server

# Configuración de timeout
export ADB_TRACE=all  # Debug completo
export ADB_VENDOR_KEYS=$HOME/.android  # Claves vendor

# Archivo de configuración global
# ~/.android/adb_usb.ini
# Contiene Vendor IDs adicionales
0x2717  # Xiaomi
0x2a70  # OnePlus

Gestión de Múltiples Dispositivos

# Cómo el servidor maneja múltiples dispositivos
class ADBServer:
    def __init__(self):
        self.devices = {}  # {serial: connection}
        self.port = 5037
    
    def handle_client_request(self, request):
        if request.startswith("host:"):
            # Comandos del servidor
            return self.handle_host_command(request)
        elif request.startswith("host-serial:"):
            # Comando para dispositivo específico
            serial = self.extract_serial(request)
            return self.forward_to_device(serial, request)
        elif request.startswith("host:transport"):
            # Seleccionar dispositivo para comandos siguientes
            self.select_device(request)

📱 El Daemon (adbd)

Ubicación y Permisos

# Ubicación del daemon
$ adb shell ls -la /system/bin/adbd
-rwxr-xr-x 1 root shell 334408 2024-01-01 00:00 /system/bin/adbd

# Proceso en ejecución
$ adb shell ps | grep adbd
shell    1234  1  19264  1620  poll_schedule_timeout  S  adbd

# Propiedades relacionadas
$ adb shell getprop | grep adb
[init.svc.adbd]: [running]
[persist.adb.tcp.port]: [5555]
[ro.adb.secure]: [1]  # ADB seguro habilitado
[sys.usb.config]: [adb]
[sys.usb.state]: [adb]

Modos de Operación del Daemon

USB Mode (Por defecto):
  - Conexión: Cable USB
  - Configuración: sys.usb.config=adb
  - Seguridad: Requiere autorización RSA
  - Velocidad: Más rápida y estable

TCP/IP Mode (WiFi):
  - Conexión: Red WiFi
  - Puerto: 5555 (configurable)
  - Comando: adb tcpip 5555
  - Seguridad: Menos segura (sin cable físico)

Root Mode:
  - Solo en builds userdebug/eng
  - Comando: adb root
  - Reinicia adbd como root
  - Acceso completo al sistema

Control del Daemon

# Reiniciar daemon en el dispositivo
$ adb shell "stop adbd && start adbd"

# Cambiar a modo TCP/IP
$ adb shell setprop service.adb.tcp.port 5555
$ adb shell "stop adbd && start adbd"

# Verificar estado
$ adb shell getprop init.svc.adbd
running

# Ver logs del daemon
$ adb shell logcat -s adbd

🔐 Autenticación RSA

Proceso de Autorización

# Flujo de autenticación RSA
def authenticate_device():
    # 1. Cliente genera par de claves RSA (si no existe)
    if not exists("~/.android/adbkey"):
        generate_rsa_keypair()
    
    # 2. Servidor envía clave pública al dispositivo
    public_key = read_file("~/.android/adbkey.pub")
    send_to_device("AUTH", public_key)
    
    # 3. Dispositivo muestra prompt al usuario
    # "¿Permitir depuración USB?"
    # "Huella digital RSA: XX:XX:XX:XX..."
    
    # 4. Usuario acepta
    if user_accepts():
        # Clave se guarda en dispositivo
        save_to_file("/data/misc/adb/adb_keys", public_key)
        return "authorized"
    else:
        return "unauthorized"

Ubicación de Claves

# En tu computadora
~/.android/adbkey      # Clave privada
~/.android/adbkey.pub  # Clave pública

# En Windows
%USERPROFILE%\.android\adbkey
%USERPROFILE%\.android\adbkey.pub

# En el dispositivo Android
/data/misc/adb/adb_keys  # Claves autorizadas

# Ver claves autorizadas en dispositivo (requiere root)
$ adb shell su -c "cat /data/misc/adb/adb_keys"

# Revocar todas las autorizaciones
# Ajustes → Opciones de desarrollador → Revocar autorizaciones USB

🔌 Modos de Conexión

Conexión USB

// Configuración USB
const usbConfig = {
  mode: "MTP",  // Media Transfer Protocol
  speed: "USB 3.0",  // Hasta 5 Gbps
  power: "500mA",  // Alimentación estándar
  
  advantages: [
    "Más rápida y estable",
    "Conexión segura (cable físico)",
    "No requiere red",
    "Carga el dispositivo"
  ],
  
  disadvantages: [
    "Requiere cable",
    "Limitado por longitud del cable",
    "Un dispositivo por puerto USB"
  ]
};

// Detección USB
$ lsusb | grep -i android
Bus 001 Device 004: ID 18d1:4ee7 Google Inc. Nexus/Pixel Device

// Verificar conexión USB
$ adb shell getprop sys.usb.state
adb

Conexión WiFi

# Configuración inicial (requiere USB primero)
# 1. Conectar por USB
$ adb devices

# 2. Habilitar TCP/IP
$ adb tcpip 5555
restarting in TCP mode port: 5555

# 3. Obtener IP del dispositivo
$ adb shell ip addr show wlan0
inet 192.168.1.100/24 brd 192.168.1.255

# 4. Conectar por WiFi
$ adb connect 192.168.1.100:5555
connected to 192.168.1.100:5555

# 5. Desconectar USB (opcional)
# Ya puedes trabajar sin cables

# Verificar conexión
$ adb devices
192.168.1.100:5555  device

# Configuración persistente (requiere root)
$ adb shell su -c "setprop persist.adb.tcp.port 5555"

Conexión Ethernet

# Para dispositivos con puerto Ethernet o adaptador USB-Ethernet
# Similar a WiFi pero más estable

# 1. Obtener IP Ethernet
$ adb shell ip addr show eth0
inet 192.168.1.200/24

# 2. Habilitar TCP/IP
$ adb tcpip 5555

# 3. Conectar
$ adb connect 192.168.1.200:5555

# Ventajas sobre WiFi:
# - Conexión más estable
# - Mayor velocidad
# - Menor latencia
# - Ideal para CI/CD

Wireless Debugging (Android 11+)

# Android 11 introdujo Wireless Debugging nativo

# En el dispositivo:
# Ajustes → Opciones de desarrollador → Depuración inalámbrica

# Opción 1: Pairing con código
$ adb pair 192.168.1.100:37853
Enter pairing code: 123456
Successfully paired to 192.168.1.100:37853

# Opción 2: QR Code
$ adb pair --qr-code
# Escanear QR con el dispositivo

# Conectar después del pairing
$ adb connect 192.168.1.100:39875
connected to 192.168.1.100:39875

# Ventajas:
# - No requiere cable USB inicial
# - Más seguro (pairing code)
# - Integrado en Android

📊 Protocolos y Comunicación

Protocolo ADB

# Estructura de mensajes ADB
class ADBMessage:
    def __init__(self):
        self.command = 4  # bytes: CNXN, OPEN, OKAY, CLSE, WRTE
        self.arg0 = 4     # bytes: primer argumento
        self.arg1 = 4     # bytes: segundo argumento
        self.data_length = 4  # bytes: longitud de datos
        self.data_crc32 = 4   # bytes: checksum
        self.magic = 4    # bytes: command ^ 0xFFFFFFFF

# Comandos principales
COMMANDS = {
    "CNXN": 0x4e584e43,  # Conexión
    "OPEN": 0x4e45504f,  # Abrir stream
    "OKAY": 0x59414b4f,  # Confirmación
    "CLSE": 0x45534c43,  # Cerrar stream
    "WRTE": 0x45545257,  # Escribir datos
    "AUTH": 0x48545541,  # Autenticación
    "SYNC": 0x434e5953,  # Sincronización
}

Servicios Disponibles

# Servicios que el daemon puede ejecutar
shell:comando          # Ejecutar comando shell
sync:                 # Sincronización de archivos
tcp:puerto            # Reenvío de puerto TCP
local:socket          # Socket local Unix
localreserved:socket  # Socket reservado
localabstract:socket  # Socket abstracto
jdwp:pid             # Java Debug Wire Protocol
track-jdwp           # Rastrear procesos JDWP
reverse:comando      # Reenvío inverso

Port Forwarding

# Reenviar puerto local al dispositivo
$ adb forward tcp:8080 tcp:8080
# Ahora localhost:8080 → dispositivo:8080

# Reenviar a socket Unix
$ adb forward tcp:9999 localabstract:chrome_devtools_remote

# Ver reenvíos activos
$ adb forward --list
ABC123DEF456 tcp:8080 tcp:8080
ABC123DEF456 tcp:9999 localabstract:chrome_devtools_remote

# Eliminar reenvío
$ adb forward --remove tcp:8080
$ adb forward --remove-all

# Reverse forwarding (dispositivo → PC)
$ adb reverse tcp:3000 tcp:3000
# El dispositivo puede acceder a localhost:3000 del PC

🔍 Debugging de ADB

Variables de Entorno para Debug

# Activar logging completo
export ADB_TRACE=all
adb devices

# Niveles de trace específicos
export ADB_TRACE=adb,packets,rwx,usb,sync,sysdeps,transport,jdwp

# Ver comunicación USB
export ADB_TRACE=usb
adb devices

# Log a archivo
export ADB_TRACE=all
export ADB_TRACE_OUTPUT=/tmp/adb.log
adb devices
cat /tmp/adb.log

Análisis de Problemas de Conexión

#!/bin/bash
# diagnose_adb.sh

echo "🔍 Diagnóstico de ADB"
echo "===================="

# 1. Verificar servidor
echo -e "\n1. Estado del servidor:"
if pgrep -x "adb" > /dev/null; then
    echo "✅ Servidor ADB corriendo"
    echo "   PID: $(pgrep -x adb)"
else
    echo "❌ Servidor ADB no está corriendo"
fi

# 2. Verificar puerto
echo -e "\n2. Puerto 5037:"
if netstat -an | grep -q ":5037.*LISTEN"; then
    echo "✅ Puerto 5037 en uso"
else
    echo "❌ Puerto 5037 no está escuchando"
fi

# 3. Verificar USB
echo -e "\n3. Dispositivos USB:"
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
    lsusb | grep -i "android\|google" || echo "No se detectan dispositivos Android"
elif [[ "$OSTYPE" == "darwin"* ]]; then
    system_profiler SPUSBDataType | grep -i "android" || echo "No se detectan dispositivos Android"
fi

# 4. Verificar permisos
echo -e "\n4. Permisos:"
ls -la ~/.android/adbkey 2>/dev/null || echo "No se encuentra clave RSA"

# 5. Intentar conexión
echo -e "\n5. Intentando conexión:"
adb devices -l

🛡️ Seguridad en ADB

Mejores Prácticas

Desarrollo:
  - Usar solo en redes confiables
  - Deshabilitar ADB cuando no se use
  - No usar adb root en producción
  - Revisar claves autorizadas regularmente

Producción:
  - ro.adb.secure=1 (ADB seguro)
  - ro.debuggable=0 (No debuggeable)
  - Deshabilitar ADB completamente
  - USB debugging desactivado

WiFi ADB:
  - Usar solo en red privada
  - Cambiar puerto por defecto
  - Firewall en el dispositivo
  - VPN para conexiones remotas

Comandos de Seguridad

# Verificar modo seguro
$ adb shell getprop ro.adb.secure
1  # Seguro habilitado

# Ver build type
$ adb shell getprop ro.build.type
user  # user, userdebug, o eng

# Verificar debuggeable
$ adb shell getprop ro.debuggable
0  # No debuggeable

# Revocar autorizaciones
$ adb shell rm /data/misc/adb/adb_keys  # Requiere root

# Deshabilitar ADB
$ adb shell settings put global adb_enabled 0

🎯 Ejercicios Prácticos

Ejercicio 1: Explorar Arquitectura

# 1. Verificar componentes
ps aux | grep adb          # Ver servidor
adb shell ps | grep adbd   # Ver daemon

# 2. Analizar puerto
netstat -tulpn | grep 5037

# 3. Ver comunicación
export ADB_TRACE=packets
adb shell echo "test"

Ejercicio 2: Cambiar Modos de Conexión

# 1. USB → WiFi
adb tcpip 5555
adb connect [IP]:5555

# 2. WiFi → USB
adb usb

# 3. Puerto personalizado
adb tcpip 5556
adb connect [IP]:5556

Ejercicio 3: Debugging

# 1. Activar trace completo
export ADB_TRACE=all
export ADB_TRACE_OUTPUT=adb_debug.log

# 2. Ejecutar comando
adb devices

# 3. Analizar log
grep "transport" adb_debug.log
grep "usb" adb_debug.log

📚 Resumen

Has aprendido la arquitectura completa de ADB:

🚀 Próximo Paso

Con el entendimiento de la arquitectura, ahora exploraremos los comandos esenciales de ADB.

👉 Continuar con Capítulo 3: Comandos Esenciales


Tip Pro: Entender la arquitectura de ADB te ayudará a diagnosticar problemas rápidamente. Cuando algo falle, piensa en qué componente puede estar fallando: ¿cliente, servidor o daemon?