Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

El cangrejo vive dentro del teléfono

Daniel rooteó un Xiaomi Mi 8, metió OpenCrabs en un chroot de Ubuntu dentro del propio dispositivo y conectó una app de Flutter con él a través de ACP. Después el cangrejo escribió una app de Android, compiló el APK en el teléfono con aapt2, javac, d8 y apksigner, y la instaló. Sin PC, sin nube, sin Gradle, sin SDK.

Hay quien dice que Flutter es un desastre… pues sí (irónico) @opencrabs dentro del teléfono conectado por a2a a una app flutter propia. Puede cambiar el SO. Puede programar una app android, compilarla y abrirla… todo dentro del mismísimo teléfono

Primera app construida por completo dentro del teléfono con @opencrabs, sí, código hecho dentro del teléfono, apk compilada y abierta. No hace falta un pc ;)

El dispositivo: un Xiaomi Mi 8 (dipper), Android 10 / API 29, MIUI 12, aarch64, kernel 4.9.186, 5.6 GB de RAM. El root salió de la propia imagen de arranque: Magisk la parchea en el teléfono, fastboot la flashea y un verificador desempaqueta el resultado para inspeccionar el ramdisk en lugar de fiarse del log de parcheo. Ahora mismo: magisk -c informa de 30.7:MAGISK:R.

Meter un userland de Linux en Android llevó dos intentos. La primera generación enviaba el binario aarch64-linux-android como módulo de Magisk con un script supervisor, lo que suponía un port de cfg de 59 archivos y una pelea de glibc contra musl. La segunda generación, la que funciona hoy, es un chroot de Ubuntu 24.04.5 con glibc 2.39, que es lo que de verdad pide el binario linux-arm64 publicado. La trampa que más tiempo costó: /apex es un tmpfs de bind mounts por cada apex, así que un único bind de /apex copia un directorio vacío y todos los binarios de Android mueren con “required file not found”, que parece un error de permisos pero es un intérprete que falta. La solución es montar con bind cada entrada /apex/* por separado.

Luego la app. Daniel quería la interfaz de conversación que le gusta en la web, construida de forma nativa en Flutter, no una WebView. Así que la app habla ACP (JSON-RPC 2.0 sobre stdio) con opencrabs acp ejecutándose en el chroot, el mismo protocolo que usa la TUI: fragmentos de razonamiento en vivo, tarjetas de herramientas, solicitudes de permiso, uso de tokens. Sin navegador, sin servidor, sin puertos abiertos.

  • Sobrevive a un reinicio sin que nadie toque el teléfono: una tarea de JobScheduler que se rearma sin condiciones, un hook de servicio que espera sys.boot_completed y restablece los siete montajes, y un bucle que vuelve a aplicar los appops de reposo y arranque automático de MIUI porque el powerkeeper borra la exención de batería unos 20 s después del arranque
  • Prueba, tomada del logcat tras un reinicio real: handshake ok a los 12 s, servicio activo, exención de batería asentada, y después una autoprueba sin interfaz de 12 pass / 0 fail, GREEN en 3.7 s que cubre la versión del binario, la shell, las sesiones, el cableado de arranque, el estado del servicio, la exención de batería, el reconocedor de voz, el permiso de micrófono, la vinculación del widget, ACP listo y un prompt real
  • El APK compilado en el teléfono: MIUI incluye su tile de grabación de pantalla con solo un stub de 20 KB detrás, así que al tocarlo se abre la tienda de apps y no graba nada. El cangrejo escribió un tile real en los Ajustes rápidos, lo compiló en seis pasos sin Gradle y sin SDK manager, y lo puso en el panel junto al WiFi. 12,784 bytes.
  • La cadena de compilación: aapt2 compile → aapt2 link → javac --release 8 contra android.jar → d8 de R8 → meter el dex en el zip → zipalign → apksigner sign y verify
  • Instalado desde dentro del chroot, alcanzando el gestor de paquetes de Android mediante nsenter -t 1 -m; después se le concedió root escribiendo una fila de política de Magisk y se añadió al panel con cmd statusbar add-tile
  • Un cuerpo, dos cerebros: ACP es stdio y ssh -T también es stdio, así que el teléfono puede apuntar a un Mac en la LAN sin puente y sin puerto abierto. Medido: initialize en 1.2 s, lista de sesiones remotas de 40, autoprueba 9/9 GREEN contra el cerebro remoto

Lo que importa: el tile no graba nada por sí mismo. Lanza un comando, a través del su de Magisk, al mismo binario de grabación del chroot que usa el comando de chat /rec, así que hay una sola grabadora, un solo archivo de estado y una sola carpeta de salida. El cangrejo escribió una app de Android que es un mando para una herramienta de Linux dentro del mismo teléfono. La app es el pulgar, el cangrejo es el cerebro. Esa es toda la arquitectura de este proyecto, en 13 KB.

El log de razonamiento de esa sesión es el detalle que merece conservarse: el cangrejo se detuvo a comprobar si de verdad estaba en un teléfono, y lo confirmó desde el runtime en lugar de darlo por supuesto.

Ver la fuente en X ↗

El APK compilado en el teléfono ↗