mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-04-07 10:24:02 +08:00
WifiManager: guard init_wifi_state (#37413)
* failing test * fix * rename * better
This commit is contained in:
@@ -347,6 +347,33 @@ class TestThreadRaces:
|
||||
assert wm._wifi_state.ssid == "B"
|
||||
assert wm._wifi_state.status == ConnectStatus.CONNECTING
|
||||
|
||||
def test_init_wifi_state_race_user_tap_during_dbus(self, mocker):
|
||||
"""User taps B while _init_wifi_state's DBus calls are in flight.
|
||||
|
||||
_init_wifi_state runs from set_active(True) or worker error paths. It does
|
||||
2 DBus calls (device State property + _get_active_wifi_connection) then
|
||||
unconditionally writes _wifi_state. If the user taps a network during those
|
||||
calls, _set_connecting("B") is overwritten with stale NM ground truth.
|
||||
"""
|
||||
wm = _make_wm(mocker, connections={"A": "/path/A", "B": "/path/B"})
|
||||
wm._wifi_device = "/dev/wifi0"
|
||||
wm._router_main = mocker.MagicMock()
|
||||
|
||||
state_reply = mocker.MagicMock()
|
||||
state_reply.body = [('u', NMDeviceState.ACTIVATED)]
|
||||
wm._router_main.send_and_get_reply.return_value = state_reply
|
||||
|
||||
def user_taps_b_during_dbus(*args, **kwargs):
|
||||
wm._set_connecting("B")
|
||||
return ("/path/A", {})
|
||||
|
||||
wm._get_active_wifi_connection.side_effect = user_taps_b_during_dbus
|
||||
|
||||
wm._init_wifi_state()
|
||||
|
||||
assert wm._wifi_state.ssid == "B"
|
||||
assert wm._wifi_state.status == ConnectStatus.CONNECTING
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Full sequences (NM signal order from real devices)
|
||||
|
||||
@@ -197,7 +197,7 @@ class WifiManager:
|
||||
self._networks_updated: list[Callable[[list[Network]], None]] = []
|
||||
self._disconnected: list[Callable[[], None]] = []
|
||||
|
||||
self._lock = threading.Lock()
|
||||
self._scan_lock = threading.Lock()
|
||||
self._scan_thread = threading.Thread(target=self._network_scanner, daemon=True)
|
||||
self._state_thread = threading.Thread(target=self._monitor_state, daemon=True)
|
||||
self._initialize()
|
||||
@@ -227,6 +227,8 @@ class WifiManager:
|
||||
cloudlog.warning("No WiFi device found")
|
||||
return
|
||||
|
||||
epoch = self._user_epoch
|
||||
|
||||
dev_addr = DBusAddress(self._wifi_device, bus_name=NM, interface=NM_DEVICE_IFACE)
|
||||
dev_state = self._router_main.send_and_get_reply(Properties(dev_addr).get('State')).body[0][1]
|
||||
|
||||
@@ -239,6 +241,10 @@ class WifiManager:
|
||||
conn_path, _ = self._get_active_wifi_connection()
|
||||
if conn_path:
|
||||
wifi_state.ssid = next((s for s, p in self._connections.items() if p == conn_path), None)
|
||||
|
||||
if self._user_epoch != epoch:
|
||||
return
|
||||
|
||||
self._wifi_state = wifi_state
|
||||
|
||||
if block:
|
||||
@@ -281,11 +287,13 @@ class WifiManager:
|
||||
|
||||
@property
|
||||
def connecting_to_ssid(self) -> str | None:
|
||||
return self._wifi_state.ssid if self._wifi_state.status == ConnectStatus.CONNECTING else None
|
||||
wifi_state = self._wifi_state
|
||||
return wifi_state.ssid if wifi_state.status == ConnectStatus.CONNECTING else None
|
||||
|
||||
@property
|
||||
def connected_ssid(self) -> str | None:
|
||||
return self._wifi_state.ssid if self._wifi_state.status == ConnectStatus.CONNECTED else None
|
||||
wifi_state = self._wifi_state
|
||||
return wifi_state.ssid if wifi_state.status == ConnectStatus.CONNECTED else None
|
||||
|
||||
@property
|
||||
def tethering_password(self) -> str:
|
||||
@@ -822,7 +830,7 @@ class WifiManager:
|
||||
return
|
||||
|
||||
def worker():
|
||||
with self._lock:
|
||||
with self._scan_lock:
|
||||
if self._wifi_device is None:
|
||||
cloudlog.warning("No WiFi device found")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user