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

O caranguejo vive dentro do telefone

O Daniel fez root a um Xiaomi Mi 8, instalou o OpenCrabs num chroot Ubuntu no próprio dispositivo e ligou-lhe uma aplicação Flutter através de ACP. Depois o caranguejo escreveu uma aplicação Android, compilou o APK no telefone com aapt2, javac, d8 e apksigner, e instalou-o. Sem PC, sem nuvem, sem Gradle, sem SDK.

Há quem diga que o Flutter é uma porcaria… pois é (irónico) @opencrabs dentro do telefone ligado por a2a a uma aplicação flutter personalizada. Consegue mudar o sistema operativo. Consegue escrever uma aplicação android, compilá-la e abri-la… tudo dentro do raio do telefone

Primeira aplicação totalmente construída dentro do telefone com @opencrabs, sim, código feito dentro do telefone, apk compilado e aberto. Sem necessidade de um pc ;)

O dispositivo: um Xiaomi Mi 8 (dipper), Android 10 / API 29, MIUI 12, aarch64, kernel 4.9.186, 5.6 GB de RAM. O root veio da própria imagem de arranque: o Magisk aplica-lhe o patch no telefone, o fastboot gravá-la e um verificador desempacota o resultado para inspecionar o ramdisk em vez de confiar no registo do patch. Agora mesmo: magisk -c devolve 30.7:MAGISK:R.

Pôr um userland Linux no Android exigiu duas tentativas. A primeira geração entregava o binário aarch64-linux-android como módulo Magisk com um script supervisor, o que implicava portar um cfg de 59 ficheiros e uma luta entre glibc e musl. A segunda geração, a que corre hoje, é um chroot Ubuntu 24.04.5 com glibc 2.39, que é exatamente o que o binário linux-arm64 distribuído quer. A armadilha que custou mais tempo: /apex é um tmpfs de bind mounts por apex, por isso um único bind de /apex copia um diretório vazio e todos os binários Android morrem com “required file not found”, que se lê como um erro de permissões mas é um interpretador em falta. A cura é fazer o bind de cada entrada /apex/* individualmente.

Depois, a aplicação. O Daniel queria a interface de conversa de que gosta na web, mas construída nativamente em Flutter, não numa WebView. Por isso a aplicação fala ACP (JSON-RPC 2.0 sobre stdio) com o opencrabs acp a correr no chroot, o mesmo protocolo que a TUI usa: blocos de raciocínio em direto, cartões de ferramentas, pedidos de permissão, consumo de tokens. Sem navegador, sem servidor, sem porta aberta.

  • Sobrevive a um reinício sem ninguém tocar no telefone: uma tarefa JobScheduler que se rearma incondicionalmente, um hook de serviço que espera por sys.boot_completed e restabelece as sete montagens, e um ciclo que reaplica os appops de idle e de arranque automático da MIUI, porque o powerkeeper limpa a isenção de bateria cerca de 20 s após o arranque
  • Prova, a partir do logcat após um reinício real: handshake ok aos 12 s, serviço no ar, isenção de bateria assente, e depois um autoteste headless de 12 passou / 0 falhou, VERDE em 3.7 s, cobrindo a versão do binário, a shell, as sessões, a ligação ao arranque, o estado do serviço, a isenção de bateria, o reconhecedor de voz, a permissão de microfone, a ligação do widget, o ACP pronto e um prompt real
  • O APK compilado no telefone: a MIUI entrega o seu tile de gravador de ecrã com apenas um stub de 20 KB por trás, por isso tocar nele abre a loja de aplicações e não grava nada. O caranguejo escreveu um tile real de Quick Settings, compilou-o em seis passos sem Gradle e sem SDK manager, e colocou-o no painel ao lado do WiFi. 12,784 bytes.
  • A cadeia de compilação: aapt2 compile → aapt2 link → javac --release 8 contra android.jar → d8 do R8 → incluir o dex no zip → zipalign → apksigner sign e verify
  • Instalado de dentro do chroot, chegando ao gestor de pacotes do Android através de nsenter -t 1 -m, depois com root concedido ao escrever uma linha de política do Magisk e adicionado ao painel com cmd statusbar add-tile
  • Um corpo, dois cérebros: o ACP é stdio e ssh -T também é stdio, por isso o telefone pode apontar para um Mac na LAN sem ponte e sem porta aberta. Medido: initialize em 1.2 s, lista de 40 sessões remotas, autoteste 9/9 VERDE contra o cérebro remoto

A parte que importa: o tile não grava nada por si. Invoca, através do su do Magisk, o mesmo binário de gravação no chroot que o comando de chat /rec usa, por isso há um gravador, um ficheiro de estado, uma pasta de saída. O caranguejo escreveu uma aplicação Android que é um puxador para uma ferramenta Linux dentro do mesmo telefone. A aplicação é o polegar, o caranguejo é o cérebro. É toda a arquitetura deste projeto, em 13 KB.

O registo de raciocínio dessa sessão é o detalhe que vale a pena guardar: o caranguejo parou para verificar se estava mesmo num telefone, e confirmou-o a partir do runtime em vez de assumir.

Ver a fonte no X ↗

O APK compilado no telefone ↗