mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-15 06:12:11 +08:00
Reapply "The Final Kachow"
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Executable
+65
@@ -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' </sys/firmware/devicetree/base/model
|
||||
printf '\nUptime: '
|
||||
cut -d' ' -f1 /proc/uptime
|
||||
|
||||
echo
|
||||
echo "===== Boot Summary ====="
|
||||
systemd-analyze time
|
||||
|
||||
echo
|
||||
echo "===== Slowest Units ====="
|
||||
systemd-analyze blame | head -n 20
|
||||
|
||||
echo
|
||||
echo "===== Critical Chain ====="
|
||||
systemd-analyze critical-chain graphical.target
|
||||
|
||||
echo
|
||||
echo "===== Display Startup ====="
|
||||
systemctl show comma.service weston.service weston-ready.service magic.service \
|
||||
-p Id -p LoadState -p ActiveState -p ActiveEnterTimestampMonotonic \
|
||||
-p ExecMainStartTimestampMonotonic -p ExecMainExitTimestampMonotonic --no-pager
|
||||
|
||||
if systemctl cat magic.service >/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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user