From 72c64688f17c79a237c2780caa3a7c2ade49d647 Mon Sep 17 00:00:00 2001 From: Workbench IA Date: Wed, 30 Sep 2026 14:38:10 +0000 Subject: [PATCH 1/3] =?UTF-8?q?Fiabiliser=20la=20reprise=20du=20simulateur?= =?UTF-8?q?=20apr=C3=A8s=20d=C3=A9placement=20des=20homes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/ipod-emu/HANDOFF.md | 25 ++++++++++++++++ contrib/ipod-emu/README.md | 21 ++++++++++++++ contrib/ipod-emu/bin/ipod-agent | 4 ++- contrib/ipod-emu/bin/ipod-emu | 47 +++++++++++++++++++++++++++---- contrib/ipod-emu/bin/ipod-qmp | 5 +++- contrib/ipod-emu/netd/ipod-netd.c | 2 ++ 6 files changed, 96 insertions(+), 8 deletions(-) diff --git a/contrib/ipod-emu/HANDOFF.md b/contrib/ipod-emu/HANDOFF.md index 4a5d494bd2..578b547cf6 100644 --- a/contrib/ipod-emu/HANDOFF.md +++ b/contrib/ipod-emu/HANDOFF.md @@ -146,3 +146,28 @@ Debug : `IPOD_QEMU_EXTRA="-d unimp,guest_errors -D ~/ipod-emu/run/int.log"` ; `I - `-f` efface la session persistée. Ne pas l'utiliser pour vérifier la conservation d'un fichier. - QEMU et netd sont lancés avec `setsid` pour survivre à la fin du terminal appelant. Le launcher suit netd par PID. - Un `.deb` 2.x qui dépend d'un jailbreak (bash, etc.) ne marchera pas : aucun shell dans l'image. + +## Reprise du 30 septembre 2026 — après déplacement des homes + +- Projets retrouvés sous `/srv/homes/iphoneos2/{ipod-emu,qemu-ios}`. +- Bibliothèques QEMU/libslirp et ImageMagick réinstallées dans le conteneur courant ; + lien BootROM 5H11a corrigé en relatif ; commandes accessibles par wrappers dans + `/home/dev/.local/bin`. Ces installations locales ne modifient pas l'image Docker. +- Lanceur adapté aux chemins déplacés, sélection automatique des keymaps via `-L`, + contrôle du démarrage QEMU et du relais, nettoyage du relais même après arrêt QEMU. + `ipod-qmp` prend en compte `IPOD_EMU_HOME`. +- Test sur une copie de NAND dans `ipod-emu/work/reprise-20260930` : boot de l'image + de base en 28 s, Safari et HTTP validés. `push-app HelloEmu.app` copie les deux + fichiers, redémarre sans réinitialiser la NAND ; HelloEmu apparaît ensuite dans + le catalogue `apps`. Le lancement répond toujours `device locked`, écran noir. + Le programme de diagnostic `unlock` retourne 0 sans débloquer le lancement. + Ne pas considérer le lancement après installation comme validé. +- La copie de la session initiale est conservée dans + `work/reprise-20260930/run-session-initiale` ; la session d'origine `run/nand` + n'a pas été modifiée. Les captures et préférences de diagnostic sont dans le + dossier de reprise. Les sessions de test ont été arrêtées. +- Un ancien relais survivant à QEMU occupait 7788 : supprimé avant de refaire le + test. L'ancien code continuait malgré l'échec de redirection ; le nouveau échoue. +- Vérifications : syntaxe Bash/Python, compilation du relais avec `-Wall`, + échec QEMU volontaire détecté immédiatement, port 7788 occupé détecté et QEMU + arrêté, `stop` après échec. Aucun changement des modèles matériels dans cette reprise. diff --git a/contrib/ipod-emu/README.md b/contrib/ipod-emu/README.md index 4e39e1c416..f724248df2 100644 --- a/contrib/ipod-emu/README.md +++ b/contrib/ipod-emu/README.md @@ -3,6 +3,27 @@ Émulateur [qemu-ios](https://git.mahtan-melwasul.com/Mahtan/qemu-ios) (branche iPod Touch 2G, N72AP), adapté pour démarrer **iPhone OS 2.2.1 (5H11a)**. iPhone OS 2.1.1 (5F138) reste disponible. Les outils sont dans `/opt/ios-legacy/bin`. +## Environnement déplacé + +Dans le workbench actuel, les projets sont sous `/srv/homes/iphoneos2` : +`ipod-emu` contient les images et les outils, `qemu-ios` contient QEMU. +Les outils utilisés directement depuis `ipod-emu/bin` retrouvent ce dossier ; +le lanceur cherche QEMU dans le dossier voisin et transmet son dossier `pc-bios` +pour retrouver les keymaps VNC après déplacement. `IPOD_EMU_HOME`, `IPOD_QEMU`, +`IPOD_QEMU_DATA` et `IPOD_QMP` permettent de choisir d'autres chemins. +`ipod-qmp` respecte également `IPOD_EMU_HOME` pour le socket de session. + +Vérifier les liens symboliques des images après déplacement : le lien de +`images/5H11a/bootrom` doit viser `../5F138/bootrom`, plutôt qu'un ancien home absolu. +Sur Arch, le binaire construit dans cet environnement utilise notamment `pixman`, +`libpng`, `libjpeg-turbo`, `sdl2` et `libslirp` ; les captures PNG utilisent +`imagemagick`. Compiler le relais réseau demande aussi `pkgconf` et `glib2-devel`. +Ces dépendances doivent être présentes dans chaque nouveau conteneur. + +Le lanceur échoue explicitement si QEMU ou le relais réseau s'arrête au démarrage. +Un port agent déjà occupé est une erreur : le relais ne poursuit plus sans sa +redirection. `stop` nettoie le relais suivi par PID même si QEMU est déjà arrêté. + ## Utilisation ```bash diff --git a/contrib/ipod-emu/bin/ipod-agent b/contrib/ipod-emu/bin/ipod-agent index 7956143ce5..a842222167 100755 --- a/contrib/ipod-emu/bin/ipod-agent +++ b/contrib/ipod-emu/bin/ipod-agent @@ -52,7 +52,9 @@ def out(body): def push_app(a, app): - emu_home = os.environ.get("IPOD_EMU_HOME", os.path.expanduser("~/ipod-emu")) + tools_home = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + default_home = tools_home if os.path.isdir(os.path.join(tools_home, "images")) else os.path.expanduser("~/ipod-emu") + emu_home = os.environ.get("IPOD_EMU_HOME", default_home) run = os.path.join(emu_home, "run") try: with open(os.path.join(run, "nand", ".ipod-nand-format")) as f: diff --git a/contrib/ipod-emu/bin/ipod-emu b/contrib/ipod-emu/bin/ipod-emu index 0bbb3cdf56..d86c1fe72d 100755 --- a/contrib/ipod-emu/bin/ipod-emu +++ b/contrib/ipod-emu/bin/ipod-emu @@ -2,8 +2,13 @@ # Lance / arrête l'émulateur iPod Touch 2G (qemu-ios, N72AP). set -euo pipefail -EMU_HOME="${IPOD_EMU_HOME:-$HOME/ipod-emu}" -QEMU="${IPOD_QEMU:-$HOME/qemu-ios/build/qemu-system-arm}" +TOOLS_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +DEFAULT_EMU_HOME="$HOME/ipod-emu" +# Les outils peuvent être utilisés directement depuis un home de toolchain déplacé. +[ ! -d "$TOOLS_DIR/../images" ] || DEFAULT_EMU_HOME=$(cd "$TOOLS_DIR/.." && pwd) +EMU_HOME="${IPOD_EMU_HOME:-$DEFAULT_EMU_HOME}" +QEMU="${IPOD_QEMU:-$(dirname "$EMU_HOME")/qemu-ios/build/qemu-system-arm}" +QEMU_DATA="${IPOD_QEMU_DATA:-$(dirname "$(dirname "$QEMU")")/pc-bios}" FW="${IPOD_FW:-5H11a}" # dossier $EMU_HOME/images// : bootrom, nor.bin, nand/ (5H11a = 2.2.1, 5F138 = 2.1.1) RUN="$EMU_HOME/run" VNC="${IPOD_VNC:-127.0.0.1:0}" # :0 => port 5900 @@ -62,10 +67,17 @@ start) img="$EMU_HOME/images/$FW" [ -d "$img" ] || { echo "Firmware inconnu : $img" >&2; exit 1; } [ -z "$(pid)" ] || { echo "Déjà lancé (pid $(pid))"; exit 0; } + [ -x "$QEMU" ] || { echo "QEMU introuvable : $QEMU (définir IPOD_QEMU)" >&2; exit 1; } + [ -r "$img/bootrom" ] || { echo "BootROM introuvable : $img/bootrom (vérifier les liens après déplacement du home)" >&2; exit 1; } + [ -x "$EMU_HOME/netd/ipod-netd" ] || { echo "Relais réseau introuvable : $EMU_HOME/netd/ipod-netd" >&2; exit 1; } + "$QEMU" --version >/dev/null + qemu_data_args=() + [ ! -d "$QEMU_DATA/keymaps" ] || qemu_data_args=(-L "$QEMU_DATA") mkdir -p "$RUN" if [ $fresh = 1 ] || [ ! -d "$RUN/nand" ] || [ "$(cat "$RUN/fw" 2>/dev/null)" != "$FW" ]; then rm -rf "$RUN/nand"; cp -rL "$img/nand" "$RUN/nand"; echo "$FW" > "$RUN/fw" fi + stop_netd rm -f "$RUN/qmp.sock" "$RUN/serial.log" mopts=$(cat "$img/machine-opts" 2>/dev/null || true) # ex. ",legacy-nor=off" if [[ "$mopts" == *",nand-write=on"* ]] && @@ -74,21 +86,44 @@ start) exit 1 fi nohup setsid "$QEMU" -M "iPod-Touch,bootrom=$img/bootrom,nand=$RUN/nand,nor=$img/nor.bin$mopts" \ - -cpu max -m 2G -serial "file:$RUN/serial.log" -serial "unix:$RUN/uart1.sock,server=on,wait=off" \ + "${qemu_data_args[@]}" -cpu max -m 2G -serial "file:$RUN/serial.log" -serial "unix:$RUN/uart1.sock,server=on,wait=off" \ -display none -vnc "$VNC" -qmp "unix:$RUN/qmp.sock,server,nowait" \ -pidfile "$RUN/qemu.pid" ${IPOD_QEMU_EXTRA:-} > "$RUN/qemu.log" 2>&1 & - for _ in $(seq 50); do [ -S "$RUN/qmp.sock" ] && break; sleep 0.2; done + qemu_pid=$! + for _ in $(seq 50); do + if ! kill -0 "$qemu_pid" 2>/dev/null; then + echo "Échec du démarrage de QEMU :" >&2 + cat "$RUN/qemu.log" >&2 + exit 1 + fi + [ ! -S "$RUN/qmp.sock" ] || [ -z "$(pid)" ] || break + sleep 0.2 + done + if [ ! -S "$RUN/qmp.sock" ] || [ -z "$(pid)" ]; then + kill "$qemu_pid" 2>/dev/null || true + echo "QEMU n'a pas ouvert son socket QMP (voir $RUN/qemu.log)" >&2 + exit 1 + fi # réseau : PPP sur l'UART1 -> slirp (NAT, DNS, 127.0.0.1:7788 -> agent de l'iPod) stop_netd nohup setsid "$EMU_HOME/netd/ipod-netd" -s "$RUN/uart1.sock" ${IPOD_NETD_FWD:-} > "$RUN/netd.log" 2>&1 & - echo "$!" > "$RUN/netd.pid" + netd_pid=$! + echo "$netd_pid" > "$RUN/netd.pid" + sleep 0.3 + if ! kill -0 "$netd_pid" 2>/dev/null; then + echo "Échec du relais réseau :" >&2 + cat "$RUN/netd.log" >&2 + "$(dirname "$0")/ipod-qmp" -s "$RUN/qmp.sock" quit 2>/dev/null || kill "$qemu_pid" + stop_netd + exit 1 + fi echo "Démarré ($FW) — pid $(pid), VNC $VNC. SpringBoard apparaît en ~1 min." echo "Logs iOS : $RUN/serial.log" [ $waitr = 0 ] || wait_ready ;; wait) wait_ready "${1:-300}" ;; stop) - p=$(pid) || { echo "Pas lancé"; exit 0; } + p=$(pid) || { stop_netd; echo "Pas lancé"; exit 0; } "$(dirname "$0")/ipod-qmp" -s "$RUN/qmp.sock" quit 2>/dev/null || kill "$p" for _ in $(seq 50); do kill -0 "$p" 2>/dev/null || break; sleep 0.2; done kill -0 "$p" 2>/dev/null && kill -9 "$p" diff --git a/contrib/ipod-emu/bin/ipod-qmp b/contrib/ipod-emu/bin/ipod-qmp index 5ffb2ddb1a..708cd3cf30 100755 --- a/contrib/ipod-emu/bin/ipod-qmp +++ b/contrib/ipod-emu/bin/ipod-qmp @@ -59,7 +59,10 @@ def key(q, qcode): def main(): p = argparse.ArgumentParser(usage=__doc__) - p.add_argument("-s", "--sock", default=os.environ.get("IPOD_QMP", os.path.expanduser("~/ipod-emu/run/qmp.sock"))) + tools_home = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + default_home = tools_home if os.path.isdir(os.path.join(tools_home, "images")) else os.path.expanduser("~/ipod-emu") + emu_home = os.environ.get("IPOD_EMU_HOME", default_home) + p.add_argument("-s", "--sock", default=os.environ.get("IPOD_QMP", os.path.join(emu_home, "run", "qmp.sock"))) p.add_argument("action") p.add_argument("args", nargs="*") a = p.parse_args() diff --git a/contrib/ipod-emu/netd/ipod-netd.c b/contrib/ipod-emu/netd/ipod-netd.c index 24aed56d3a..ae34d99243 100644 --- a/contrib/ipod-emu/netd/ipod-netd.c +++ b/contrib/ipod-emu/netd/ipod-netd.c @@ -556,6 +556,8 @@ static void add_fwd(const char *spec) } if (slirp_add_hostfwd(slirp, 0, host, hp, guest, gp) < 0) { logm("redirection %s impossible (port occupé ?)", spec); + /* Ne pas laisser le client contacter le relais d'une autre session. */ + exit(1); } else { logm("redirection tcp %s:%d -> iPod:%d", inet_ntoa(host), hp, gp); } -- 2.54.0 From e28583407affa8618a10f18c71471214a4033491 Mon Sep 17 00:00:00 2001 From: Workbench IA Date: Wed, 30 Sep 2026 15:08:21 +0000 Subject: [PATCH 2/3] =?UTF-8?q?D=C3=A9verrouiller=20SpringBoard=20avant=20?= =?UTF-8?q?le=20lancement=20des=20applications?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/ipod-emu/HANDOFF.md | 24 +++++++++++++ contrib/ipod-emu/README.md | 44 +++++++++++++++++++---- contrib/ipod-emu/agent/emuagent.c | 32 +++++++++++++++-- contrib/ipod-emu/bin/ipod-agent | 60 ++++++++++++++++++++++++++++--- contrib/ipod-emu/bin/ipod-emu | 4 ++- 5 files changed, 151 insertions(+), 13 deletions(-) diff --git a/contrib/ipod-emu/HANDOFF.md b/contrib/ipod-emu/HANDOFF.md index 578b547cf6..dc98d9ca2c 100644 --- a/contrib/ipod-emu/HANDOFF.md +++ b/contrib/ipod-emu/HANDOFF.md @@ -171,3 +171,27 @@ Debug : `IPOD_QEMU_EXTRA="-d unimp,guest_errors -D ~/ipod-emu/run/int.log"` ; `I - Vérifications : syntaxe Bash/Python, compilation du relais avec `-Wall`, échec QEMU volontaire détecté immédiatement, port 7788 occupé détecté et QEMU arrêté, `stop` après échec. Aucun changement des modèles matériels dans cette reprise. + +## Correction du verrouillage — agent v11 + +- `SBGetScreenLockStatus` confirme `locked=1 passcode=0` après redémarrage. + `SBApplicationRequestedDeviceUnlock` réveille un clavier de code sans déverrouiller. +- Solution validée : `SBDimScreen(port, false)`, attendre deux secondes, glisser + `(60,450)` → `(319,450)`, attendre deux secondes, vérifier `locked=0`. + Le geste historique `(40,430)` → `(280,430)` n'atteint pas correctement le bord + de la surface tactile émulée. Home/Power et gestes lors de la reprise du pilote + peuvent encore provoquer un arrêt QEMU ; aucun correctif matériel n'est revendiqué. +- Agent v11 : commandes `screen` et `wake`. Client : `unlock`, vérification des + marqueurs de disponibilité, refus si un code est actif, trois essais maximum. + `start -W` / `wait` ne rendent la main avec succès qu'après déverrouillage. +- Validations sans débogueur sur la session copiée : démarrage en 36 s ; nouvelle + installation de HelloEmu avec `push-app`, redémarrage conservant la NAND en 47 s, + `launch` réussi et `front` = `com.allovoisins.helloemu`. Capture : + `work/reprise-20260930/hello-v11-apres-push.png`. +- L'agent v11 a été installé atomiquement dans la session de test puis synchronisé + avant redémarrage ; aucune relance à chaud de l'agent/PPP. + Nouvelle image `images/5H11a-agent-v11` construite avec l'overlay de l'agent, + sans modifier l'image 5H11a ni la NAND d'origine. L'image de base v10 doit être + mise à jour avant d'utiliser le déverrouillage automatique. +- La faute `diff_y` utilisant `x` dans `get_frame` reste à étudier séparément ; + elle n'a pas été modifiée pour cette validation. diff --git a/contrib/ipod-emu/README.md b/contrib/ipod-emu/README.md index f724248df2..41b7d0a8e0 100644 --- a/contrib/ipod-emu/README.md +++ b/contrib/ipod-emu/README.md @@ -1,7 +1,7 @@ # Simulateur iPod Touch 2G (iPhone OS 2.2.1) Émulateur [qemu-ios](https://git.mahtan-melwasul.com/Mahtan/qemu-ios) (branche iPod Touch 2G, N72AP), adapté pour -démarrer **iPhone OS 2.2.1 (5H11a)**. iPhone OS 2.1.1 (5F138) reste disponible. Les outils sont dans `/opt/ios-legacy/bin`. +démarrer **iPhone OS 2.2.1 (5H11a)**. iPhone OS 2.1.1 (5F138) reste disponible. Les outils sont dans `ipod-emu/bin` ; dans le workbench actuel, des wrappers les exposent via `/home/dev/.local/bin`. ## Environnement déplacé @@ -27,7 +27,7 @@ redirection. `stop` nettoie le relais suivi par PID même si QEMU est déjà arr ## Utilisation ```bash -ipod-emu start -W # démarre 2.2.1 en conservant la NAND et attend SpringBoard (~25–50 s) +ipod-emu start -W # agent v11 : conserve la NAND, attend SpringBoard et déverrouille (~35–50 s) # Ajouter -f uniquement pour remettre la NAND à zéro. ipod-qmp screenshot ecran.png # capture 320x480 ipod-qmp tap 160 326 # touche (coordonnées écran), ipod-qmp tap X Y 1.5 = appui long @@ -42,11 +42,41 @@ ipod-emu stop - VNC sur `127.0.0.1:5900` pour interagir à la main (tunnel SSH : `ssh -L 5900:127.0.0.1:5900 …`). - Le lancement d'une app prend 10-20 s. +## Déverrouillage après redémarrage + +Avec l'agent **v11**, `start -W` et `wait` vérifient le verrouillage, réveillent +l'écran et effectuent le glissement normal avant de rendre la main. +`ipod-agent screen` retourne `locked=0 passcode=0` une fois déverrouillé ; +`ipod-agent unlock` permet de refaire ce parcours après démarrage. +Si un code est activé, le client s'arrête et demande un déverrouillage manuel. +Aucun geste n'est envoyé avant les marqueurs de démarrage du pilote tactile. + +Le réveil utilise `SBDimScreen(port, false)`, puis un glissement de `(60,450)` +à `(319,450)` adapté à la surface tactile du modèle. Le client laisse deux +secondes au réveil et à la fin du geste, puis vérifie le verrouillage ; trois +essais maximum. `SBApplicationRequestedDeviceUnlock` affiche le clavier de code +sur 2.2.1 même sans code actif : ce n'est pas le parcours utilisé. + +Une image contenant l'agent v10 doit être mise à jour avant d'utiliser ce workflow. +Créer une image distincte préserve l'image de base : + +```bash +cd /srv/homes/iphoneos2/ipod-emu/agent +PATH=/opt/cctools/bin:$PATH make +ipod-mkimage -o 5H11a-agent-v11 overlay +``` + +Le firmware se choisit avec `start -w 5H11a-agent-v11 -W`. Attention : comme pour +tout changement de firmware, cette commande remplace la NAND du dossier `run` ; +conserver sa session précédente ou utiliser un environnement de test séparé. +Le dossier de diagnostic `work/reprise-20260930` conserve une session avec l'agent +v11 et HelloEmu, indépendante de la session d'origine. + ## Tester nos apps ```bash -ipod-mkimage MonApp.app autre.ipa paquet.deb # -> images/5H11a-apps (base : -b 5H11a ou -b 5F138) -ipod-emu start -f -W -w 5H11a-apps +ipod-mkimage -b 5H11a-agent-v11 MonApp.app autre.ipa paquet.deb # -> images/5H11a-agent-v11-apps +ipod-emu start -f -W -w 5H11a-agent-v11-apps ipod-agent launch com.exemple.monapp --log /private/var/mobile/monapp.log ipod-agent get /private/var/mobile/monapp.log @@ -72,8 +102,10 @@ la toolchain de l'environnement (`arm-apple-darwin9-gcc -isysroot /opt/theos/sdk avant la fin du démarrage de SpringBoard. L'image de base est en français, région France, fuseau Europe/Paris. - **Relance de SpringBoard** : `respring` peut bloquer la reconstruction du catalogue d'apps. `push-app` redémarre - donc l'émulateur. Après un redémarrage d'une session conservée, le verrouillage iOS peut encore empêcher un - lancement (`device locked`) ; le lancement d'une app installée ainsi n'est pas encore validé. + donc l'émulateur sans reconstruire l'image ni réinitialiser la NAND. Avec l'agent v11, le déverrouillage puis + le lancement de HelloEmu au premier plan sont validés après cette installation. Les gestes Home/Power restent + susceptibles de déclencher un défaut du pilote lors de la reprise de l'écran ; le workflow automatique utilise + le réveil par l'API d'affichage et vérifie le verrouillage. - **Veille** : l'agent v10 pose `SleepDisabled` sur `IOPMrootDomain`, le SoC ne sachant pas reprendre une veille profonde. - Pas de son, pas d'accélération graphique (SpringBoard tourne avec `LK_ENABLE_MBX2D=0`). diff --git a/contrib/ipod-emu/agent/emuagent.c b/contrib/ipod-emu/agent/emuagent.c index 1ab9b477cb..a9d17060b9 100644 --- a/contrib/ipod-emu/agent/emuagent.c +++ b/contrib/ipod-emu/agent/emuagent.c @@ -67,7 +67,7 @@ struct rt_msghdr { #include #include -#define VERSION "10" +#define VERSION "11" #define PORT 7788 #define PPP_TTY "/dev/tty.bluetooth" #define GUEST_IP "10.0.2.15" @@ -332,6 +332,9 @@ static void cmd_exec(int fd, char **args, int nargs) static int (*p_SBSLaunchApplication)(CFStringRef, CFURLRef, CFArrayRef, CFDictionaryRef, CFStringRef, CFStringRef, unsigned); static CFStringRef (*p_SBSApplicationLaunchingErrorString)(int); static CFStringRef (*p_SBSCopyFrontmostApplicationDisplayIdentifier)(void); +static unsigned (*p_SBSSpringBoardServerPort)(void); +static int (*p_SBGetScreenLockStatus)(unsigned, unsigned char *, unsigned char *); +static int (*p_SBDimScreen)(unsigned, unsigned char); static void load_sbs(void) { @@ -339,6 +342,9 @@ static void load_sbs(void) if (h) return; h = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_NOW); if (!h) return; + p_SBSSpringBoardServerPort = dlsym(h, "SBSSpringBoardServerPort"); + p_SBGetScreenLockStatus = dlsym(h, "SBGetScreenLockStatus"); + p_SBDimScreen = dlsym(h, "SBDimScreen"); p_SBSLaunchApplication = dlsym(h, "SBSLaunchApplication"); p_SBSApplicationLaunchingErrorString = dlsym(h, "SBSApplicationLaunchingErrorString"); p_SBSCopyFrontmostApplicationDisplayIdentifier = dlsym(h, "SBSCopyFrontmostApplicationDisplayIdentifier"); @@ -350,6 +356,26 @@ static void cfstr(CFStringRef s, char *out, size_t len) if (s) CFStringGetCString(s, out, len, kCFStringEncodingUTF8); } +/* API MIG du firmware 2.2.1 : les deux états sont des octets, retour kern_return_t. */ +static void cmd_screen(int fd, int wake) +{ + load_sbs(); + if (!p_SBSSpringBoardServerPort || !p_SBGetScreenLockStatus || !p_SBDimScreen) { + reply_str(fd, 0, "API d'écran indisponible"); return; + } + unsigned port = p_SBSSpringBoardServerPort(); + unsigned char locked = 0, passcode = 0; + int rc = p_SBGetScreenLockStatus(port, &locked, &passcode); + if (rc) { reply_str(fd, 0, "SBGetScreenLockStatus : %d", rc); return; } + if (wake) { + /* SBApplicationRequestedDeviceUnlock affiche le clavier de code même + sans code activé. Réveiller seulement l'écran, puis glisser côté hôte. */ + rc = p_SBDimScreen(port, 0); + if (rc) { reply_str(fd, 0, "SBDimScreen : %d", rc); return; } + } + reply_str(fd, 1, "locked=%u passcode=%u", locked, passcode); +} + static void cmd_launch(int fd, char **args, int nargs) { load_sbs(); @@ -710,6 +736,8 @@ static void handle(int fd, char *line) else if (!strcmp(cmd, "exec")) cmd_exec(fd, a, na); else if (!strcmp(cmd, "launch")) cmd_launch(fd, a, na); else if (!strcmp(cmd, "front")) cmd_front(fd); + else if (!strcmp(cmd, "screen")) cmd_screen(fd, 0); + else if (!strcmp(cmd, "wake")) cmd_screen(fd, 1); else if (!strcmp(cmd, "fetch")) cmd_fetch(fd, a, na); else if (!strcmp(cmd, "sc")) cmd_sc(fd, a, na); else if (!strcmp(cmd, "routes")) cmd_routes(fd); @@ -733,7 +761,7 @@ static void handle(int fd, char *line) else if (!strcmp(cmd, "net")) cmd_net(fd); else if (!strcmp(cmd, "respring")) reply_str(fd, kill_by_name("SpringBoard", SIGTERM) > 0, "SpringBoard relancé"); else if (!strcmp(cmd, "sync")) { sync(); reply_str(fd, 1, "ok"); } - else reply_str(fd, 0, "commande inconnue : %s (ping exec launch fetch sc routes settime front apps put get ls rm mkdir ps kill net respring sync)", cmd); + else reply_str(fd, 0, "commande inconnue : %s (ping exec launch fetch sc routes settime screen wake front apps put get ls rm mkdir ps kill net respring sync)", cmd); } static void serve_client(int fd) diff --git a/contrib/ipod-emu/bin/ipod-agent b/contrib/ipod-emu/bin/ipod-agent index a842222167..fa6dc78b93 100755 --- a/contrib/ipod-emu/bin/ipod-agent +++ b/contrib/ipod-emu/bin/ipod-agent @@ -7,6 +7,8 @@ lance une app (stdout/stderr, donc NSLog, dans F sur l'iPod ; URL à ouvrir) ipod-agent fetch http://hôte/chemin requête HTTP depuis l'iPod (test réseau : DNS + TCP) ipod-agent front app au premier plan + ipod-agent screen | wake état du verrouillage / réveil sans clavier de code (agent v11) + ipod-agent unlock réveille puis glisse et vérifie le déverrouillage (sans code) ipod-agent exec PROG [ARGS...] exécute un programme (pas de shell : chemin absolu) ipod-agent ps | net | respring | sync ipod-agent kill PID|NOM [SIGNAL] @@ -51,17 +53,63 @@ def out(body): sys.stdout.buffer.write(b"\n") -def push_app(a, app): +def emu_home(): tools_home = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) default_home = tools_home if os.path.isdir(os.path.join(tools_home, "images")) else os.path.expanduser("~/ipod-emu") - emu_home = os.environ.get("IPOD_EMU_HOME", default_home) - run = os.path.join(emu_home, "run") + return os.environ.get("IPOD_EMU_HOME", default_home) + + +def unlock(a): + def screen(): + ok, body, _ = a.call("screen") + if not ok: + sys.exit("État d'écran indisponible (agent v11 requis) : " + body.decode()) + return dict(field.split("=", 1) for field in body.decode().split()) + + state = screen() + if state.get("locked") == "0": + print("Écran déverrouillé") + return + if state.get("passcode") != "0": + sys.exit("Un code de verrouillage est activé : déverrouiller manuellement.") + # Le pilote tactile doit avoir terminé son démarrage avant tout glissement. + try: + with open(os.path.join(emu_home(), "run", "serial.log"), "rb") as f: + serial = f.read() + except OSError as e: + sys.exit(f"Console de session inaccessible : {e}") + helper_ready = any(b"SCHelper" in line and b'"EXIT"' in line for line in serial.splitlines()) + if serial.count(b"AppleMultitouchSPIUserClient::attach") < 2 or not helper_ready: + sys.exit("Contrôleur tactile pas encore prêt : attendre ipod-emu wait.") + qmp = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ipod-qmp") + sock = os.environ.get("IPOD_QMP", os.path.join(emu_home(), "run", "qmp.sock")) + for attempt in range(3): + ok, body, _ = a.call("wake") + if not ok: + sys.exit(body.decode()) + time.sleep(2) # laisser le pilote réactiver l'écran et le tactile + # La surface tactile émulée est légèrement plus petite que l'écran : + # le geste doit atteindre le bord droit pour terminer le déverrouillage. + subprocess.run([qmp, "-s", sock, "swipe", "60", "450", "319", "450"], check=True) + time.sleep(2) + state = screen() + if state.get("locked") == "0": + print("Écran déverrouillé") + return + if state.get("passcode") != "0": + sys.exit("Un code de verrouillage est activé : déverrouiller manuellement.") + sys.exit("Écran toujours verrouillé après trois glissements.") + + +def push_app(a, app): + home = emu_home() + run = os.path.join(home, "run") try: with open(os.path.join(run, "nand", ".ipod-nand-format")) as f: layout = f.read().strip() with open(os.path.join(run, "fw")) as f: firmware = f.read().strip() - with open(os.path.join(emu_home, "images", firmware, "machine-opts")) as f: + with open(os.path.join(home, "images", firmware, "machine-opts")) as f: machine_opts = f.read() except OSError: sys.exit("push-app nécessite une image locale avec persistance NAND (ipod-mkimage / ipod-build-fw).") @@ -122,6 +170,10 @@ def main(): except OSError as e: sys.exit(f"agent injoignable sur {HOST}:{PORT} ({e}) — ipod-netd lancé ?") + if cmd == "unlock": + a.s.settimeout(15) + unlock(a) + return if cmd == "get": ok, body, _ = a.call("get", rest[0]) if not ok: diff --git a/contrib/ipod-emu/bin/ipod-emu b/contrib/ipod-emu/bin/ipod-emu index d86c1fe72d..f1b1ed9b8b 100755 --- a/contrib/ipod-emu/bin/ipod-emu +++ b/contrib/ipod-emu/bin/ipod-emu @@ -44,7 +44,9 @@ wait_ready() { [ $((SECONDS - s)) -lt "$t" ] || { echo "Timeout : SpringBoard pas prêt après ${t}s" >&2; return 1; } sleep 2 done - sleep 3; echo "SpringBoard prêt ($((SECONDS - s)) s)" + sleep 3 + "$(dirname "$0")/ipod-agent" unlock + echo "SpringBoard prêt et déverrouillé ($((SECONDS - s)) s)" } pid() { [ -f "$RUN/qemu.pid" ] && kill -0 "$(cat "$RUN/qemu.pid")" 2>/dev/null && cat "$RUN/qemu.pid"; } -- 2.54.0 From 7b6afeb4776874abf6bf10a2cc08a797964b1040 Mon Sep 17 00:00:00 2001 From: Workbench IA Date: Wed, 30 Sep 2026 15:12:13 +0000 Subject: [PATCH 3/3] =?UTF-8?q?Attendre=20le=20d=C3=A9verrouillage=20d?= =?UTF-8?q?=E2=80=99une=20session=20d=C3=A9j=C3=A0=20lanc=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/ipod-emu/HANDOFF.md | 7 +++++++ contrib/ipod-emu/bin/ipod-emu | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/contrib/ipod-emu/HANDOFF.md b/contrib/ipod-emu/HANDOFF.md index dc98d9ca2c..e9db8228eb 100644 --- a/contrib/ipod-emu/HANDOFF.md +++ b/contrib/ipod-emu/HANDOFF.md @@ -195,3 +195,10 @@ Debug : `IPOD_QEMU_EXTRA="-d unimp,guest_errors -D ~/ipod-emu/run/int.log"` ; `I mise à jour avant d'utiliser le déverrouillage automatique. - La faute `diff_y` utilisant `x` dans `get_frame` reste à étudier séparément ; elle n'a pas été modifiée pour cette validation. + +## Relecture avant merge + +- Corrigé `start -W` sur une session déjà lancée : attendre et vérifier le + déverrouillage avant de rendre la main, au lieu de retourner immédiatement. +- Image distincte 5H11a-agent-v11 démarrée et déverrouillée en 27 s ; agent v11 + confirmé. Les deux sessions de test antérieures sont conservées séparément. diff --git a/contrib/ipod-emu/bin/ipod-emu b/contrib/ipod-emu/bin/ipod-emu index f1b1ed9b8b..41988316f4 100755 --- a/contrib/ipod-emu/bin/ipod-emu +++ b/contrib/ipod-emu/bin/ipod-emu @@ -68,7 +68,11 @@ start) while getopts "fWw:" o; do case $o in f) fresh=1 ;; W) waitr=1 ;; w) FW=$OPTARG ;; *) usage 1 ;; esac; done img="$EMU_HOME/images/$FW" [ -d "$img" ] || { echo "Firmware inconnu : $img" >&2; exit 1; } - [ -z "$(pid)" ] || { echo "Déjà lancé (pid $(pid))"; exit 0; } + if [ -n "$(pid)" ]; then + echo "Déjà lancé (pid $(pid))" + [ $waitr = 0 ] || wait_ready + exit 0 + fi [ -x "$QEMU" ] || { echo "QEMU introuvable : $QEMU (définir IPOD_QEMU)" >&2; exit 1; } [ -r "$img/bootrom" ] || { echo "BootROM introuvable : $img/bootrom (vérifier les liens après déplacement du home)" >&2; exit 1; } [ -x "$EMU_HOME/netd/ipod-netd" ] || { echo "Relais réseau introuvable : $EMU_HOME/netd/ipod-netd" >&2; exit 1; } -- 2.54.0