Aller au contenu

D'Android 13 à Android 17, comment Claude a récupéré, transformé et optimisé un téléphone de chantier

Une semaine avec Claude Code pour ressusciter un Ulefone Power Armor 18, le passer sous Android 17 avec une ROM compilée maison, puis l'optimiser.

Retours d'expérience23 min de lecture

Deux téléphones de chantier, un gris affichant 13 et un orange et noir affichant 17, à côté du titre de l'article et du logo de Claude.

Mon Pixel 8a a rendu l'âme. Un proche m'a donné un Ulefone Power Armor 18 qui ne marchait plus, et je me suis dit qu'il pouvait devenir mon téléphone principal. Sur le papier, c'est une bonne machine, avec une batterie de 9 600 mAh, un capteur de 108 Mpx, un écran 120 Hz et un Dimensity 900. Dans la vraie vie, il tourne sous Android 13 avec un vendor Android 12, un patch de sécurité de 2024, et Ulefone ne le mettra plus jamais à jour.

Le défi était simple à énoncer. Le faire tourner sous Android 17, sans rien perdre (120 Hz, caméra, NFC, appels, autonomie). Je ne l'ai pas relevé seul. Pendant une semaine, j'ai travaillé dans un terminal avec Claude Code, branché au téléphone en adb (Android Debug Bridge, l'outil en ligne de commande qui pilote un téléphone Android depuis un PC).

La méthode de travail#

Je n'ai pas utilisé Claude comme un moteur de recherche. Il travaillait directement sur ma machine. Il lançait les commandes adb et fastboot, lisait les logs, désassemblait les binaires, écrivait les scripts de build et de flash. Moi, je validais les étapes risquées et je tenais le téléphone.

Trois choses ont rendu ça possible.

  • Une mémoire persistante. Claude Code garde des notes entre les sessions. Chaque découverte importante (« ne jamais toucher à vbmeta », « le TEE n'accepte que l'identité stock ») finissait dans un fichier. Le lendemain, il reprenait exactement là où on s'était arrêtés, avec les pièges déjà connus.
  • Des garde-fous. Les écritures en mode BROM, capables de réécrire n'importe quelle partition, étaient bloquées par le mode automatique. C'est moi qui lançais ces commandes, avec ! dans le prompt. Pour tout ce qui pouvait bricker le téléphone (le transformer en brique irrécupérable), Claude demandait avant d'agir.
  • Des sauvegardes systématiques. Avant chaque grosse étape, Claude faisait un dump des partitions avec leurs SHA-256, comparés entre le téléphone et le PC.

Comprendre le terrain#

Avant de toucher à quoi que ce soit, Claude a cartographié le téléphone. C'est ce qui a permis de comprendre chaque panne par la suite, alors voici l'essentiel.

Les couches d'un téléphone Android#

Un téléphone Android n'est pas un bloc unique, c'est un empilement de couches.

  • Le noyau (kernel) est un Linux adapté par le fabricant de la puce. Il parle directement au matériel.
  • Le vendor regroupe tout ce que le constructeur et le fondeur ajoutent pour faire marcher leur matériel, avec les pilotes de la caméra, du modem, du GPU et de l'écran. On parle de HAL (Hardware Abstraction Layer), des petits programmes qui traduisent les demandes d'Android en ordres pour le matériel.
  • Le système, c'est Android lui-même, avec l'interface, les applis système et les services. C'est la partie qu'on veut remplacer.

Une ROM est un système Android complet prêt à être installé (« flashé »). La ROM stock est celle d'origine du constructeur.

Le Power Armor 18 réunit à peu près tout ce qui complique la tâche.

  • Une puce MediaTek MT6877 (Dimensity 900) avec un noyau Linux 4.19, bien trop vieux pour Android 17.
  • Android 13 stock (version Ulefone V16), posé sur un vendor Android 12 jamais mis à jour.
  • Des partitions A/B, en Virtual A/B, et des partitions dynamiques.
  • La compatibilité Treble.
  • Un TEE TrustKernel (Trusted Execution Environment), un mini-système isolé à côté d'Android qui garde les clés de chiffrement et refuse de les donner si quelque chose lui semble suspect.
  • Un bootloader (le programme qui démarre le téléphone et vérifie ce qu'il lance) verrouillé, mais déverrouillable.

Treble et les GSI#

Avant Android 8, système et vendor étaient mélangés. Pour mettre à jour Android, le constructeur devait reprendre tout son code à chaque version, ce qu'il ne faisait évidemment jamais. Avec le projet Treble, Google a coupé le téléphone en deux, avec une interface stable entre le système et le vendor.

C'est la clé de tout le projet. Il n'existe aucune ROM faite pour ce modèle, mais on peut flasher une GSI (Generic System Image), une image système générique qui s'appuie sur le vendor du constructeur pour parler au matériel. En théorie, ça démarre. En pratique, sur un MediaTek avec un vendor de 2021, il faut se battre.

Les partitions#

La mémoire du téléphone est découpée en plus de 70 partitions sur ses 512 Go de stockage UFS. Voici celles qui ont compté dans cette histoire.

PartitionTailleRôle
preloader4 MoPremier programme chargé, il initialise la RAM et lance le bootloader
lk2 MoLe bootloader (Little Kernel), qui gère le logo, le mode fastboot et la vérification des signatures
boot40 MoLe noyau Linux et son ramdisk, un mini-système de fichiers chargé en mémoire au démarrage (c'est là que Magisk s'installe)
dtbo8 MoLa description du matériel (device tree), quels composants et à quelles adresses
vbmeta, vbmeta_system, vbmeta_vendor8 MoLes signatures qui permettent de vérifier toutes les autres partitions
super7 GoLe conteneur des partitions dynamiques system, vendor et product
tee5 MoLe système sécurisé TrustKernel
md1img200 MoLe firmware du modem (4G, 5G, appels)
scp, sspm, gz, cam_vpu…quelques MoLes firmwares des co-processeurs de la puce (audio, énergie, caméra)
nvram, nvdata64 MoL'IMEI et les calibrations radio propres à ce téléphone, introuvables ailleurs
seccfg8 MoL'état du bootloader (verrouillé ou non)
metadata32 MoLes clés de chiffrement de /data, l'état des mises à jour, les infos du DSU
userdata468 Go/data, avec les applis, leurs données et les photos

Les partitions dynamiques vivent dans super, comme des volumes logiques (l'équivalent de LVM sur un PC Linux) qu'on peut créer et redimensionner. Le revers, c'est que le bootloader ne sait pas lire à l'intérieur de super.

Les slots A/B doublent presque tout ce qui sert à démarrer (boot_a, boot_b, lk_a, lk_b…). Une mise à jour s'installe sur le slot inactif, le téléphone bascule dessus au redémarrage, et revient tout seul à l'ancien en cas d'échec. Le Virtual A/B économise de la place en n'écrivant que les blocs modifiés dans des snapshots (les partitions -cow, pour copy-on-write), fusionnés pour de bon après un démarrage réussi. Retenez cette étape de fusion, c'est elle qui a tout déclenché.

La chaîne de démarrage#

Au démarrage, une série de programmes se passent le relais, et chacun vérifie la signature du suivant. C'est la chaîne de confiance, ou AVB (Android Verified Boot).

Démarrage d'un téléphone MediaTek
BROM          gravé dans la puce, impossible à modifier
  └─ preloader     initialise la RAM
      └─ LK            bootloader, fastboot, vérification AVB
          └─ boot          noyau Linux + ramdisk
              └─ init (1er étage)   monte super, vérifie system avec vbmeta
                  └─ init            lance les services, le TEE, déchiffre /data
                      └─ zygote          et enfin Android, les applis

Déverrouiller le bootloader revient à lui dire d'accepter des maillons non signés par le constructeur. Mais le TEE garde en mémoire dans quel état était la chaîne, et c'est lui qui a posé le plus de problèmes.

Les modes de démarrage#

  • Recovery, un mini-système de secours pour faire une réinitialisation d'usine ou installer une mise à jour.
  • Fastboot, servi par LK avant même le noyau. Il écrit boot ou vbmeta, mais pas ce qui se trouve dans super.
  • fastbootd, la même chose servie depuis le recovery, donc par un vrai noyau qui sait manipuler super. C'est par là qu'on flashe une GSI dans system_a.
  • Le mode BROM et le mode preloader, propres à MediaTek. Téléphone éteint et branché, un outil comme SP Flash Tool ou mtkclient peut lire et écrire toutes les partitions, même quand plus rien ne démarre. C'est le filet de sécurité ultime.
  • Le DSU (Dynamic System Updates), une fonction d'Android qui démarre un autre système stocké dans un simple fichier sur /data, sans toucher aux partitions.

Récupérer le téléphone#

Réparer le bootloop du déverrouillage#

Pour installer autre chose que le système d'origine, il faut déverrouiller le bootloader. J'ai lancé fastboot flashing unlock, et le téléphone est parti en bootloop sur les deux slots, avec un joli « dm-verity corruption ». dm-verity, c'est le mécanisme qui vérifie bloc par bloc que la partition système n'a pas été modifiée. Là, il trouvait des incohérences partout.

Claude a remonté la piste en lisant l'état de super. Une mise à jour OTA (Over The Air) était encore en attente de fusion, ses snapshots system_b-cow et product_b-cow toujours présents. Or le déverrouillage efface /data, qui contenait aussi l'état de ces snapshots. Plus rien ne tenait debout. Et en essayant de réparer, on a aussi effacé /metadata, ce qui a aggravé les choses.

La sortie de secours a été une ROM stock V12 trouvée sur needrom. Claude a écrit un petit script pour la flasher sur le slot a via le fastboot de LK, partition par partition. Le téléphone est reparti, déverrouillé, en Android 13.

Réparer le brick du vbmeta#

Le deuxième jour, j'ai voulu flasher une GSI pour de bon sur system_a. La recette habituelle des forums consiste à flasher un vbmeta avec les flags à 2 ou 3, qui dit au bootloader de ne plus rien vérifier. Sur ce téléphone, c'est un piège.

Avec le vbmeta principal désactivé, le bootloader ne transmet plus de root of trust valide au TEE, cette information qui dit « le démarrage est fiable, voici avec quelle clé ». Le TEE refuse alors de donner les clés, et /data ne se déchiffre plus. Même le système stock ne démarrait plus. Et le vbmeta_system est signé par une clé privée d'Ulefone, impossible à re-signer.

Le BROM n'étant pas protégé sur ce modèle, Claude a préparé la restauration avec mtkclient à partir des dumps du premier jour, et j'ai lancé les écritures moi-même. Le téléphone est revenu.

La solution qu'il a trouvée ensuite est élégante. Laisser tous les vbmeta d'origine, et modifier le boot.img, déjà patché par Magisk (l'outil qui donne les droits root sans toucher à la partition système). Son premier étage de démarrage contient un fstab, la liste des partitions à monter et de leurs options. Claude a simplement retiré la demande de vérification AVB sur la ligne system. Le système est monté sans dm-verity, et le TEE reste content.

Installer la dernière ROM stock#

La ROM V12 de needrom m'avait sorti du pétrin, mais elle avait un an de retard, et une ROM récupérée sur un site tiers n'est jamais idéale. Pire, j'avais un mélange V12 et preloader V16 sur lequel les OTA refusaient de s'installer.

J'ai écrit au service client d'Ulefone pour demander la dernière ROM stock, la V16. Deux jours plus tard, ils m'ont envoyé un guide en PDF et des identifiants FTP, avec la ROM complète, SP Flash Tool et les pilotes USB. Je ne m'attendais pas à une réponse aussi rapide, encore moins aussi complète.

Claude a d'abord vérifié que le preloader de la ROM était identique à celui du téléphone, pour écarter tout risque d'anti-rollback (une protection qui bloque définitivement le téléphone si on installe une version plus ancienne que celle déjà vue). Il a ensuite comparé V12 et V16, avec le même noyau 4.19 mais 439 fichiers vendor modifiés (caméra, modem, Wi-Fi, keymaster, GPU…). Son script a mis à jour le boot, le vendor et les firmwares, et re-patché l'identité TEE au niveau V16, tout en gardant la GSI et mes données. 45 secondes de boot, et tout était là.

Transformer le téléphone#

Faire démarrer une GSI Android 17#

Plutôt que de flasher en aveugle, Claude a testé chaque image en DSU. Si ça plante, un redémarrage ramène sur le système stock. Pour voir ce qui se passait pendant un boot raté, il a ajouté au boot.img un petit script qui copie les logs dans /metadata, la seule partition lisible après un échec.

Il a fallu une série de correctifs, chacun identifié dans ces logs.

  • L'APEX de virtualisation. Des morceaux du système sont livrés en APEX, des paquets que Google met à jour séparément. Celui de la virtualisation est formaté en EROFS, un système de fichiers que le noyau 4.19 ne connaît pas, et apexd échouait au démarrage. Claude l'a retiré de l'image, il ne sert à rien ici.
  • La signature AVB. Sans hashtree footer (l'empreinte de la partition ajoutée en fin d'image) signé avec la clé de test d'AOSP, le DSU restait bloqué au premier étage. Coup de chance, Ulefone utilise justement cette clé de test.
  • Le TEE TrustKernel. Le plus vicieux. Le keymaster n'accepte que l'identité exacte du firmware stock, jusqu'à ro.product.name = Power_Armor_18_EEA, le patch de sécurité et même ro.build.version.release=13. Sinon, il répond TEE return -38 / Invalid Root of Trust, le chiffrement de /data échoue et le téléphone redémarre en boucle. Claude a donc fait mentir la GSI sur son identité dans tous les build.prop.
  • BPF. Android 17 exige un noyau 5.4 minimum pour charger ses programmes eBPF de comptage réseau. Avec un 4.19, NetBpfLoad échouait et faisait redémarrer le téléphone. Claude a porté les patchs « kernel-relax » de TrebleDroid, le projet communautaire qui maintient les GSI, pour rendre ces vérifications optionnelles.

Pourquoi garder le noyau 4.19#

La question revient souvent. Si Android 17 attend un noyau 5.4 ou plus, pourquoi ne pas simplement en installer un plus récent ? Je l'ai demandé à Claude. Sa réponse, c'est que ce serait faisable en théorie, mais au prix de beaucoup de temps et de tests, pour un gain qui n'en vaut pas la peine. Plusieurs raisons se cumulent.

  • Pas de sources. Ulefone ne publie pas le code de son noyau, alors que la licence GPL l'y oblige. Sans lui, impossible de savoir exactement quels pilotes et quels réglages sont embarqués, ni de repartir de sa configuration.
  • Une puce livrée en 4.19. Le support du MT6877 fourni par MediaTek aux constructeurs (le BSP, pour Board Support Package) a été développé pour la branche 4.19, et les noyaux MT6877 publiés par d'autres marques sont eux aussi en 4.19. Il n'existe pas de base 5.x toute prête pour cette puce.
  • Des pilotes hors du noyau officiel. L'écran, le modem, la caméra, la gestion de la charge, l'empreinte ou le TEE reposent sur des pilotes maison de MediaTek et d'Ulefone, absents du Linux officiel. Il faudrait tous les porter à la main vers une API du noyau qui a beaucoup changé entre 4.19 et 5.x, sans matériel de test autre que mon téléphone.
  • Un vendor figé. Les HAL du vendor sont des binaires compilés pour parler à ce noyau-là. Le pilote GPU Mali, par exemple, doit correspondre exactement à la version de la bibliothèque graphique du vendor. Et les HAL de cette génération allouent leur mémoire via ION, un mécanisme supprimé du noyau à partir de la version 5.11. Changer de noyau casserait la caméra, l'affichage ou le GPU, sauf à réécrire aussi le vendor, dont on n'a pas les sources non plus.
  • Le TEE et la chaîne de démarrage. Le pilote TrustKernel est propriétaire, et le bootloader attend une image et un device tree bien précis. Une erreur à ce niveau se termine en brick, avec le mode BROM comme seule issue.

Au bout du compte, porter un noyau 5.x représenterait des mois de travail pour un résultat incertain. Il était bien plus réaliste de faire l'inverse, c'est-à-dire adapter Android 17 à ce vieux noyau, en rendant optionnelles les quelques fonctions qu'il ne sait pas fournir.

Compiler LineageOS 24#

Une GSI Android 17 existait déjà (RestlessOS), et elle démarrait avec nos correctifs. Mais elle est basée sur GrapheneOS, sans services Google, donc sans Google Wallet. Les appels ne passaient pas, le NFC ne s'allumait pas, et 13 % des images à l'écran étaient en retard.

J'ai donc demandé à Claude de compiler ma propre GSI LineageOS 24 (l'équivalent d'Android 17), à partir du travail de TrebleDroid et du développeur cawilliamson.

  • 134 Go de sources synchronisés avec repo, l'outil de Google qui gère les centaines de dépôts Git d'Android.
  • 351 patchs appliqués automatiquement, et une dizaine portés à la main par Claude quand ils ne s'appliquaient plus sur Android 17 (BPF sans noyau récent, empreinte via HIDL pour mon vendor Android 12, vold, fs-verity, LightsService…).
  • Des corrections de build à la chaîne, avec des modules de virtualisation retirés, des doublons de protobuf, des erreurs Java et des API cachées pour metalava.

Le 2 novembre au matin, le build est passé. Premier test en DSU, boot complet, avec le chiffrement, le 120 Hz, les 4 caméras, l'empreinte, le Wi-Fi et même le NFC.

La VoLTE et la fluidité#

Deux points restaient bloquants pour un usage quotidien.

La VoLTE, qui fait passer les appels directement sur le réseau 4G. Sans elle, le téléphone redescend en 3G à chaque appel. Chez MediaTek, le service IMS qui la gère est une appli propriétaire. Claude a embarqué ImsServiceMtk en application système privilégiée, patché CarrierConfig pour activer la VoLTE et la VoWiFi chez Free, et forcé deux propriétés système. Au bout du compte, les appels passent en ims sur LTE.

Le lag dans les Paramètres. Quand on touche l'écran, Android envoie un « indice » au HAL de performance du vendor, qui monte aussitôt la fréquence du processeur. Claude a découvert que l'indice envoyé par la GSI n'activait aucun boost côté MediaTek. En le remplaçant par le scénario APP_ROTATE (fréquence max et priorité au premier plan pendant une seconde), on est passé de 20 % d'images en retard à 0,9 %.

Optimiser le téléphone#

Le téléphone marchait. Mais au quotidien, plusieurs choses clochaient. C'est la partie où Claude m'a le plus impressionné, parce qu'on est passé de « ça marche » à « ça marche bien ».

Faire marcher le 120 Hz#

Soit le téléphone restait bloqué à 60 Hz, soit à 120 Hz en permanence, et la batterie trinquait. Claude a trouvé la cause dans un overlay du vendor (un petit APK qui remplace des valeurs de configuration d'Android) qui fixe config_defaultRefreshRate=61.

Son premier correctif, un module Magisk qui ajoute un overlay corrigé, a marché jusqu'à ce que Gmail, Teams et le navigateur restent bloqués au chargement. Dans les logs, il a vu webview_zygote planter à chaque rendu. zygote avait ouvert l'APK de l'overlay, mais Magisk masquait ce fichier à webview_zygote, qui plantait en voulant le rouvrir.

La version finale tient en deux pièces.

  1. Un overlay statique intégré à l'image système, avec la valeur à 0 (« pas de limite »).
  2. Un minuscule module Magisk qui définit debug.sf.set_idle_timer_ms=500, pour que SurfaceFlinger (le service qui assemble l'image affichée) redescende en fréquence après une demi-seconde sans mouvement.

Le téléphone affiche désormais 60 Hz quand l'écran est statique, 120 Hz dès que ça bouge.

Sortir la composition du GPU#

L'autonomie restait décevante pour une telle batterie. Ce qu'on voit à l'écran est un empilement de couches (barre d'état, appli, barre de navigation, clavier…) à superposer 60 ou 120 fois par seconde. Deux façons de faire existent.

  • Le GPU dessine tout dans une seule image (composition « client »), ce qui le réveille et consomme de la mémoire à chaque image.
  • Le contrôleur d'affichage, un circuit dédié, superpose lui-même les couches au moment de les envoyer à l'écran (composition « device »). C'est presque gratuit en énergie. Le HAL qui le pilote s'appelle le HWC (Hardware Composer).

Claude a constaté que toutes les couches étaient composées par le GPU, à chaque image, même pour une appli toute simple. SurfaceFlinger consommait la moitié d'un cœur pendant un simple défilement.

L'enquête a pris plusieurs sessions sur quatre jours, couche par couche.

  • SurfaceFlinger demandait bien une composition matérielle.
  • Le HWC du vendor ne forçait rien non plus.
  • C'est le noyau qui, via une règle de répartition des couches, renvoyait « tout en GPU » à chaque image.
  • Une première théorie (un retour en arrière en mode veille) s'est révélée fausse. Claude l'a lui-même démontée avec des kprobes, des sondes posées à chaud sur une fonction du noyau en marche pour voir quand elle est appelée et avec quelles valeurs, sans recompiler ni redémarrer.

Ulefone ne publie pas les sources de son noyau. Claude l'a donc désassemblé, en retraduisant le code machine en assembleur ARM64. Il a isolé la fonction copy_hrt_bound_table et l'a comparée au code source publié d'un autre téléphone MT6877, chez Xiaomi. La fonction calcule correctement la bande passante disponible… puis l'ignore, et écrit en dur une limite de 100.

Noyau Ulefone, copy_hrt_bound_table
mov  x9, #0x64              // 100
movk x9, #0x64, lsl #32     // 100 dans les deux moitiés
stp  x9, x9, [...]          // emi_bound_table = {100, 100, 100, 100}

Cette table indique combien de couches le contrôleur d'affichage peut lire en mémoire en même temps sans prendre de retard (HRT, pour Hard Real Time). 100, c'est la bande passante d'une seule couche plein écran. Dès deux couches, le noyau décide que le contrôleur ne suivra pas, et tout part au GPU. La ROM stock fait pareil, c'est un choix d'Ulefone, peut-être pour éviter des glitchs, peut-être un oubli.

Le correctif de Claude tient en 11 instructions modifiées dans l'image du noyau, pour utiliser la valeur réellement calculée (548, soit environ 5 couches) au lieu de 100. Il l'a appliqué avec magiskboot hexpatch, qui cherche une suite d'octets précise et la remplace. Ni sources, ni recompilation.

Côté autonomie, la première charge à 100 %, faite avant ce patch, avait tenu trois jours. C'est correct, mais pas à la hauteur d'une batterie de 9 600 mAh, j'en attendais davantage. Depuis le patch, le téléphone est en test de décharge sur une utilisation de tous les jours, et les réglages restent à affiner.

Réduire la consommation de la batterie#

  • Le Bluetooth qui scannait 9 h par jour. Une nuit, 17 % perdus écran éteint. Claude a trouvé dans batterystats que Google Play Services faisait un scan BLE continu pour Fast Pair, la détection automatique des écouteurs à proximité. Désactiver « Rechercher des appareils à proximité », puis couper et rallumer le Bluetooth, a réglé le problème.
  • Le CPU. Claude a vérifié la gestion de fréquence, avec le governor schedutil, des cœurs au minimum au repos, le HAL de performance MediaTek et le boost au toucher actifs. Rien à corriger, et c'est bien de le savoir aussi.
  • La santé de la batterie. Android annonçait 2 946 mAh, une valeur fausse. Claude est allé lire la vraie jauge, une puce SD77561, dans dmesg, qui donne environ 8,5 à 9,3 Ah sur 9,6. Au passage, il a trouvé comment couper la charge à la main, et une limite de charge à 80 % est née.

Corriger les bugs du quotidien#

  • Plus de 4G après un appel. L'icône de données barrée, systématiquement après un appel. Claude a découvert qu'une préférence de l'appli TrebleApp désactivait la VoLTE au démarrage en écrasant nos propriétés. Les appels basculaient en 3G (le CSFB), et au retour en 4G la connexion de données restait « connectée » mais morte. Une préférence à true, et la VoLTE est revenue.
  • Le bouton power qui marche une fois sur trois. getevent montrait que toutes les pressions arrivaient bien. En fait, le capteur d'empreinte du bouton réveillait l'écran 400 ms après l'avoir éteint, le doigt étant encore dessus. Désactiver « Toucher pour déverrouiller à tout moment » a suffi.

Transformer le téléphone en outil USB#

Tant qu'à avoir un téléphone rooté avec 512 Go, autant s'amuser.

  • Une clé Ventoy dans le téléphone. Ventoy met plusieurs ISO sur une seule clé USB. Le noyau Linux sait se faire passer pour une clé de stockage (le gadget mass_storage), donc un fichier image de 128 Go sur le téléphone devient une clé bootable pour PC (SystemRescue, MemTest86+, installeurs Windows et Linux), tout en gardant adb actif.
  • Un clavier et une souris USB. Le noyau MediaTek contient un /* HACK, replace content */ qui écrase le descripteur HID (la fiche d'identité d'un clavier ou d'une souris) par un périphérique inutile. Claude a remplacé une seule instruction par un saut, et le PC voit un vrai clavier.
  • Une appli Toolbox. Une petite appli Android compilée sans Gradle, avec des tuiles dans les réglages rapides pour la clé Ventoy, le partage de connexion USB, le clavier et touchpad, la limite de charge, et le bouton latéral gauche qui ouvre le panneau (lampe torche en appui long).

Sauvegarder les données#

Sauvegarder 32 Go de /data depuis adb paraît simple. Ça ne l'est pas.

  • adb exec-out mélange la sortie d'erreur du téléphone au flux. Un avertissement de tar sur une socket, et l'archive est corrompue.
  • /data/user/0 est un bind mount de /data/data, et la sauvegarde double de taille.
  • Le su de Magisk passe par un pseudo-terminal qui finit par se figer.

La méthode retenue par Claude consiste à arrêter les applis, lancer tar en arrière-plan sur le téléphone vers un fichier local (environ 200 Mo/s), puis faire un adb pull et comparer les SHA-256.

Ce que Claude a bien fait, et moins bien#

Ce qui m'a bluffé.

  • Le reverse engineering du noyau. Désassembler une fonction compilée avec CFI et beaucoup d'inlining, la comparer au code d'un autre constructeur, poser des kprobes pour valider une hypothèse. Je n'aurais jamais eu la patience de le faire seul.
  • La rigueur sur les sauvegardes et les checksums avant chaque flash. C'est elle qui a rendu le deuxième brick réparable.
  • La mémoire entre les sessions. Sur une semaine, avec des dizaines de pièges, c'est ce qui fait la différence entre un projet qui avance et un projet qui tourne en rond.
  • La méthode de diagnostic, toujours la même. Lire les logs, formuler une hypothèse, la vérifier, et l'abandonner si les faits la contredisent.

Ce qui a moins bien marché.

  • Le premier jour, effacer /metadata pour réparer a aggravé la situation.
  • Une fausse piste sur la composition GPU, défendue pendant une session entière avant d'être démontée.
  • Un build lancé avec trop de jobs, qui a mis la machine à genoux.

Rien de dramatique, mais ça rappelle qu'il faut garder la main sur les décisions irréversibles. Les garde-fous (valider chaque flash, lancer moi-même les écritures BROM) n'étaient pas de trop.

Les limites#

  • Play Integrity. C'est le test de Google qui permet aux applis (banques, Wallet) de vérifier que le téléphone n'a pas été modifié. Avec un bootloader déverrouillé et une GSI, on n'obtient que le niveau BASIC, alors que le paiement sans contact demande le niveau supérieur. Google Wallet ne fonctionne donc toujours pas. Mes applis bancaires, elles, marchent sans aucun souci, grâce à la DenyList de Magisk, à HMA-OSS (qui cache aux applis la liste des applis installées) et au module Play Integrity Fix.
  • Les patchs noyau sont fragiles. Toute mise à jour de Magisk ou reflash du boot efface les patchs HID et composition GPU. Il faut les réappliquer, heureusement en une commande.
  • Le DSU du système stock V16 n'a jamais démarré, on n'a donc pas pu comparer directement avec le comportement d'origine.

En bref#

  • Un téléphone Treble abandonné par son constructeur peut tourner sous Android 17, même avec un noyau 4.19 et un vendor Android 12, au prix d'une ROM compilée et patchée sur mesure.
  • Sur MediaTek, le TEE impose l'identité du firmware stock, et le vbmeta ne doit surtout pas être touché.
  • Le DSU permet de tester une GSI sans risque, et le BROM non protégé sert de filet de sécurité, à condition d'avoir fait ses dumps avant.
  • Les vrais gains de batterie sont venus du diagnostic, avec un noyau qui envoyait tout au GPU, un scan Bluetooth sans fin et un 120 Hz bloqué.
  • Claude Code s'est comporté comme un binôme très compétent et infatigable, à condition de lui donner une mémoire, des garde-fous, et de garder les décisions risquées pour soi.

En une semaine, un téléphone cassé et coincé en Android 13 est devenu mon téléphone principal sous Android 17, plus fluide et plus endurant qu'en stock. Et j'ai beaucoup plus appris sur Android, MediaTek et les noyaux que je ne l'aurais imaginé.