同步移动端工程、设备控制改进与发布资料
This commit is contained in:
@@ -14,11 +14,13 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
from typing import Any
|
||||
import urllib.request
|
||||
|
||||
from app.ota.diagnostics import DiagnosticLog, clear_failure_log, persist_failure_log, sha256_file
|
||||
from app.ota.package import extract_payload, inspect_package
|
||||
from app.ota.state import read_json, utc_now, write_json, write_last_result
|
||||
from app.ota.versioning import SoftwareVersion
|
||||
from app.system.kernel_recovery import CANDIDATE_RELEASE, KernelRecovery
|
||||
|
||||
TARGET = Path("/opt/matrix-screen-controller")
|
||||
RELEASES = Path("/opt/matrix-screen-controller.releases")
|
||||
@@ -34,6 +36,32 @@ class UpdateFailed(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def verify_kernel_capability_retained(
|
||||
before: dict[str, Any],
|
||||
after: dict[str, Any],
|
||||
performance_before: dict[str, Any],
|
||||
performance_after: dict[str, Any],
|
||||
) -> None:
|
||||
previously_healthy = (
|
||||
before.get("release") == CANDIDATE_RELEASE
|
||||
and before.get("available") is True
|
||||
and before.get("marker") is True
|
||||
)
|
||||
if not previously_healthy:
|
||||
return
|
||||
if (after["release"] != CANDIDATE_RELEASE or not after["available"] or not after["marker"]
|
||||
or set(after["policies"]) != set(before["policies"])):
|
||||
raise UpdateFailed("OTA lost the validated candidate kernel or cpufreq policy")
|
||||
requested = performance_before.get("requested")
|
||||
if (performance_after.get("available") is not True or performance_after.get("requested") is not requested
|
||||
or (requested is True and performance_after.get("effective") is not True)):
|
||||
raise UpdateFailed("OTA changed performance mode availability or effective state")
|
||||
if requested is False and performance_after.get("current_governors") != {
|
||||
name: value["current"] for name, value in before["policies"].items()
|
||||
}:
|
||||
raise UpdateFailed("OTA did not restore the original CPU governors")
|
||||
|
||||
|
||||
def snapshot(root: Path, *, ignored: set[str] | None = None) -> dict[str, tuple[int, str]]:
|
||||
records: dict[str, tuple[int, str]] = {}
|
||||
ignored = ignored or set()
|
||||
@@ -81,6 +109,9 @@ class Transaction:
|
||||
f"job_id={self.job_id} current_version={self.current_version} "
|
||||
f"target_version={self.target_version} packaged_at={request.get('packaged_at') or ''}"
|
||||
)
|
||||
self.kernel_recovery = KernelRecovery(DATA_ROOT)
|
||||
self.kernel_before: dict[str, Any] | None = None
|
||||
self.performance_before: dict[str, Any] | None = None
|
||||
self.job = {
|
||||
"id": self.job_id,
|
||||
"target_version": str(self.target_version),
|
||||
@@ -118,6 +149,13 @@ class Transaction:
|
||||
)
|
||||
|
||||
def prepare(self) -> None:
|
||||
self.kernel_before = self.kernel_recovery.capability()
|
||||
with urllib.request.urlopen("http://127.0.0.1:8080/api/status", timeout=8) as response:
|
||||
self.performance_before = json.loads(response.read().decode("utf-8"))["system"]["performance_mode"]
|
||||
self.diagnostics.write(
|
||||
f"kernel_before={self.kernel_before['release']} "
|
||||
f"cpufreq_available={self.kernel_before['available']} marker={self.kernel_before['marker']}"
|
||||
)
|
||||
if any(path.exists() for path in (self.work_root, self.release, self.data_candidate, self.data_backup)):
|
||||
raise UpdateFailed("OTA transaction paths already exist")
|
||||
self.work_root.mkdir(parents=True, mode=0o700)
|
||||
@@ -273,6 +311,15 @@ class Transaction:
|
||||
raise UpdateFailed("new service reports the wrong hardware mapping")
|
||||
if driver.get("oe_timing_backend") != "h618-pwm4" or driver.get("oe_pulse_faults") != 0:
|
||||
raise UpdateFailed("new service did not pass the PWM4 OE health check")
|
||||
before = self.kernel_before or {}
|
||||
if (before.get("available") and before.get("marker")
|
||||
and before.get("release") == CANDIDATE_RELEASE):
|
||||
verify_kernel_capability_retained(
|
||||
before, self.kernel_recovery.capability(), self.performance_before or {},
|
||||
(status.get("system") or {}).get("performance_mode") or {},
|
||||
)
|
||||
else:
|
||||
self.diagnostics.write("kernel_preexisting_degraded=true; application update may proceed")
|
||||
self.diagnostics.write(
|
||||
"health_summary="
|
||||
f"version:{status.get('service', {}).get('software_version')} "
|
||||
|
||||
Reference in New Issue
Block a user