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

Le crabe vit à l’intérieur du téléphone

Daniel a rooté un Xiaomi Mi 8, installé OpenCrabs dans un chroot Ubuntu sur l’appareil, et branché une app Flutter dessus via ACP. Puis le crabe a écrit une app Android, compilé l’APK sur le téléphone avec aapt2, javac, d8 et apksigner, et l’a installée. Pas de PC, pas de cloud, pas de Gradle, pas de SDK.

Certains disent que Flutter craint… ouais (ironique) @opencrabs à l’intérieur du téléphone relié en a2a sur une app flutter maison. Il peut changer l’OS. Il peut coder une app android, la compiler et l’ouvrir… tout ça dans le satané téléphone

Première app entièrement construite dans le téléphone avec @opencrabs oui, code fait dans le téléphone, apk compilé et ouvert. Pas besoin de pc ;)

L’appareil : un Xiaomi Mi 8 (dipper), Android 10 / API 29, MIUI 12, aarch64, noyau 4.9.186, 5,6 Go de RAM. Le root vient de l’image de boot elle-même : Magisk la patche sur le téléphone, fastboot la flashe, et un vérificateur dépaquette le résultat pour inspecter le ramdisk au lieu de faire confiance au log de patch. En direct : magisk -c renvoie 30.7:MAGISK:R.

Faire tourner un userland Linux sur Android a demandé deux tentatives. La première génération livrait le binaire aarch64-linux-android sous forme de module Magisk avec un script superviseur, ce qui impliquait un port de cfg sur 59 fichiers et une bataille glibc contre musl. La deuxième génération, celle qui tourne aujourd’hui, est un chroot Ubuntu 24.04.5 en glibc 2.39, ce que réclame réellement le binaire linux-arm64 publié. Le piège qui a coûté le plus de temps : /apex est un tmpfs de bind mounts par apex, donc un seul bind de /apex copie un répertoire vide et tous les binaires Android meurent avec « required file not found », ce qui ressemble à une erreur de permission mais signale un interpréteur manquant. Le remède est de binder chaque entrée /apex/* séparément.

Puis l’app. Daniel voulait l’UI de conversation qu’il aime sur le web, construite nativement en Flutter, pas une WebView. L’app parle donc ACP (JSON-RPC 2.0 sur stdio) à opencrabs acp qui tourne dans le chroot, le même protocole que la TUI : chunks de raisonnement en direct, cartes d’outils, demandes de permission, consommation de tokens. Pas de navigateur, pas de serveur, pas de port ouvert.

  • Survit à un redémarrage sans que personne touche au téléphone : un job JobScheduler qui se réarme sans condition, un hook de service qui attend sys.boot_completed et rétablit les sept mounts, et une boucle qui réapplique les appops idle et autostart de MIUI parce que le powerkeeper efface l’exemption de batterie environ 20 s après le boot
  • Preuve, depuis logcat après un vrai redémarrage : handshake ok à 12 s, service up, exemption de batterie stabilisée, puis un self test headless de 12 pass / 0 fail, GREEN en 3,7 s couvrant la version du binaire, le shell, les sessions, le câblage de boot, l’état du service, l’exemption de batterie, le recognizer vocal, la permission micro, le binding du widget, ACP prêt et un vrai prompt
  • L’APK compilé sur le téléphone : MIUI livre sa tuile d’enregistreur d’écran avec seulement un stub de 20 Ko derrière, donc l’appuyer ouvre le store et n’enregistre rien. Le crabe a écrit une vraie tuile Quick Settings, l’a compilée en six étapes sans Gradle ni SDK manager, et l’a placée dans le panneau à côté du WiFi. 12 784 octets.
  • La chaîne de build : aapt2 compile → aapt2 link → javac --release 8 contre android.jar → d8 de R8 → zipper le dex dedans → zipalign → apksigner sign et verify
  • Installé depuis l’intérieur du chroot, en atteignant le package manager d’Android via nsenter -t 1 -m, puis root accordé en écrivant une ligne de policy Magisk et ajouté au shade avec cmd statusbar add-tile
  • Un corps, deux cerveaux : ACP passe par stdio et ssh -T aussi, donc le téléphone peut pointer vers un Mac du LAN sans bridge et sans port ouvert. Mesuré : initialize en 1,2 s, liste de 40 sessions distantes, self test 9/9 GREEN contre le cerveau distant

Le point qui compte : la tuile n’enregistre rien elle-même. Elle shell out, via su de Magisk, vers le même binaire d’enregistrement dans le chroot que celui utilisé par la commande de chat /rec, donc un seul enregistreur, un seul fichier d’état, un seul dossier de sortie. Le crabe a écrit une app Android qui est une poignée pour un outil Linux dans le même téléphone. L’app est le pouce, le crabe est le cerveau. C’est toute l’architecture de ce projet, en 13 Ko.

Le journal de raisonnement de cette session est le détail qui vaut la peine d’être gardé : le crabe s’est arrêté pour vérifier qu’il était vraiment sur un téléphone, et l’a confirmé depuis le runtime au lieu de le supposer.

Voir la source sur X ↗

L’APK compilé sur le téléphone ↗