Motivation du projet
Le Magcubic HY350 Max est un projecteur LCD en 1080p natif — 1920 × 1080 réels, pas une image étirée depuis du 720p, ce qui est loin d'être la règle dans cette gamme de prix. Il est animé par un Allwinner H726 sous Android 14, avec autofocus et correction trapézoïdale automatique. (fiche produit officielle)
Resolution native 1920 x 1080, dalle LCD
Luminosite 600 ANSI lumens
Taille d'image 35 a 135 pouces de diagonale
Rapport de projection 1:1 (une image de 2,50 m de large
demande 2,50 m de recul)
Contraste 10 000:1
Systeme Android 14 - Allwinner H726
Reseau Wi-Fi 2,4 / 5 GHz, Bluetooth 5.4
Audio haut-parleur 15 W
Encombrement 183,5 x 176 x 109 mm, 1,41 kgDeux précisions honnêtes, parce que les fiches commerciales ont leurs raccourcis et que je préfère qu'on soit d'accord dès le départ.
Le « 8K » qu'on lit un peu partout désigne le décodage vidéo, pas l'affichage : l'appareil sait lire un fichier en 8K, il l'affiche en 1080p. Ce qui est déjà très bien, et honnêtement suffisant pour la taille d'image visée.
Et 600 ANSI lumens, c'est un appareil de pièce sombre ou de fin de journée. N'espérez pas projeter volets ouverts en plein après-midi : aucun projecteur de cette catégorie ne le fait, quoi qu'en disent les annonces qui promettent 20 000 « lumens » sans préciser lesquels.
Cela dit — et je tiens à le dire, parce que la suite de cet article pourrait laisser croire le contraire — le rapport qualité-prix est imbattable. Le site officiel l'affiche à 104,95 €, et on le trouve régulièrement entre 60 et 80 € en promotion sur les places de marché. Pour ce tarif, avoir un vrai 1080p, l'autofocus, la correction automatique des trapèzes et un haut-parleur qui tient la route, c'était impensable il y a trois ans. Chez moi il projette sur 2,50 m de large et le résultat est très convaincant. Il serait dommage de s'en passer !
C'est d'ailleurs toute la raison de ce projet : je n'avais aucune envie de jeter un bon appareil. Je voulais juste qu'il cesse de faire des choses que je ne lui avais pas demandées.
Car à la suite des articles parus sur ces projecteurs (sources 1, 2), j'ai voulu regarder ce que contenait réellement la ROM de mon HY350 Max, puis la nettoyer.
De son côté, le constructeur a publié un communiqué officiel au sujet de certains fichiers APK présents sur la série HY300 équipée de la puce H713. Il y indique que les modèles à puce H726 ne sont pas concernés. Le HY350 Max est un H726. Le second article, consacré à l'analyse, présentera simplement les relevés que j'ai faits sur le mien.
Articles et analyse personnelle
Selon ces articles, et après avoir sondé moi-même le projecteur, l'examen du micrologiciel montre la présence d'applications et de services intégrés au système. Ils appartiennent à la base logicielle Hotack, sur laquelle reposent ces projecteurs : le constructeur assemble un matériel autour d'une base fournie par un tiers, ce qui est la norme dans ce secteur.
Ces composants n'apparaissent nulle part dans l'interface, et fonctionnent avec l'identité système d'Android — autrement dit le niveau de privilège le plus élevé qu'une application puisse recevoir. Ils contactent des serveurs distants dès le démarrage, en tâche de fond, sans que rien ne l'indique à l'écran ni ne soit demandé à l'utilisateur.
Les analyses publiées vont plus loin : elles décrivent des appareils de ce type enrôlés comme relais résidentiels, dont la connexion Internet du foyer sert à masquer l'origine d'activités malveillantes. Je n'ai pas cherché à reproduire cette partie-là. Je m'en tiens à ce que j'ai pu constater moi-même, et je renvoie aux sources pour le reste — la distinction me paraît importante.
Un mot, aussi, sur ce que je n'écrirai pas. On peut établir ce qu'un micrologiciel contient et ce qu'il fait : c'est mesurable, et ce sera l'objet du second article. On ne peut pas établir qui l'y a mis, ni pourquoi. Une chaîne de fabrication compte plusieurs intervenants, et n'importe lequel d'entre eux peut lui-même avoir été compromis quelque part. Il y a des victimes — à commencer par ceux qui ont acheté l'appareil — mais désigner un coupable relèverait de la spéculation, et je m'en abstiendrai.
Aboutissement

Une mise à jour simplifiée
Les procédures que l'on trouve sur Internet sont laborieuses. Elles demandent d'abord de connecter le projecteur à Internet pour activer l'ADB, en passant par les paramètres Android ou par le menu d'usine présent sur l'appareil, puis de le relier à un ordinateur avec un câble USB type A ⟷ USB type A. Ce n'est pas à la portée de tout le monde.
Vous trouverez ici 4 fichiers que j'ai préparés.

L'autre voie consiste à récupérer une ROM personnalisée et, toujours avec ce câble, à l'écrire sur le projecteur à l'aide d'un logiciel dédié.
J'ai voulu simplifier tout cela en vous proposant deux formats de mise à jour, qui ne réclament qu'une clé USB formatée en FAT32.
- La mise à jour OTA, directement depuis MagcubicOS, l'interface du constructeur : elle conserve vos applications et vos réglages déjà en place.
- La mise à jour au démarrage, en allumant le projecteur : elle efface vos données existantes.
Pour ces ROM, j'ai installé et préconfiguré plusieurs applications :
- Projectivy : un lanceur bien adapté à la télécommande, entièrement personnalisable, avec pas mal d'options intéressantes
- SmartTube : pour vos vidéos YouTube
- Nova Player : open source, pour vos vidéos en USB et en réseau, avec une présentation par jaquettes, comme une vraie vidéothèque
- VLC, qu'on ne présente plus
- Voyager : gestionnaire de fichiers open source, avec un excellent accès aux partages réseau
J'ai également mis à jour les services Google Play ainsi que le Play Store. Précision qui a son importance : ces mises à jour ont été faites par Android lui-même, et non avec un APK récupéré sur un site tiers. C'est donc le système qui a vérifié la signature de Google.
Sous le capot : qu'est-ce qu'on ouvre, au juste ?
Quatre poupées russes
Avant de raconter les essais, il faut poser le décor. Quand on télécharge le firmware officiel du HY350 Max sur le site de support du constructeur, on récupère un fichier update.img de 2,2 Go. On serait tenté de croire qu'il s'agit d'une image disque. Pas du tout.
C'est une archive, au format IMAGEWTY, propre à Allwinner. Elle contient une soixantaine de fichiers : le chargeur d'amorçage, l'environnement de démarrage, les tables de partitions, le logo affiché à l'allumage… et surtout un gros morceau nommé super.fex, qui contient lui-même les partitions Android.
update.img archive IMAGEWTY
└─ super.fex image de partitions dynamiques
├─ system Android
├─ product applications du constructeur
├─ vendor pilotes
└─ …Autrement dit : une archive, dans laquelle il y a une image de partitions dynamiques, dans laquelle il y a des systèmes de fichiers, dans lesquels il y a les applications. Quatre poupées russes. Chaque niveau demande son propre outil, et aucun ne pardonne l'erreur d'un octet.
Le détail qui m'a coûté deux jours
Dans cette archive, chaque fichier est accompagné d'un compagnon de vérification : à côté de mediadata.fex, il y a Vmediadata.fex, qui contient sa somme de contrôle. Si vous modifiez le premier sans recalculer le second, l'appareil refuse l'image. Logique.
J'avais écrit l'outil qui recalcule ces sommes. Il fonctionnait. Sauf pour un fichier, toujours le même, et je ne comprenais pas pourquoi. La réponse :
attendu par mon outil : Vmediadata.fex
present dans l'archive : vmediadata.fexUne lettre. L'image partait avec une somme périmée et le projecteur la rejetait sans un mot d'explication.
Je le raconte parce que c'est exactement ce à quoi ressemble ce genre de travail. Ce n'est presque jamais un obstacle intellectuel. C'est une lettre, un octet, un décalage.
La mise à jour OTA : quatre portes fermées
Le morceau le plus difficile, et de loin, aura été de fabriquer une mise à jour que le projecteur accepte sans câble. Android sait faire ça depuis longtemps : la documentation officielle des mises à jour A/B décrit précisément le format attendu. J'ai suivi la documentation à la lettre. Le projecteur a dit non.
Quatre fois, pour quatre raisons différentes. Les trois premières se referment avant l'installation ; la quatrième ne se voit qu'une fois tout le reste réussi. Il a fallu décompiler l'application de mise à jour du constructeur pour comprendre les trois premières, et beaucoup d'observation pour la dernière. Je les détaille, parce qu'elles ne sont documentées nulle part et que si quelqu'un cherche un jour, ça lui fera gagner des semaines.
Première porte : un tableau de taille négative
Premier essai : l'application plante immédiatement.
java.lang.NegativeArraySizeException: -1En décompilant, on comprend : l'application lit la taille de la métadonnée en interrogeant l'en-tête local de l'entrée dans le fichier ZIP. Or cette taille n'y figure que si l'entrée est stockée sans compression. Sinon la fonction rend -1… et le programme tente d'allouer un tableau de moins un octet.
Correctif : la métadonnée doit être stockée non compressée, et en première position dans l'archive. Ce que la documentation d'Android ne demande nulle part.
Deuxième porte : mais où est la charge utile ?
Deuxième essai. Cette fois l'application démarre, la barre de progression avance… et s'arrête :
ERROR_CODE = 21
invalid delta magicTraduction : « ce que je lis ne ressemble pas à une mise à jour ». Nouvelle plongée dans le code décompilé, et découverte assez stupéfiante : l'application ne cherche jamais le fichier de la charge utile dans l'archive. Elle lit sa position en octets dans un champ de la métadonnée. Si ce champ est absent, elle lit à partir du début du fichier — c'est-à-dire n'importe où.
ota-property-files=payload.bin:<decalage>:<taille>,…Et là se pose un joli problème de serpent qui se mord la queue : la position de la charge utile dépend de la longueur de la métadonnée, laquelle change dès qu'on y écrit cette position. Écrire le chiffre déplace ce qu'on est en train de mesurer.
La solution tient en deux passes. On assemble une première fois avec un gabarit de longueur fixe — des zéros, mais le bon nombre de zéros. On mesure les positions réelles. On réassemble en y inscrivant les vraies valeurs, complétées par des espaces pour que la longueur ne bouge pas d'un caractère. Puis on vérifie que les positions n'ont effectivement pas bougé.
Troisième porte : la signature qu'on ne voit pas
Troisième essai, troisième refus :
ERROR_CODE = 39
payload metadata signature missingSigner l'archive ne suffit pas. Le moteur de mise à jour veut aussi une signature à l'intérieur de la charge utile, qui porte sur ses propres empreintes internes. C'est documenté chez AOSP, mais du côté de la chaîne de vérification du démarrage, pas du côté du format de paquet — et quand on cherche au mauvais endroit, on ne trouve pas.
La fabrication se fait en trois temps : on extrait les empreintes de la charge utile, on les signe, on les réinjecte. Et surtout, on régénère le fichier de propriétés après la signature, sinon il décrit une charge utile qui n'existe plus.
Quatrième porte : celle qui n'apparaît qu'à la fin
Le paquet passe. L'installation va au bout. L'appareil démarre, l'image est correcte, les données sont préservées. Victoire ?
Presque. Le Play Store était absent, et les Paramètres Android apparaissaient comme une application ordinaire au milieu des autres. Deux symptômes sans rapport apparent, et pourtant une seule cause.
Android garde en mémoire une analyse des applications installées, dans un cache qu'il ne recalcule que si l'empreinte de la compilation change. Comme la mise à jour préserve les données — c'est tout son intérêt — ce cache survivait. Le système relisait donc sa propre analyse de la version précédente, et ignorait tout ce que la nouvelle apportait.
Le correctif tient en un petit script qui s'exécute très tôt au démarrage : il compare un marqueur de version posé dans l'image à celui gardé dans les données. S'ils diffèrent, il vide le cache avant qu'Android n'ait commencé à analyser quoi que ce soit.
version dans l'image : v1-20260831045953
marqueur dans /data : v1-20260831045953 -> rien a faire
(different) -> purge du cacheCe défaut-là, aucune documentation ne pouvait me l'apprendre. Il a fallu remettre le firmware d'origine, refaire la mise à jour, observer, et recommencer.
Douze partitions selon Android, quinze sur ce projecteur
Revenons un instant en arrière, sur un obstacle qui n'a rien à voir avec le format du paquet. Quand celui-ci a enfin été accepté, l'installation allait au bout : le projecteur redémarrait… et ne démarrait plus.
Un appareil A/B possède deux jeux de partitions : pendant que vous utilisez le jeu A, la mise à jour écrit dans le jeu B, puis bascule au redémarrage. Le mécanisme est robuste, c'est même son intérêt. Encore faut-il que le jeu B soit complet.
En lisant l'environnement du chargeur d'amorçage, j'y ai trouvé sa propre liste de partitions à dupliquer. Elle est plus longue que celle d'Android :
ab_partition_list = bootloader, env, boot, vendor_boot, dtbo,
vbmeta, vbmeta_system, vbmeta_vendor,
init_boot, Reserve0Trois de ces noms — bootloader, env et Reserve0 — n'existent pas dans le standard Android. Une mise à jour conforme ne les remplit donc pas. Le constructeur, lui, les confiait à un mécanisme maison qui réclame un fichier livré par un serveur… dont le domaine n'existe plus.
Résultat : le second jeu recevait douze partitions sur quinze, et démarrait avec un environnement sorti d'usine, sans commande de démarrage utilisable. Pas d'écran, pas d'USB, rien.
L'écran noir, et ce qui m'a sauvé
J'ajoute l'environnement manquant. Je réessaie. Le projecteur s'allume — et reste noir. Allumé, mais noir.
Il m'a fallu du temps pour l'admettre : la partition bootloader ne contient pas que le chargeur d'amorçage. Elle contient aussi gamma.tbl et LogoRegData.bin, c'est-à-dire l'initialisation de la dalle. Sans elle, le système démarre parfaitement et n'a simplement rien pour allumer l'image.
Ce qui m'a sauvé à chaque fois, c'est le mécanisme A/B lui-même. Au bout de quelques tentatives infructueuses, le chargeur revient tout seul au système précédent. Quatre à six coupures d'alimentation, en laissant chaque fois trente secondes, et l'appareil repart sur l'ancienne version. Sans perdre une donnée.
Quand même ce filet ne suffisait plus, il restait PhoenixSuit et le fameux câble USB A ⟷ A — celui-là même dont je voulais vous dispenser. J'y suis passé plus d'une fois.
Combien d'essais ?
Je ne les ai pas comptés. Mais je peux vous donner les jalons, et vous compterez vous-même : quatre paquets OTA refusés pour quatre raisons différentes, cinq démarrages en échec avant de comprendre l'histoire du second jeu de partitions, un écran noir qu'il a fallu diagnostiquer à l'aveugle, et plusieurs restaurations complètes par PhoenixSuit.
Chaque cycle complet — reconstruire les images, refabriquer les paquets, graver, démarrer, observer — se compte en heures.
La leçon que je retiens : lire avant de sonder
Sur l'un de ces blocages, j'ai passé un temps considérable à échafauder une hypothèse et à construire deux paquets complets pour la vérifier. Les deux ont échoué. La documentation d'AOSP réfutait mon hypothèse en trois paragraphes, et j'aurais pu les lire avant.
C'est le conseil que je donne à mes élèves et que je ne m'applique pas toujours : quand la machine vous surprend, cherchez d'abord si quelqu'un l'a écrit. Sur ce projet, les sources qui m'ont réellement fait avancer sont peu nombreuses et je les cite volontiers : la documentation Android sur les mises à jour A/B et le démarrage vérifié, le dépôt hy350max-badbox-removal pour le relevé propre à ce modèle, et le dépôt magcubic-root pour le format de conteneur Allwinner et le tableau des permissions.
Avant / après, en un tableau
Je réserve l'analyse au second article, mais il serait frustrant de refermer celui-ci sans montrer le résultat. Voici, sur des relevés faits dans les mêmes conditions — même appareil, même réseau, appareil au repos — les serveurs contactés spontanément.
| Serveur contacté | Firmware d'origine | CleanRom |
|---|---|---|
store-api.aodintech.com | 216 | 0 |
server.mphotool.com | 249 | 0 |
server2.mphotool.com | 250 | 0 |
ota.triplesai.com et ses variantes | 6 | 0 |
hmma.baidu.com, dxp.baidu.com | 8 | 0 |
stat.visionular.cn | 1 | 0 |
Sur le firmware d'origine, au repos, cela représentait environ 35 requêtes par minute. Avec une connexion réelle, une capture de paquets faite sur l'appareil lui-même ne montre plus, côté CleanRom, que des destinations appartenant à Google : les services du système et les applications que vous avez lancées vous-même. Rien d'autre.
Le détail des mesures, les conditions de chacune et surtout leurs limites — parce qu'une mesure sans ses limites ne vaut pas grand-chose — feront l'objet du second article.
Ce que je n'ai pas résolu
Un projet honnête se termine par ce qui reste ouvert.
Le contrôle de connectivité
Android vérifie régulièrement qu'il a bien accès à Internet en interrogeant une adresse témoin. Sur ce firmware, cette adresse a été remplacée par un point de terminaison chinois. Ce n'est pas une fuite de données — la requête part chez Google dans les deux cas — mais elle peut échouer ou traîner depuis l'Europe, et Android déclare alors le réseau « sans Internet ». C'est un défaut de fonctionnement plus qu'un problème de vie privée. Le correctif est identifié, il n'est pas dans cette version.
SmartTube et ses rapports de plantage
SmartTube envoie des rapports de plantage à son développeur, par le service Crashlytics de Google : pile d'appels, version de l'application, modèle d'appareil. Pas de données personnelles. C'est la seule des applications que je livre à embarquer un tel module — j'ai vérifié les cinq autres, elles n'en ont aucun. Ça se désactive dans l'application, et l'application se désinstalle comme n'importe quelle autre. Je préfère vous le dire que de vous le laisser découvrir.
Magisk qui redemande son installation
Sur la version rootée, Magisk demande au premier lancement de terminer l'installation et de redémarrer. C'est déroutant, et pourtant tout va bien : la partition de démarrage livrée est déjà modifiée, le root fonctionne dès le premier allumage. Ce que Magisk complète, c'est sa base d'autorisations.
Et je ne la livre pas exprès. Cette base associe le droit au root à des identifiants d'applications qui diffèrent d'un appareil à l'autre. La livrer toute faite reviendrait à accorder le root, chez vous, à des identifiants qui désignent de tout autres applications. Magisk doit la construire sur place. Ce qui ressemble à un défaut est ici une sécurité.

























