mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-24 01:33:46 +08:00
fixes
This commit is contained in:
@@ -5,6 +5,7 @@ import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import signal
|
||||
import stat
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
@@ -759,6 +760,48 @@ def migrate_legacy_experimental_longitudinal(params: Params, params_cache: Param
|
||||
params_cache.remove("ExperimentalLongitudinalEnabled")
|
||||
|
||||
|
||||
def _msgq_file_is_readwrite_openable(path: Path) -> bool:
|
||||
fd = os.open(path, os.O_RDWR | getattr(os, "O_CLOEXEC", 0))
|
||||
try:
|
||||
return True
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
|
||||
def cleanup_inaccessible_msgq_files(shm_path: str | Path) -> int:
|
||||
"""Remove stale msgq files that would crash SubSocket/PubSocket creation."""
|
||||
shm_root = Path(shm_path)
|
||||
if not shm_root.is_dir():
|
||||
return 0
|
||||
|
||||
removed = 0
|
||||
for path in shm_root.rglob("msgq_*"):
|
||||
try:
|
||||
st = path.lstat()
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
if not stat.S_ISREG(st.st_mode):
|
||||
continue
|
||||
|
||||
try:
|
||||
_msgq_file_is_readwrite_openable(path)
|
||||
continue
|
||||
except PermissionError:
|
||||
pass
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
try:
|
||||
path.unlink()
|
||||
removed += 1
|
||||
cloudlog.warning(f"Removed inaccessible stale msgq file: {path}")
|
||||
except OSError:
|
||||
cloudlog.exception(f"Failed to remove inaccessible stale msgq file: {path}")
|
||||
|
||||
return removed
|
||||
|
||||
|
||||
def manager_init() -> None:
|
||||
manager_init_start = time.monotonic()
|
||||
last_timing = _log_boot_timing("manager_init", "start", manager_init_start, manager_init_start)
|
||||
@@ -829,6 +872,11 @@ def manager_init() -> None:
|
||||
print(f"WARNING: failed to make {Paths.shm_path()}")
|
||||
last_timing = _log_boot_timing("manager_init", "shm_path", manager_init_start, last_timing)
|
||||
|
||||
removed_msgq_files = cleanup_inaccessible_msgq_files(Paths.shm_path())
|
||||
if removed_msgq_files:
|
||||
cloudlog.warning(f"Removed {removed_msgq_files} inaccessible stale msgq files before process startup")
|
||||
last_timing = _log_boot_timing("manager_init", "msgq_cleanup", manager_init_start, last_timing)
|
||||
|
||||
# set params
|
||||
serial = HARDWARE.get_serial()
|
||||
params.put("Version", build_metadata.openpilot.version)
|
||||
|
||||
@@ -376,6 +376,40 @@ class TestManager:
|
||||
|
||||
assert params.get_bool("PrioritizeSmoothFollowing")
|
||||
|
||||
def test_cleanup_inaccessible_msgq_files_removes_only_blocked_files(self, tmp_path, monkeypatch):
|
||||
healthy = tmp_path / "msgq_deviceState"
|
||||
blocked = tmp_path / "msgq_gpsLocation"
|
||||
unrelated = tmp_path / "not_msgq_gpsLocation"
|
||||
healthy.write_bytes(b"healthy")
|
||||
blocked.write_bytes(b"blocked")
|
||||
unrelated.write_bytes(b"unrelated")
|
||||
|
||||
def fake_open_probe(path):
|
||||
if path == blocked:
|
||||
raise PermissionError("blocked")
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(manager, "_msgq_file_is_readwrite_openable", fake_open_probe)
|
||||
|
||||
assert manager.cleanup_inaccessible_msgq_files(tmp_path) == 1
|
||||
assert healthy.read_bytes() == b"healthy"
|
||||
assert not blocked.exists()
|
||||
assert unrelated.read_bytes() == b"unrelated"
|
||||
|
||||
def test_cleanup_inaccessible_msgq_files_ignores_msgq_directories(self, tmp_path, monkeypatch):
|
||||
msgq_dir = tmp_path / "msgq_desktop"
|
||||
msgq_dir.mkdir()
|
||||
child = msgq_dir / "gpsLocation"
|
||||
child.write_bytes(b"child")
|
||||
|
||||
def fake_open_probe(path):
|
||||
raise AssertionError(f"directories and non-msgq children should not be probed: {path}")
|
||||
|
||||
monkeypatch.setattr(manager, "_msgq_file_is_readwrite_openable", fake_open_probe)
|
||||
|
||||
assert manager.cleanup_inaccessible_msgq_files(tmp_path) == 0
|
||||
assert child.read_bytes() == b"child"
|
||||
|
||||
@pytest.mark.skip("this test is flaky the way it's currently written, should be moved to test_onroad")
|
||||
def test_clean_exit(self, subtests):
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
from openpilot.system import tombstoned
|
||||
|
||||
|
||||
def test_report_tombstone_apport_ignores_hal3_direct_widthfix(tmp_path, monkeypatch):
|
||||
crash = tmp_path / "_data_agnos-compat_bin_hal3_direct_widthfix.0.crash"
|
||||
crash.write_text("\n".join([
|
||||
"ProblemType: Crash",
|
||||
"ExecutablePath: /data/agnos-compat/bin/hal3_direct_widthfix",
|
||||
"Signal: 11",
|
||||
"CoreDump: base64",
|
||||
]))
|
||||
|
||||
sentry_calls = []
|
||||
monkeypatch.setattr(tombstoned.sentry, "report_tombstone", lambda *args: sentry_calls.append(args))
|
||||
|
||||
def fail_retrace(fn):
|
||||
raise AssertionError(f"ignored tombstones should not be retraced: {fn}")
|
||||
|
||||
monkeypatch.setattr(tombstoned, "get_apport_stacktrace", fail_retrace)
|
||||
|
||||
tombstoned.report_tombstone_apport(str(crash))
|
||||
|
||||
assert sentry_calls == []
|
||||
assert not crash.exists()
|
||||
+31
-4
@@ -19,6 +19,9 @@ MAX_TOMBSTONE_FN_LEN = 62 # 85 - 23 ("<dongle id>/crash/")
|
||||
|
||||
TOMBSTONE_DIR = "/data/tombstones/"
|
||||
APPORT_DIR = "/var/crash/"
|
||||
IGNORED_APPORT_EXECUTABLES = {
|
||||
"/data/agnos-compat/bin/hal3_direct_widthfix",
|
||||
}
|
||||
|
||||
|
||||
def safe_fn(s):
|
||||
@@ -44,6 +47,27 @@ def get_apport_stacktrace(fn):
|
||||
return "Timeout getting stacktrace"
|
||||
|
||||
|
||||
def get_apport_executable_path(fn: str) -> str:
|
||||
try:
|
||||
with open(fn) as f:
|
||||
for line in f:
|
||||
if line.startswith("ExecutablePath:"):
|
||||
return line.strip().split(': ', 1)[-1]
|
||||
if line.startswith("CoreDump"):
|
||||
break
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def remove_crashlog(fn: str) -> None:
|
||||
try:
|
||||
os.remove(fn)
|
||||
except PermissionError:
|
||||
pass
|
||||
|
||||
|
||||
def get_tombstones():
|
||||
"""Returns list of (filename, ctime) for all crashlogs"""
|
||||
files = []
|
||||
@@ -64,6 +88,12 @@ def report_tombstone_apport(fn):
|
||||
cloudlog.error(f"Tombstone {fn} too big, {f_size}. Skipping...")
|
||||
return
|
||||
|
||||
executable_path = get_apport_executable_path(fn)
|
||||
if executable_path in IGNORED_APPORT_EXECUTABLES:
|
||||
cloudlog.warning(f"Ignoring known agnos-compat tombstone: {executable_path}")
|
||||
remove_crashlog(fn)
|
||||
return
|
||||
|
||||
message = "" # One line description of the crash
|
||||
contents = "" # Full file contents without coredump
|
||||
path = "" # File path relative to openpilot directory
|
||||
@@ -134,10 +164,7 @@ def report_tombstone_apport(fn):
|
||||
# Files could be on different filesystems, copy, then delete
|
||||
shutil.copy(fn, os.path.join(crashlog_dir, new_fn))
|
||||
|
||||
try:
|
||||
os.remove(fn)
|
||||
except PermissionError:
|
||||
pass
|
||||
remove_crashlog(fn)
|
||||
|
||||
|
||||
def main() -> NoReturn:
|
||||
|
||||
Reference in New Issue
Block a user