Redroid

Guía Completa: Implementación de Redroid en ARM64 Debian 12 con Kernel Android Personalizado

📋 Resumen Ejecutivo

Esta guía documenta el proceso completo para implementar Redroid (Android containerizado) en un servidor ARM64 Debian 12, incluyendo la compilación de un kernel personalizado con soporte Android nativo. La solución elimina la dependencia de módulos DKMS problemáticos mediante la integración directa de binderfs en el kernel.

Hardware probado: VPS ARM64 Netcup con 24GB RAM, 12 cores Ampere Altra
SO: Debian GNU/Linux 12 (bookworm)
Kernel objetivo: Linux 6.1.0 con soporte Android nativo
Resultado: Redroid funcionando establemente con múltiples contenedores


🔍 Análisis del Problema Inicial

Incompatibilidad Fundamental

Los contenedores Redroid están diseñados para kernels con soporte Android, pero Debian 12 no incluye estas características por defecto:

  • CONFIG_ANDROID_BINDER_IPC: Deshabilitado
  • CONFIG_ANDROID_BINDERFS: Deshabilitado
  • Módulos redroid-modules: Incompatibles con kernel 6.1 moderno

Síntomas Identificados

# Error típico al intentar usar módulos DKMS
/root/redroid-modules/ashmem/ashmem.c:950:15: error: too few arguments to function 'register_shrinker'
/root/redroid-modules/binder/binderfs.c:375:30: error: passing argument 1 of 'simple_rename'

Decisión Arquitectural

Estrategia elegida: Recompilación del kernel 6.1 con soporte Android nativo
Alternativas descartadas: Módulos DKMS (incompatibles), kernel 5.8 (obsoleto)


🛠️ Proceso de Implementación

Fase 1: Preparación del Entorno

Instalación de Dependencias

#!/bin/bash
# Dependencias completas para compilación de kernel
sudo apt update && sudo apt upgrade -y

# Paquetes esenciales
sudo apt install -y \
    build-essential \
    libncurses-dev \
    libssl-dev \
    flex \
    bison \
    bc \
    kmod \
    cpio \
    libelf-dev \
    pkg-config \
    rsync \
    git \
    wget \
    xz-utils \
    dwarves \
    zstd \
    pahole

Verificación de Recursos

# Verificar espacio disponible (mínimo 15GB)
df -h /usr/src

# Verificar memoria (recomendado 8GB+)
free -h

# Verificar cores disponibles
nproc

Fase 2: Descarga y Configuración del Kernel

Obtención del Código Fuente

cd /usr/src
sudo wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.tar.xz
sudo tar -xf linux-6.1.tar.xz
cd linux-6.1

Configuración Base

# Copiar configuración del kernel actual (enfoque conservador)
sudo cp /boot/config-$(uname -r) .config

# Verificar configuración copiada
grep -E "CONFIG_NAMESPACES|CONFIG_CGROUPS" .config

Habilitación de Soporte Android

# Método automático con scripts/config
sudo ./scripts/config --enable CONFIG_ANDROID_BINDER_IPC
sudo ./scripts/config --enable CONFIG_ANDROID_BINDERFS
sudo ./scripts/config --set-str CONFIG_ANDROID_BINDER_DEVICES "binder,hwbinder,vndbinder"

# Resolver dependencias automáticamente
sudo make olddefconfig

Verificación de Configuración

# Confirmar configuraciones Android
grep -E "CONFIG_ANDROID" .config

# Resultado esperado:
# CONFIG_ANDROID_BINDER_IPC=y
# CONFIG_ANDROID_BINDERFS=y
# CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"

Fase 3: Compilación del Kernel

# Compilación con optimización de cores
sudo make -j$(nproc) bindeb-pkg LOCALVERSION=-android 2>&1 | tee /tmp/kernel-compile.log

# Tiempo estimado: 1-3 horas en ARM64
# Archivos generados en /usr/src/:
# - linux-image-6.1.0-android_6.1.0-android-1_arm64.deb
# - linux-headers-6.1.0-android_6.1.0-android-1_arm64.deb
# - linux-image-6.1.0-android-dbg_6.1.0-android-1_arm64.deb
# - linux-libc-dev_6.1.0-android-1_arm64.deb

Fase 4: Instalación del Kernel

# Instalación de paquetes generados
cd /usr/src
sudo dpkg -i linux-*.deb

# Notas sobre warnings DKMS:
# - Los errores de redroid-ashmem y redroid-binder son ESPERADOS
# - Son módulos obsoletos que ya no necesitamos
# - El kernel nuevo tiene soporte Android nativo

# Actualización automática de GRUB
sudo update-grub

Limpieza de Módulos DKMS Obsoletos

# Remover módulos DKMS problemáticos
sudo dkms remove redroid-ashmem/1 --all
sudo dkms remove redroid-binder/1 --all

# Limpiar fuentes obsoletas
sudo rm -rf /usr/src/redroid-*
sudo rm -rf /var/lib/dkms/redroid-*

Fase 5: Configuración de GRUB

Problema Identificado: Terminal Serie

En VPS ARM64, GRUB usa terminal serie (GRUB_TERMINAL=serial), imposibilitando navegación manual del menú.

Solución: Configuración Automática

# Editar configuración GRUB
sudo nano /etc/default/grub

# Cambiar línea:
# GRUB_DEFAULT=0
# Por:
GRUB_DEFAULT="1>4"

# Explicación:
# 1 = "Advanced options for Debian GNU/Linux" (submenú)
# 4 = "Debian GNU/Linux, with Linux 6.1.0-android" (entrada específica)

# Aplicar cambios
sudo update-grub
sudo reboot

Fase 6: Verificación del Kernel Android

# Confirmar kernel activo
uname -r
# Resultado esperado: 6.1.0-android

# Verificar configuración Android compilada
cat /boot/config-6.1.0-android | grep -i android
# Resultado esperado:
# CONFIG_ANDROID_BINDER_IPC=y
# CONFIG_ANDROID_BINDERFS=y
# CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"

# Verificar interfaz de debug binder
ls -la /sys/kernel/debug/binder/
# Debe mostrar: failed_transaction_log, proc, state, stats, etc.

Fase 7: Configuración de Binderfs

Montaje Manual Inicial

# Crear directorio y montar binderfs
sudo mkdir -p /dev/binderfs
sudo mount -t binder binder /dev/binderfs

# Verificar dispositivos creados
ls -la /dev/binderfs/
# Resultado esperado:
# crw------- 1 root root 238, 1 binder
# crw------- 1 root root 238, 0 binder-control  
# crw------- 1 root root 238, 2 hwbinder
# crw------- 1 root root 238, 3 vndbinder

Enlaces de Compatibilidad

# Crear enlaces para compatibilidad con contenedores legacy
sudo ln -sf /dev/binderfs/binder /dev/binder
sudo ln -sf /dev/binderfs/hwbinder /dev/hwbinder
sudo ln -sf /dev/binderfs/vndbinder /dev/vndbinder

# Verificar enlaces
ls -la /dev/binder /dev/hwbinder /dev/vndbinder

Automatización con Systemd

# Script de configuración automática
sudo tee /usr/local/bin/android-setup.sh > /dev/null << 'EOF'
#!/bin/bash
# Android Setup Script
# Monta binderfs y crea enlaces de compatibilidad

# Montar binderfs
mkdir -p /dev/binderfs
mount -t binder binder /dev/binderfs

# Crear enlaces de compatibilidad para contenedores legacy
ln -sf /dev/binderfs/binder /dev/binder
ln -sf /dev/binderfs/hwbinder /dev/hwbinder
ln -sf /dev/binderfs/vndbinder /dev/vndbinder

echo "✅ Android setup completado"
EOF

sudo chmod +x /usr/local/bin/android-setup.sh

# Servicio systemd para automatización
sudo tee /etc/systemd/system/android-setup.service > /dev/null << 'EOF'
[Unit]
Description=Android Setup (binderfs + enlaces)
After=local-fs.target
Before=docker.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/android-setup.sh
RemainAfterExit=yes
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

# Habilitar y iniciar servicio
sudo systemctl daemon-reload
sudo systemctl enable android-setup.service
sudo systemctl start android-setup.service

Fase 8: Implementación de Redroid

Instalación de Docker (si no está instalado)

# Instalación oficial de Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo systemctl enable docker
sudo systemctl start docker

# Instalar herramientas ADB
sudo apt install android-tools-adb -y

Contenedor de Prueba

# Crear directorio de datos
mkdir -p ~/redroid-data

# Ejecutar contenedor Redroid de prueba
docker run -itd --privileged \
  --name redroid-test \
  --cpus="2.5" \
  --memory="4g" \
  -v ~/redroid-data:/data \
  -p 127.0.0.1:5555:5555 \
  redroid/redroid:12.0.0_64only-latest \
  androidboot.redroid_width=1080 \
  androidboot.redroid_height=1920 \
  androidboot.redroid_dpi=320 \
  androidboot.redroid_fps=30 \
  androidboot.use_memfd=true

# Monitorear arranque del contenedor
docker logs -f redroid-test
# Tiempo de arranque típico: 60-90 segundos en ARM64

Verificación de Conectividad ADB

# Esperar arranque completo
sleep 90

# Conectar ADB
adb connect localhost:5555

# Verificar dispositivos conectados
adb devices
# Resultado esperado:
# List of devices attached
# localhost:5555  device

# Probar comandos básicos
adb shell getprop ro.build.version.release
adb shell getprop ro.product.cpu.abi

🔧 Configuración para Múltiples Contenedores

Docker Compose para Producción

version: '3.8'
services:
  redroid-1:
    image: redroid/redroid:12.0.0_64only-latest
    container_name: redroid-instance-1
    privileged: true
    restart: unless-stopped
    ports:
      - "127.0.0.1:5555:5555"
    volumes:
      - ./data/instance-1:/data
    environment:
      - androidboot.redroid_width=1080
      - androidboot.redroid_height=1920
      - androidboot.redroid_dpi=320
      - androidboot.redroid_fps=30
      - androidboot.use_memfd=true
      - androidboot.redroid_fake_wifi=1
    deploy:
      resources:
        limits:
          cpus: '3.0'
          memory: 4G
        reservations:
          cpus: '1.5'
          memory: 2G

  redroid-2:
    image: redroid/redroid:12.0.0_64only-latest
    container_name: redroid-instance-2
    privileged: true
    restart: unless-stopped
    ports:
      - "127.0.0.1:5556:5555"
    volumes:
      - ./data/instance-2:/data
    environment:
      - androidboot.redroid_width=1080
      - androidboot.redroid_height=1920
      - androidboot.redroid_dpi=320
      - androidboot.redroid_fps=30
      - androidboot.use_memfd=true
      - androidboot.redroid_fake_wifi=1
    deploy:
      resources:
        limits:
          cpus: '3.0'
          memory: 4G
        reservations:
          cpus: '1.5'
          memory: 2G

  redroid-3:
    image: redroid/redroid:12.0.0_64only-latest
    container_name: redroid-instance-3
    privileged: true
    restart: unless-stopped
    ports:
      - "127.0.0.1:5557:5555"
    volumes:
      - ./data/instance-3:/data
    environment:
      - androidboot.redroid_width=1080
      - androidboot.redroid_height=1920
      - androidboot.redroid_dpi=320
      - androidboot.redroid_fps=30
      - androidboot.use_memfd=true
      - androidboot.redroid_fake_wifi=1
    deploy:
      resources:
        limits:
          cpus: '3.0'
          memory: 4G
        reservations:
          cpus: '1.5'
          memory: 2G

  redroid-4:
    image: redroid/redroid:12.0.0_64only-latest
    container_name: redroid-instance-4
    privileged: true
    restart: unless-stopped
    ports:
      - "127.0.0.1:5558:5555"
    volumes:
      - ./data/instance-4:/data
    environment:
      - androidboot.redroid_width=1080
      - androidboot.redroid_height=1920
      - androidboot.redroid_dpi=320
      - androidboot.redroid_fps=30
      - androidboot.use_memfd=true
      - androidboot.redroid_fake_wifi=1
    deploy:
      resources:
        limits:
          cpus: '3.0'
          memory: 4G
        reservations:
          cpus: '1.5'
          memory: 2G

Script de Gestión de Múltiples Contenedores

#!/bin/bash
# multiple-redroid.sh - Gestión de múltiples contenedores Redroid

set -e

CONTAINERS=4
BASE_PORT=5555
BASE_DIR="$HOME/redroid-multi"

start_containers() {
    echo "🚀 Iniciando $CONTAINERS contenedores Redroid..."

    # Crear directorios de datos
    for i in $(seq 1 $CONTAINERS); do
        mkdir -p "$BASE_DIR/data/instance-$i"
    done

    # Iniciar contenedores
    cd "$BASE_DIR"
    docker-compose up -d

    echo "⏱️  Esperando arranque de contenedores..."
    sleep 90

    # Conectar ADB a todos los contenedores
    for i in $(seq 1 $CONTAINERS); do
        local port=$((BASE_PORT + i - 1))
        echo "Conectando ADB al contenedor $i (puerto $port)..."
        adb connect localhost:$port
    done

    echo "✅ Contenedores iniciados:"
    adb devices
}

stop_containers() {
    echo "🛑 Deteniendo contenedores..."
    cd "$BASE_DIR"
    docker-compose down
}

status_containers() {
    echo "📊 Estado de contenedores:"
    docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}\t{{.CPUPerc}}\t{{.MemUsage}}"

    echo -e "\n📱 Dispositivos ADB:"
    adb devices
}

case "${1:-}" in
    start)
        start_containers
        ;;
    stop)
        stop_containers
        ;;
    status)
        status_containers
        ;;
    restart)
        stop_containers
        sleep 5
        start_containers
        ;;
    *)
        echo "Uso: $0 {start|stop|status|restart}"
        exit 1
        ;;
esac

📊 Optimizaciones de Rendimiento

Distribución de CPU por Contenedor

# Asignar cores específicos a cada contenedor (hardware con 12+ cores)
docker update --cpuset-cpus="0,1,2" redroid-instance-1
docker update --cpuset-cpus="3,4,5" redroid-instance-2  
docker update --cpuset-cpus="6,7,8" redroid-instance-3
docker update --cpuset-cpus="9,10,11" redroid-instance-4

Configuraciones del Sistema

# Optimizaciones para ARM64 y múltiples contenedores
echo 'vm.swappiness=10' >> /etc/sysctl.conf
echo 'vm.vfs_cache_pressure=50' >> /etc/sysctl.conf
echo 'kernel.sched_migration_cost_ns=5000000' >> /etc/sysctl.conf

# Aplicar cambios
sysctl -p

Monitoreo de Recursos

#!/bin/bash
# resource-monitor.sh - Monitoreo continuo de recursos

while true; do
    clear
    echo "=== Monitoreo Redroid $(date) ==="

    echo -e "\n🖥️  Sistema:"
    echo "  CPU Load: $(uptime | awk -F'load average:' '{print $2}')"
    echo "  Memory: $(free -h | awk '/^Mem:/ {print $3"/"$2" ("$3/$2*100"%)"}')"
    echo "  Disk: $(df -h / | awk 'NR==2 {print $4" free of "$2}')"

    echo -e "\n🐳 Contenedores:"
    docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"

    echo -e "\n📱 ADB Devices:"
    adb devices

    sleep 10
done

🔒 Consideraciones de Seguridad

Configuración de Red Segura

# NUNCA exponer ADB a internet público
# Usar solo binding local:
-p 127.0.0.1:5555:5555  # ✅ Correcto
-p 5555:5555            # ❌ PELIGROSO

# Para acceso remoto, usar túnel SSH:
ssh -L 5555:localhost:5555 user@server

Configuraciones de Contenedor Restringidas

# Contenedor con seguridad mejorada
docker run -itd --privileged \
  --security-opt=no-new-privileges \
  --cap-drop=ALL \
  --cap-add=SYS_ADMIN \
  --read-only \
  --tmpfs /tmp \
  --tmpfs /var/tmp \
  [otras opciones] \
  redroid/redroid:latest

🧪 Scripts de Verificación y Diagnóstico

Script de Health Check Completo

#!/bin/bash
# health-check.sh - Verificación completa del sistema Redroid

set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

check_kernel() {
    echo "🔍 Verificando kernel..."

    local kernel=$(uname -r)
    if [[ "$kernel" == *"android"* ]]; then
        echo -e "${GREEN}✅ Kernel Android activo: $kernel${NC}"
    else
        echo -e "${RED}❌ Kernel Android no activo: $kernel${NC}"
        return 1
    fi
}

check_android_config() {
    echo "🔍 Verificando configuración Android..."

    local config="/boot/config-$(uname -r)"
    if [[ -f "$config" ]]; then
        if grep -q "CONFIG_ANDROID_BINDER_IPC=y" "$config" && \
           grep -q "CONFIG_ANDROID_BINDERFS=y" "$config"; then
            echo -e "${GREEN}✅ Configuración Android correcta${NC}"
        else
            echo -e "${RED}❌ Configuración Android incompleta${NC}"
            return 1
        fi
    else
        echo -e "${YELLOW}⚠️  Config no encontrado: $config${NC}"
    fi
}

check_binderfs() {
    echo "🔍 Verificando binderfs..."

    if mountpoint -q /dev/binderfs; then
        echo -e "${GREEN}✅ binderfs montado${NC}"

        local devices=("binder" "hwbinder" "vndbinder" "binder-control")
        for device in "${devices[@]}"; do
            if [[ -e "/dev/binderfs/$device" ]]; then
                echo -e "${GREEN}  ✅ /dev/binderfs/$device${NC}"
            else
                echo -e "${RED}  ❌ /dev/binderfs/$device faltante${NC}"
            fi
        done
    else
        echo -e "${RED}❌ binderfs no montado${NC}"
        return 1
    fi
}

check_compatibility_links() {
    echo "🔍 Verificando enlaces de compatibilidad..."

    local links=("binder" "hwbinder" "vndbinder")
    for link in "${links[@]}"; do
        if [[ -L "/dev/$link" ]]; then
            echo -e "${GREEN}✅ /dev/$link -> $(readlink /dev/$link)${NC}"
        else
            echo -e "${RED}❌ /dev/$link faltante${NC}"
        fi
    done
}

check_containers() {
    echo "🔍 Verificando contenedores..."

    local running=$(docker ps --filter "ancestor=redroid/redroid:12.0.0_64only-latest" --format "{{.Names}}" | wc -l)
    echo "📊 Contenedores Redroid ejecutándose: $running"

    if [[ $running -gt 0 ]]; then
        docker ps --filter "ancestor=redroid/redroid:12.0.0_64only-latest" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
    fi
}

check_adb() {
    echo "🔍 Verificando conectividad ADB..."

    if command -v adb &>/dev/null; then
        local devices=$(adb devices | grep -v "List of devices" | grep "device" | wc -l)
        echo "📱 Dispositivos ADB conectados: $devices"

        if [[ $devices -gt 0 ]]; then
            adb devices
        fi
    else
        echo -e "${YELLOW}⚠️  ADB no instalado${NC}"
    fi
}

main() {
    echo "🩺 Health Check Completo - $(date)"
    echo "=================================="

    check_kernel
    check_android_config  
    check_binderfs
    check_compatibility_links
    check_containers
    check_adb

    echo -e "\n✅ Health check completado"
}

main "$@"

📚 Troubleshooting

Problemas Comunes y Soluciones

Contenedor no arranca

# Verificar logs del contenedor
docker logs redroid-test

# Errores comunes:
# - "Binder driver '/dev/binder' could not be opened"
#   Solución: Verificar enlaces de compatibilidad
# - "servicemanager: binder interface failed to initialize"
#   Solución: Reiniciar servicio android-setup

ADB no conecta

# Verificar puerto ocupado
netstat -tulpn | grep 5555

# Reiniciar servidor ADB
adb kill-server
adb start-server
adb connect localhost:5555

Kernel no arranca

# Arrancar con kernel anterior desde GRUB
# Editar GRUB_DEFAULT en /etc/default/grub
# Usar entrada del kernel estándar Debian

Rendimiento bajo

# Verificar distribución de CPU
docker stats

# Ajustar límites de recursos
docker update --cpus="4.0" --memory="6g" redroid-instance-1

📈 Métricas de Rendimiento Esperadas

Hardware de Referencia (VPS ARM64 Netcup)

  • CPU: 12 cores Ampere Altra
  • RAM: 24GB DDR4
  • Storage: NVMe SSD
  • Network: 1Gbps

Rendimiento por Contenedor

  • Tiempo de arranque: 60-90 segundos
  • Uso de memoria: 3-4GB por contenedor
  • Uso de CPU: 15-25% por contenedor en idle
  • Throughput de red: 200-500 Mbps por contenedor

Escalabilidad Máxima Probada

  • Contenedores simultáneos: 4 (recomendado)
  • Contenedores máximos: 6 (con limitaciones)
  • Uso total de memoria: ~16GB con 4 contenedores
  • Load average: 2-4 con 4 contenedores activos

🎯 Conclusiones

Logros Alcanzados

  1. Kernel Android nativo compilado exitosamente para ARM64
  2. Binderfs funcional con dispositivos Android completos
  3. Redroid estable ejecutándose en múltiples contenedores
  4. Automatización completa via systemd y Docker Compose
  5. Monitoreo y diagnóstico con scripts personalizados

Ventajas del Enfoque

  • Estabilidad superior vs módulos DKMS
  • Rendimiento nativo sin overhead de módulos
  • Mantenimiento simplificado con actualizaciones estándar
  • Escalabilidad probada para múltiples contenedores
  • Compatibilidad futura con evolución del kernel Linux

Recomendaciones de Producción

  1. Backup del kernel anterior antes de implementar
  2. Monitoreo continuo de recursos y estabilidad
  3. Actualizaciones graduales con testing previo
  4. Documentación personalizada para el entorno específico
  5. Plan de rollback en caso de problemas críticos

📝 Anexos

Script de Instalación Automatizada

#!/bin/bash
# auto-install-redroid.sh - Instalación completamente automatizada

# [El script completo combinaría todos los pasos anteriores 
#  en una secuencia automatizada con validaciones]

Archivos de Configuración de Referencia

Configuración GRUB completa:

# /etc/default/grub
GRUB_DEFAULT="1>4"
GRUB_TIMEOUT=5
GRUB_CMDLINE_LINUX="install net.ifnames=0 console=tty0 video=1024x768"
GRUB_TERMINAL=serial
GRUB_SERIAL_COMMAND="serial --unit=0 --speed=9600 --stop=1"

Configuraciones del kernel verificadas:

# Extracto de /boot/config-6.1.0-android
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_BINDERFS=y
CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"
CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_CGROUPS=y

Documento técnico compilado por: Proceso colaborativo de resolución de problemas
Fecha: Agosto 2025
Versión: 1.0
Hardware probado: VPS ARM64 Netcup Ampere Altra
Estado: Implementación exitosa y funcionando en producción

This page was last edited on 2025-08-01 15:02

Powered by Wiki|Docs

This page was last edited on 2025-08-01 15:02

Furtif
Free

Powered by Wiki|Docs