atuq: en la imagen el navegador SÍ pinta — la segunda pantalla no era
La sospecha salía del propio serial: el arranque del §6.10.ter veía DOS dispositivos DRM
(`drm: card0 card1 renderD128`) y uno nuevo ve uno solo. Sin `-vga none`, QEMU agrega una VGA
estándar además del virtio-gpu, OVMF pinta su GOP ahí y el kernel levanta simpledrm encima: un
compositor con dos tarjetas puede componer en la que el `screendump` no muestra, y eso se ve igual
que «la ventana no aparece». Por eso el guion lleva `VGA=1`, para pedir ese caso por su nombre.
Medido con las dos configuraciones y el mismo lanzamiento:
-vga none → card0 → 703766 px magenta
VGA=1 → card0 card1 → 703766 px magenta
El mismo número al píxel. La ventana aparece —panel, dock y el navegador con su barra lateral—,
`nsWindow::Create() Toplevel` está en el MOZ_LOG, la superficie se mapea y `mIsFullyOccluded 0`, con
`WaylandBufferSHM` de 1280x696, el mismo camino de buffers que bajo sway.
⇒ la segunda pantalla no es la causa. Queda una sola diferencia con aquella corrida: cómo se lanzó
el navegador. Acá va con perfil nuevo y MOZ_ENABLE_WAYLAND puesto; allá fue un `atuq` pelado con su
perfil por defecto tecleado en el serial. Para eso está `--como-usuario`, que es la corrida que sigue.
⚠ Dos trampas del arnés, medidas y escritas en el guion: el terminal hace ECO de lo que se le
escribe, así que una marca de fin literal se lee en el eco y las órdenes se pisan; y `cmd & ; echo`
es error de sintaxis en ash ⇒ el navegador no se lanzó y la corrida siguió dando capturas de un
escritorio vacío, que se leen igual que el fallo que se investiga.
This commit is contained in:
@@ -25,6 +25,10 @@ causa.
|
||||
"""
|
||||
import argparse, json, os, shutil, socket, subprocess, sys, time
|
||||
|
||||
# Sin esto la salida sale por tandas cuando se redirige a un fichero, y una corrida de 20 minutos se
|
||||
# lee como si estuviera colgada.
|
||||
sys.stdout.reconfigure(line_buffering=True)
|
||||
|
||||
RAIZ = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
IMG = os.environ.get("IMG", "/mnt/cosecha/takana-cosmic-qemu.img")
|
||||
OVMF_CODE = os.environ.get("OVMF_CODE", "/usr/share/edk2/x64/OVMF_CODE.4m.fd")
|
||||
@@ -32,6 +36,18 @@ OVMF_VARS = os.environ.get("OVMF_VARS", "/usr/share/edk2/x64/OVMF_VARS.4m.fd")
|
||||
MEM = os.environ.get("MEM", "2560")
|
||||
SMP = os.environ.get("SMP", "2")
|
||||
|
||||
# ⚠ `VGA=1` reproduce el arranque del §6.10.ter, y la diferencia NO es cosmética: sin `-vga none`,
|
||||
# QEMU agrega una VGA estándar ADEMÁS del virtio-gpu, OVMF pinta su GOP ahí y el kernel levanta
|
||||
# `simpledrm` encima ⇒ el guest ve DOS dispositivos DRM. En el serial se lee tal cual:
|
||||
#
|
||||
# == cosmic :: kernel 6.16.12 · drm: card0 card1 renderD128 (corrida del §6.10.ter)
|
||||
# == cosmic :: kernel 6.16.12 · drm: card0 renderD128 (con -vga none)
|
||||
#
|
||||
# Un compositor con dos tarjetas puede componer en la que el `screendump` NO muestra. Por eso el
|
||||
# default acá es UNA sola (-vga none) y la reproducción del caso original es una opción explícita:
|
||||
# son dos mediciones distintas y hay que poder pedir cada una por su nombre.
|
||||
VGA_ARGS = [] if os.environ.get("VGA") == "1" else ["-vga", "none"]
|
||||
|
||||
|
||||
class Serial:
|
||||
"""El serial de la VM. Todo lo que entra queda en el .log crudo, pase lo que pase."""
|
||||
@@ -76,12 +92,27 @@ class Serial:
|
||||
print(f" ⚠ nunca llegó «{marca}» {nombre} en {segundos}s", flush=True)
|
||||
return self.buf[vistos:].decode("utf-8", "replace")
|
||||
|
||||
def cmd(self, orden, segundos=30):
|
||||
"""Manda una orden y devuelve su salida (delimitada por una marca propia)."""
|
||||
marca = f"__FIN{int(time.time()*1000) % 100000}__"
|
||||
self.s.sendall(f"{orden}; echo {marca}\n".encode())
|
||||
sal = self.esperar(marca, segundos, nombre=f"de «{orden[:40]}»")
|
||||
return sal
|
||||
def cmd(self, orden, segundos=30, fondo=False):
|
||||
"""Manda una orden y devuelve su salida (delimitada por una marca propia).
|
||||
|
||||
⚠ DOS TRAMPAS MEDIDAS, las dos hacen que la orden NO CORRA y el guion siga como si nada:
|
||||
|
||||
· **el terminal hace ECO de lo que se le escribe**, así que una marca escrita literal en la
|
||||
línea aparece en el serial ANTES de que el shell ejecute nada: el `esperar` la ve en el eco
|
||||
y vuelve al instante, y las órdenes se pisan unas a otras. Por eso la marca se ARMA EN EL
|
||||
GUEST partida en dos (`'FIN''-123'`): el eco muestra las comillas y sólo la salida trae la
|
||||
marca entera.
|
||||
· **`cmd & ; echo …` es un error de sintaxis** en ash: pegarle un `;` a un `&` no lanza nada
|
||||
y el shell contesta «syntax error». Lo de fondo va en su propia línea (`fondo=True`).
|
||||
"""
|
||||
n = int(time.time() * 1000) % 100000
|
||||
marca = f"FIN-{n}"
|
||||
if fondo:
|
||||
self.s.sendall(f"{orden}\n".encode()); time.sleep(0.5)
|
||||
self.s.sendall(f"echo 'FIN''-{n}'\n".encode())
|
||||
else:
|
||||
self.s.sendall(f"{orden}; echo 'FIN''-{n}'\n".encode())
|
||||
return self.esperar(marca, segundos, nombre=f"de «{orden[:40]}»")
|
||||
|
||||
|
||||
def qmp(ruta, ordenes):
|
||||
@@ -99,6 +130,8 @@ def qmp(ruta, ordenes):
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--solo-cosmic", action="store_true", help="control: no lanza el navegador")
|
||||
ap.add_argument("--como-usuario", action="store_true",
|
||||
help="lanza `atuq` a secas —perfil por defecto, sin MOZ_ENABLE_WAYLAND— como se hizo a mano en el §6.10.ter")
|
||||
ap.add_argument("--espera", type=int, default=180, help="segundos para que el navegador pinte")
|
||||
ap.add_argument("--out", default=os.path.join(RAIZ, "work/atuq-imagen"))
|
||||
a = ap.parse_args()
|
||||
@@ -114,7 +147,7 @@ def main():
|
||||
qemu = [
|
||||
"nice", "-n", "10", "qemu-system-x86_64",
|
||||
"-machine", "q35", "-accel", "tcg", "-cpu", "max", "-m", MEM, "-smp", SMP,
|
||||
"-vga", "none", "-device", "virtio-gpu-pci", "-display", "none", "-nic", "none",
|
||||
*VGA_ARGS, "-device", "virtio-gpu-pci", "-display", "none", "-nic", "none",
|
||||
"-drive", f"if=pflash,format=raw,unit=0,file={OVMF_CODE},readonly=on",
|
||||
"-drive", f"if=pflash,format=raw,unit=1,file={vars_fd}",
|
||||
"-drive", f"file={IMG},format=raw,if=virtio",
|
||||
@@ -156,12 +189,23 @@ def main():
|
||||
"<h1 style=\"font:40px monospace\">ATUQ PINTA</h1>' > /tmp/pagina.html")
|
||||
ser.cmd("printf '%s\\n' 'user_pref(\"browser.dom.window.dump.enabled\", true);' > /tmp/perfil/user.js")
|
||||
ser.cmd("printf '%s\\n' 'user_pref(\"browser.shell.checkDefaultBrowser\", false);' >> /tmp/perfil/user.js")
|
||||
lanz = ("MOZ_ENABLE_WAYLAND=1 GDK_BACKEND=wayland "
|
||||
"MOZ_LOG='Widget:5,WidgetWayland:5,WaylandBackend:5,timestamp' "
|
||||
"MOZ_LOG_FILE=/var/log/cosmic/moz "
|
||||
"/usr/bin/atuq --no-remote --profile /tmp/perfil file:///tmp/pagina.html "
|
||||
"> /var/log/cosmic/atuq.log 2>&1 &")
|
||||
print(ser.cmd(lanz).strip())
|
||||
# ⚠ LOS DOS LANZAMIENTOS NO SON EL MISMO EXPERIMENTO. El de por defecto fija el
|
||||
# entorno (perfil nuevo, `MOZ_ENABLE_WAYLAND`) para que la medición no dependa de lo que
|
||||
# haya quedado en el estado del usuario; `--como-usuario` reproduce lo que se tecleó a
|
||||
# mano en el §6.10.ter —`atuq` pelado, con SU perfil y sin variables— que es lo único que
|
||||
# sigue distinto entre aquella corrida y ésta. El `MOZ_LOG` va en los dos: no cambia el
|
||||
# comportamiento, sólo deja rastro.
|
||||
if a.como_usuario:
|
||||
lanz = ("MOZ_LOG='Widget:5,WidgetWayland:5,WaylandBackend:5,timestamp' "
|
||||
"MOZ_LOG_FILE=/var/log/cosmic/moz "
|
||||
"/usr/bin/atuq file:///tmp/pagina.html > /var/log/cosmic/atuq.log 2>&1 &")
|
||||
else:
|
||||
lanz = ("MOZ_ENABLE_WAYLAND=1 GDK_BACKEND=wayland "
|
||||
"MOZ_LOG='Widget:5,WidgetWayland:5,WaylandBackend:5,timestamp' "
|
||||
"MOZ_LOG_FILE=/var/log/cosmic/moz "
|
||||
"/usr/bin/atuq --no-remote --profile /tmp/perfil file:///tmp/pagina.html "
|
||||
"> /var/log/cosmic/atuq.log 2>&1 &")
|
||||
print(ser.cmd(lanz, fondo=True).strip())
|
||||
print(f"== navegador lanzado; observando {a.espera}s", flush=True)
|
||||
t0 = time.time(); n = 0
|
||||
while time.time() - t0 < a.espera:
|
||||
|
||||
Reference in New Issue
Block a user