From 37a6c62e6edb5c4e1382d78de8e48b15f5481655 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:27:34 -0500 Subject: [PATCH] Reapply "The Final Kachow" --- launch_env.sh | 2 +- system/hardware/tici/agnos.json | 6 +- tools/agnos/flash_desktop_system_to_comma.sh | 6 +- tools/agnos/patch_system_reset_image.py | 115 ++++++++++++++++++- tools/agnos/profile_boot.sh | 65 +++++++++++ tools/agnos/test_patch_system_reset_image.py | 54 +++++++++ 6 files changed, 235 insertions(+), 13 deletions(-) create mode 100755 tools/agnos/profile_boot.sh create mode 100644 tools/agnos/test_patch_system_reset_image.py diff --git a/launch_env.sh b/launch_env.sh index d32295607..8dde50a60 100755 --- a/launch_env.sh +++ b/launch_env.sh @@ -21,7 +21,7 @@ fi export QCOM_PRIORITY=12 if [ -z "$AGNOS_VERSION" ]; then - export AGNOS_VERSION="12.8.25" + export AGNOS_VERSION="12.8.27" fi if [ -z "$AGNOS_ACCEPTED_VERSIONS" ]; then diff --git a/system/hardware/tici/agnos.json b/system/hardware/tici/agnos.json index 1620dc9ba..4bb1eddee 100644 --- a/system/hardware/tici/agnos.json +++ b/system/hardware/tici/agnos.json @@ -67,9 +67,9 @@ }, { "name": "system", - "url": "https://www.dropbox.com/scl/fi/1c8m8oxxbry7f3muqgymx/system5.img.xz?rlkey=81nx8one4t9912izceskbk3fg&st=z870ynme&dl=1", - "hash": "23280e1073340afe23452627a53269fbdad7251620f722df502de1a071ffd88b", - "hash_raw": "23280e1073340afe23452627a53269fbdad7251620f722df502de1a071ffd88b", + "url": "https://www.dropbox.com/scl/fi/kf8be07fgdjgcv9ic482y/system7.img.xz?rlkey=0e6jwij46tndpaeu33jx65tma&st=g9g0ph65&dl=1", + "hash": "1b71fd1835610e46c9d3f2d13e389108df4777308a6128e5b794b6875c91012e", + "hash_raw": "1b71fd1835610e46c9d3f2d13e389108df4777308a6128e5b794b6875c91012e", "size": 5368709120, "sparse": false, "full_check": false, diff --git a/tools/agnos/flash_desktop_system_to_comma.sh b/tools/agnos/flash_desktop_system_to_comma.sh index f610ce39b..682034cb3 100755 --- a/tools/agnos/flash_desktop_system_to_comma.sh +++ b/tools/agnos/flash_desktop_system_to_comma.sh @@ -2,7 +2,7 @@ set -euo pipefail HOST="${1:-comma@192.168.3.110}" -IMAGE="${2:-/Users/dominickthompson/Desktop/system-23280e1073340afe23452627a53269fbdad7251620f722df502de1a071ffd88b.img.xz}" +IMAGE="${2:-/Users/dominickthompson/Desktop/system7.img.xz}" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" @@ -16,8 +16,8 @@ REMOTE_RUNNER="${REMOTE_DIR}/run_flash.sh" REMOTE_AGNOS="${REMOTE_DIR}/agnos.py" PORT="8989" -EXPECTED_VERSION="12.8.25" -RAW_HASH="23280e1073340afe23452627a53269fbdad7251620f722df502de1a071ffd88b" +EXPECTED_VERSION="12.8.27" +RAW_HASH="1b71fd1835610e46c9d3f2d13e389108df4777308a6128e5b794b6875c91012e" RAW_SIZE="5368709120" if [[ ! -f "$IMAGE" ]]; then diff --git a/tools/agnos/patch_system_reset_image.py b/tools/agnos/patch_system_reset_image.py index 1e037107a..6838c60f5 100644 --- a/tools/agnos/patch_system_reset_image.py +++ b/tools/agnos/patch_system_reset_image.py @@ -38,6 +38,7 @@ SETUP_WIFI_PATCH_MARKER = "JEEPNY_AVAILABLE = True" SETUP_BRANDING_PATCH_MARKER = "STARPILOT_SETUP_BRANDING_V1" SETUP_SSH_RESTORE_PATCH_MARKER = "STARPILOT_SETUP_SSH_RESTORE_V1" WESTON_BG_PATCH_MARKER = "STARPILOT_WESTON_BG_ORIENTATION_V2" +COMMA_SH_DISPLAY_WAIT_PATCH_MARKER = "STARPILOT_DISPLAY_READY_WAIT_V1" JEEPNY_VERSION = "0.9.0" JEEPNY_WHEEL_URL = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl" JEEPNY_WHEEL_SHA256 = "97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683" @@ -155,6 +156,62 @@ def patched_weston_bg_exec_line() -> str: return f"ExecStartPre=/bin/bash -c \"/usr/local/venv/bin/python -c '{python_cmd}'\"" +def patch_comma_sh_display_wait(original: bytes) -> bytes: + text = original.decode("utf-8") + if COMMA_SH_DISPLAY_WAIT_PATCH_MARKER in text: + return original + + old = """echo "waiting for magic" +for i in {1..200}; do + if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then + break + fi + sleep 0.1 +done + +if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then + echo "magic ready after ${SECONDS}s" +else + echo "timed out waiting for magic, ${SECONDS}s" +fi +""" + new = f"""# {COMMA_SH_DISPLAY_WAIT_PATCH_MARKER} +if systemctl cat magic.service >/dev/null 2>&1; then + echo "waiting for magic" + for i in {{1..200}}; do + if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then + break + fi + sleep 0.1 + done + + if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then + echo "magic ready after ${{SECONDS}}s" + else + echo "timed out waiting for magic, ${{SECONDS}}s" + fi +else + echo "magic unavailable; waiting for weston" + for i in {{1..200}}; do + if systemctl is-active --quiet weston-ready && [ -S /var/tmp/weston/wayland-0 ]; then + break + fi + sleep 0.1 + done + + if systemctl is-active --quiet weston-ready && [ -S /var/tmp/weston/wayland-0 ]; then + echo "weston ready after ${{SECONDS}}s" + else + echo "timed out waiting for weston, ${{SECONDS}}s" + fi +fi +""" + + if old not in text: + raise RuntimeError("Unable to find comma.sh display readiness wait") + return text.replace(old, new, 1).encode("utf-8") + + def patch_weston_service(original: bytes) -> bytes: text = original.decode("utf-8") if WESTON_BG_PATCH_MARKER in text: @@ -764,6 +821,15 @@ def weston_service_has_expected_content(data: bytes) -> bool: ) +def comma_sh_has_expected_display_wait(data: bytes) -> bool: + return ( + COMMA_SH_DISPLAY_WAIT_PATCH_MARKER.encode("utf-8") in data + and b"systemctl cat magic.service" in data + and b"systemctl is-active --quiet weston-ready" in data + and b"[ -S /var/tmp/weston/wayland-0 ]" in data + ) + + def parse_inode(debugfs_output: str) -> int: m = re.search(r"Inode:\s+(\d+)", debugfs_output) if not m: @@ -771,6 +837,30 @@ def parse_inode(debugfs_output: str) -> int: return int(m.group(1)) +def format_debugfs_mode(mode_octal: str) -> str: + try: + mode = int(mode_octal, 8) + except ValueError as e: + raise RuntimeError(f"Invalid octal inode mode: {mode_octal}") from e + if not 0 <= mode <= 0xFFFF: + raise RuntimeError(f"Inode mode exceeds ext4 field width: {mode_octal}") + return f"0{mode:o}" + + +def verify_inode_metadata(debugfs: str, image: Path, image_path: str, expected_type: str, + mode_octal: str, uid: int, gid: int) -> None: + stat_out = run_debugfs(debugfs, image, f"stat {image_path}", write=False) + file_type, perms_octal, actual_uid, actual_gid = parse_debugfs_stat(stat_out) + expected_perms = int(mode_octal, 8) & 0o7777 + actual_perms = int(perms_octal, 8) + if (file_type, actual_perms, actual_uid, actual_gid) != (expected_type, expected_perms, uid, gid): + raise RuntimeError( + f"Metadata verification failed for {image_path}: " + f"got type={file_type} mode={actual_perms:04o} uid={actual_uid} gid={actual_gid}, " + f"expected type={expected_type} mode={expected_perms:04o} uid={uid} gid={gid}" + ) + + def write_regular_file_to_image(debugfs: str, image: Path, image_path: str, local_file: Path, mode_octal: str, uid: int = 0, gid: int = 0) -> None: try: run_debugfs(debugfs, image, f"rm {image_path}", write=True) @@ -781,9 +871,10 @@ def write_regular_file_to_image(debugfs: str, image: Path, image_path: str, loca run_debugfs(debugfs, image, f"write {local_file} {image_path}", write=True) stat_out = run_debugfs(debugfs, image, f"stat {image_path}", write=False) inode = parse_inode(stat_out) - run_debugfs(debugfs, image, f"set_inode_field <{inode}> mode {mode_octal}", write=True) + run_debugfs(debugfs, image, f"set_inode_field <{inode}> mode {format_debugfs_mode(mode_octal)}", write=True) run_debugfs(debugfs, image, f"set_inode_field <{inode}> uid {uid}", write=True) run_debugfs(debugfs, image, f"set_inode_field <{inode}> gid {gid}", write=True) + verify_inode_metadata(debugfs, image, image_path, "regular", mode_octal, uid, gid) def ensure_directory_in_image(debugfs: str, image: Path, image_path: str, mode_octal: str = "040755", uid: int = 0, gid: int = 0) -> None: @@ -796,9 +887,10 @@ def ensure_directory_in_image(debugfs: str, image: Path, image_path: str, mode_o stat_out = run_debugfs(debugfs, image, f"stat {image_path}", write=False) inode = parse_inode(stat_out) - run_debugfs(debugfs, image, f"set_inode_field <{inode}> mode {mode_octal}", write=True) + run_debugfs(debugfs, image, f"set_inode_field <{inode}> mode {format_debugfs_mode(mode_octal)}", write=True) run_debugfs(debugfs, image, f"set_inode_field <{inode}> uid {uid}", write=True) run_debugfs(debugfs, image, f"set_inode_field <{inode}> gid {gid}", write=True) + verify_inode_metadata(debugfs, image, image_path, "directory", mode_octal, uid, gid) def extract_wheel_subset(wheel_path: Path, extract_dir: Path, roots: set[str]) -> dict[Path, str]: @@ -1073,12 +1165,12 @@ def main() -> int: MAGIC_PATH_IN_IMAGE: "comma_magic", BG_PATH_IN_IMAGE: "comma_bg", } - preserved_hashes: dict[str, str] = {} + expected_hashes: dict[str, str] = {} for image_path, label in preserved_paths.items(): preserved_file = work_dir / f"{label}.preserved" print(f"Recording existing {image_path} for preservation", flush=True) run_debugfs(debugfs, patched_img, f"dump -p {image_path} {preserved_file}", write=False) - preserved_hashes[image_path] = sha256_file(preserved_file) + expected_hashes[image_path] = sha256_file(preserved_file) original_updater = work_dir / "comma_updater.orig" patched_updater = work_dir / "comma_updater.patched" @@ -1086,6 +1178,15 @@ def main() -> int: original_weston = work_dir / "weston_service.orig" patched_weston = work_dir / "weston_service.patched" verify_weston = work_dir / "weston_service.verify" + patched_comma_sh = work_dir / "comma_sh.patched" + + original_comma_sh = work_dir / "comma_sh.preserved" + comma_sh_patched_data = patch_comma_sh_display_wait(original_comma_sh.read_bytes()) + patched_comma_sh.write_bytes(comma_sh_patched_data) + + print("Writing patched /usr/comma/comma.sh display readiness wait", flush=True) + write_regular_file_to_image(debugfs, patched_img, COMMA_SH_PATH_IN_IMAGE, patched_comma_sh, "100775", 0, 0) + expected_hashes[COMMA_SH_PATH_IN_IMAGE] = sha256_file(patched_comma_sh) print("Extracting weston.service from image", flush=True) run_debugfs(debugfs, patched_img, f"dump -p {WESTON_SERVICE_PATH_IN_IMAGE} {original_weston}", write=False) @@ -1128,8 +1229,10 @@ def main() -> int: for image_path, label in preserved_paths.items(): verify_file = work_dir / f"{label}.verify" run_debugfs(debugfs, patched_img, f"dump -p {image_path} {verify_file}", write=False) - if sha256_file(verify_file) != preserved_hashes[image_path]: - raise RuntimeError(f"{image_path} changed unexpectedly; protected StarPilot payload files must stay byte-identical") + if image_path == COMMA_SH_PATH_IN_IMAGE and not comma_sh_has_expected_display_wait(verify_file.read_bytes()): + raise RuntimeError("comma.sh display readiness verification failed") + if sha256_file(verify_file) != expected_hashes[image_path]: + raise RuntimeError(f"{image_path} does not match the expected generated payload") if args.set_version: version_file = work_dir / "VERSION.patched" diff --git a/tools/agnos/profile_boot.sh b/tools/agnos/profile_boot.sh new file mode 100755 index 000000000..80108815a --- /dev/null +++ b/tools/agnos/profile_boot.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +HOST="${1:-comma@192.168.3.110}" + +SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=5) + +if [[ -n "${SSH_KEY:-}" ]]; then + SSH_OPTS+=(-i "$SSH_KEY" -o IdentitiesOnly=yes) +fi + +ssh "${SSH_OPTS[@]}" "$HOST" 'bash -s' <<'REMOTE_SCRIPT' +set -u + +echo "===== Device =====" +printf "AGNOS: " +cat /VERSION +printf "Model: " +tr -d '\000' /dev/null 2>&1; then + echo "Display path: magic.service" +else + echo "Display path: weston fallback (magic.service is not installed)" +fi + +for socket_path in /tmp/drmfd.sock /var/tmp/weston/wayland-0; do + if [[ -S "$socket_path" ]]; then + echo "$socket_path: ready" + else + echo "$socket_path: missing" + fi +done + +echo +echo "===== comma.sh Readiness Logic =====" +if grep -q STARPILOT_DISPLAY_READY_WAIT_V1 /usr/comma/comma.sh; then + sed -n '/STARPILOT_DISPLAY_READY_WAIT_V1/,+50p' /usr/comma/comma.sh +else + sed -n '/waiting for magic/,+20p' /usr/comma/comma.sh + if ! systemctl cat magic.service >/dev/null 2>&1; then + echo "WARNING: comma.sh waits 20 seconds for a service that is not installed" + fi +fi +REMOTE_SCRIPT diff --git a/tools/agnos/test_patch_system_reset_image.py b/tools/agnos/test_patch_system_reset_image.py new file mode 100644 index 000000000..3acb0889a --- /dev/null +++ b/tools/agnos/test_patch_system_reset_image.py @@ -0,0 +1,54 @@ +import pytest + +from tools.agnos.patch_system_reset_image import ( + COMMA_SH_DISPLAY_WAIT_PATCH_MARKER, + comma_sh_has_expected_display_wait, + format_debugfs_mode, + patch_comma_sh_display_wait, +) + + +ORIGINAL_DISPLAY_WAIT = b'''#!/usr/bin/env bash +echo "waiting for magic" +for i in {1..200}; do + if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then + break + fi + sleep 0.1 +done + +if systemctl is-active --quiet magic && [ -S /tmp/drmfd.sock ]; then + echo "magic ready after ${SECONDS}s" +else + echo "timed out waiting for magic, ${SECONDS}s" +fi + +exec /data/continue.sh +''' + + +def test_patch_comma_sh_display_wait_uses_available_display_service(): + patched = patch_comma_sh_display_wait(ORIGINAL_DISPLAY_WAIT) + + assert COMMA_SH_DISPLAY_WAIT_PATCH_MARKER.encode() in patched + assert b"systemctl cat magic.service" in patched + assert b"systemctl is-active --quiet magic" in patched + assert b"systemctl is-active --quiet weston-ready" in patched + assert b"[ -S /var/tmp/weston/wayland-0 ]" in patched + assert comma_sh_has_expected_display_wait(patched) + assert patch_comma_sh_display_wait(patched) == patched + + +def test_patch_comma_sh_display_wait_rejects_unknown_layout(): + with pytest.raises(RuntimeError, match="display readiness wait"): + patch_comma_sh_display_wait(b"#!/usr/bin/env bash\nexec /data/continue.sh\n") + + +@pytest.mark.parametrize(("mode", "expected"), [ + ("100775", "0100775"), + ("100644", "0100644"), + ("040755", "040755"), + ("120777", "0120777"), +]) +def test_format_debugfs_mode(mode, expected): + assert format_debugfs_mode(mode) == expected