同步移动端工程、设备控制改进与发布资料

This commit is contained in:
2026-09-26 19:21:12 +08:00
parent 912ba432cf
commit 98eadc5c8b
137 changed files with 9274 additions and 85 deletions
@@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, Callable
from uuid import uuid4
from app.display.service import DisplayService
from app.system.kernel_recovery import KernelRecovery
from .diagnostics import failure_log_metadata, read_failure_log
from .package import MAX_OTA_UPLOAD_BYTES, OtaPackageError, inspect_package
@@ -84,8 +85,45 @@ class OtaManager:
"last_result": last_result,
"failure_log_available": failure_log_available,
"failure_log_bytes": failure_log_bytes,
"kernel_recovery": self.kernel_recovery_status(),
}
def _production_recovery(self) -> KernelRecovery | None:
if os.name == "nt" or self.data_root != Path("/var/lib/matrix-screen-controller"):
return None
return KernelRecovery(self.data_root)
def kernel_recovery_status(self) -> dict[str, str]:
recovery = self._production_recovery()
return recovery.status() if recovery else {"state": "not_needed", "reason": ""}
def schedule_kernel_recovery_after_ota(self) -> None:
recovery = self._production_recovery()
if recovery is None:
return
result = read_last_result(self.data_root)
if not result or result.get("status") != "success" or result.get("target_version") != str(self.software_version):
return
result_id = f"{result.get('target_version')}:{result.get('installed_at')}"
if not recovery.prepare_attempt(result_id):
return
command = [
"systemd-run", "--quiet", "--collect", "--unit=matrix-kernel-recovery",
"--on-active=5s", "/usr/bin/python3",
"/opt/matrix-screen-controller/app/system/kernel_recovery.py", "arm-and-reboot",
]
try:
subprocess.run(command, check=True, capture_output=True, timeout=10)
except (OSError, subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc:
recovery.write_record("failed", f"could not schedule kernel recovery: {exc}", attempts=0)
def finalize_kernel_recovery_after_boot(self) -> None:
recovery = self._production_recovery()
if recovery is None:
return
thread = threading.Thread(target=recovery.finalize_after_boot, name="kernel-recovery-finalize", daemon=True)
thread.start()
def failure_log(self) -> bytes | None:
last_result = read_last_result(self.data_root)
return read_failure_log(self.data_root, last_result)