1use crate::client::connection_selection::ConnectionSelectionRequester;
6use crate::client::roaming::local_roam_manager::RoamManager;
7use crate::config_management::SavedNetworksManagerApi;
8use crate::telemetry::{TelemetrySender, TimeoutSource};
9use crate::util::listener;
10use anyhow::Error;
11use fuchsia_async as fasync;
12use fuchsia_inspect::Node as InspectNode;
13use fuchsia_inspect_contrib::inspect_insert;
14use fuchsia_inspect_contrib::log::WriteInspect;
15use futures::channel::mpsc;
16use futures::lock::Mutex;
17use futures::Future;
18use std::borrow::Cow;
19use std::convert::Infallible;
20use std::sync::Arc;
21
22pub mod device_monitor;
23mod iface_manager;
24pub mod iface_manager_api;
25mod iface_manager_types;
26pub mod phy_manager;
27pub mod recovery;
28
29pub const DEFECT_CHANNEL_SIZE: usize = 100;
30
31pub fn create_iface_manager(
32 phy_manager: Arc<Mutex<dyn phy_manager::PhyManagerApi>>,
33 client_update_sender: listener::ClientListenerMessageSender,
34 ap_update_sender: listener::ApListenerMessageSender,
35 dev_monitor_proxy: fidl_fuchsia_wlan_device_service::DeviceMonitorProxy,
36 saved_networks: Arc<dyn SavedNetworksManagerApi>,
37 connection_selection_requester: ConnectionSelectionRequester,
38 roam_manager: RoamManager,
39 telemetry_sender: TelemetrySender,
40 defect_sender: mpsc::Sender<Defect>,
41 defect_receiver: mpsc::Receiver<Defect>,
42 recovery_receiver: recovery::RecoveryActionReceiver,
43 node: fuchsia_inspect::Node,
44) -> (Arc<Mutex<iface_manager_api::IfaceManager>>, impl Future<Output = Result<Infallible, Error>>)
45{
46 let (sender, receiver) = mpsc::channel(0);
47 let iface_manager_sender = Arc::new(Mutex::new(iface_manager_api::IfaceManager { sender }));
48 let iface_manager = iface_manager::IfaceManagerService::new(
49 phy_manager,
50 client_update_sender,
51 ap_update_sender,
52 dev_monitor_proxy,
53 saved_networks,
54 connection_selection_requester,
55 roam_manager,
56 telemetry_sender,
57 defect_sender,
58 node,
59 );
60 let iface_manager_service = iface_manager::serve_iface_manager_requests(
61 iface_manager,
62 receiver,
63 defect_receiver,
64 recovery_receiver,
65 );
66
67 (iface_manager_sender, iface_manager_service)
68}
69
70#[derive(Clone, Copy, Debug, PartialEq)]
71pub enum PhyFailure {
72 IfaceCreationFailure { phy_id: u16 },
73 IfaceDestructionFailure { phy_id: u16 },
74}
75
76#[derive(Clone, Copy, Debug)]
77pub enum IfaceFailure {
78 CanceledScan { iface_id: u16 },
79 FailedScan { iface_id: u16 },
80 EmptyScanResults { iface_id: u16 },
81 ApStartFailure { iface_id: u16 },
82 ConnectionFailure { iface_id: u16 },
83 Timeout { iface_id: u16, source: TimeoutSource },
84}
85
86impl PartialEq for IfaceFailure {
92 fn eq(&self, other: &Self) -> bool {
93 #[allow(
94 clippy::match_like_matches_macro,
95 reason = "mass allow for https://fxbug.dev/381896734"
96 )]
97 match (*self, *other) {
98 (IfaceFailure::CanceledScan { .. }, IfaceFailure::CanceledScan { .. }) => true,
99 (IfaceFailure::FailedScan { .. }, IfaceFailure::FailedScan { .. }) => true,
100 (IfaceFailure::EmptyScanResults { .. }, IfaceFailure::EmptyScanResults { .. }) => true,
101 (IfaceFailure::ApStartFailure { .. }, IfaceFailure::ApStartFailure { .. }) => true,
102 (IfaceFailure::ConnectionFailure { .. }, IfaceFailure::ConnectionFailure { .. }) => {
103 true
104 }
105 (IfaceFailure::Timeout { .. }, IfaceFailure::Timeout { .. }) => true,
106 _ => false,
107 }
108 }
109}
110
111#[derive(Clone, Copy, Debug, PartialEq)]
112pub enum Defect {
113 Phy(PhyFailure),
114 Iface(IfaceFailure),
115}
116
117impl WriteInspect for Defect {
118 fn write_inspect<'a>(&self, writer: &InspectNode, key: impl Into<Cow<'a, str>>) {
119 match self {
120 Defect::Phy(PhyFailure::IfaceCreationFailure { phy_id }) => {
121 inspect_insert!(writer, var key: {IfaceCreationFailure: {phy_id: phy_id}})
122 }
123 Defect::Phy(PhyFailure::IfaceDestructionFailure { phy_id }) => {
124 inspect_insert!(writer, var key: {IfaceDestructionFailure: {phy_id: phy_id}})
125 }
126 Defect::Iface(IfaceFailure::CanceledScan { iface_id }) => {
127 inspect_insert!(writer, var key: {CanceledScan: {iface_id: iface_id}})
128 }
129 Defect::Iface(IfaceFailure::FailedScan { iface_id }) => {
130 inspect_insert!(writer, var key: {FailedScan: {iface_id: iface_id}})
131 }
132 Defect::Iface(IfaceFailure::EmptyScanResults { iface_id }) => {
133 inspect_insert!(writer, var key: {EmptyScanResults: {iface_id: iface_id}})
134 }
135 Defect::Iface(IfaceFailure::ApStartFailure { iface_id }) => {
136 inspect_insert!(writer, var key: {ApStartFailure: {iface_id: iface_id}})
137 }
138 Defect::Iface(IfaceFailure::ConnectionFailure { iface_id }) => {
139 inspect_insert!(writer, var key: {ConnectionFailure: {iface_id: iface_id}})
140 }
141 Defect::Iface(IfaceFailure::Timeout { iface_id, .. }) => {
142 inspect_insert!(writer, var key: {Timeout: {iface_id: iface_id}})
143 }
144 }
145 }
146}
147
148#[derive(Debug, PartialEq)]
149struct Event<T: PartialEq> {
150 value: T,
151 time: fasync::MonotonicInstant,
152}
153
154impl<T: PartialEq> Event<T> {
155 fn new(value: T, time: fasync::MonotonicInstant) -> Self {
156 Event { value, time }
157 }
158}
159
160#[derive(Debug)]
161pub struct EventHistory<T: PartialEq> {
162 events: Vec<Event<T>>,
163 retention_time: zx::MonotonicDuration,
164}
165
166impl<T: PartialEq> EventHistory<T> {
167 fn new(retention_seconds: u32) -> Self {
168 EventHistory {
169 events: Vec::new(),
170 retention_time: zx::MonotonicDuration::from_seconds(retention_seconds as i64),
171 }
172 }
173
174 fn add_event(&mut self, value: T) {
175 let curr_time = fasync::MonotonicInstant::now();
176 self.events.push(Event::new(value, curr_time));
177 self.retain_unexpired_events(curr_time);
178 }
179
180 fn event_count(&mut self, value: T) -> usize {
181 let curr_time = fasync::MonotonicInstant::now();
182 self.retain_unexpired_events(curr_time);
183 self.events.iter().filter(|event| event.value == value).count()
184 }
185
186 fn time_since_last_event(&mut self, value: T) -> Option<zx::MonotonicDuration> {
187 let curr_time = fasync::MonotonicInstant::now();
188 self.retain_unexpired_events(curr_time);
189
190 for event in self.events.iter().rev() {
191 if event.value == value {
192 return Some(curr_time - event.time);
193 }
194 }
195 None
196 }
197
198 fn retain_unexpired_events(&mut self, curr_time: fasync::MonotonicInstant) {
199 let oldest_allowed_time = curr_time - self.retention_time;
200 self.events.retain(|event| event.time > oldest_allowed_time)
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use fuchsia_async::TestExecutor;
208 use rand::Rng;
209 use test_util::{assert_gt, assert_lt};
210
211 #[fuchsia::test]
212 fn test_event_retention() {
213 let mut event_history = EventHistory::<()>::new(1);
215
216 event_history.events = vec![
218 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) },
219 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(1_000_000_000) },
220 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(2_000_000_000) },
221 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(2_000_000_001) },
222 Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(3_000_000_000) },
223 ];
224
225 event_history.retain_unexpired_events(fasync::MonotonicInstant::from_nanos(3_000_000_000));
227
228 assert_eq!(
231 event_history.events,
232 vec![
233 Event::<()> {
234 value: (),
235 time: fasync::MonotonicInstant::from_nanos(2_000_000_001)
236 },
237 Event::<()> {
238 value: (),
239 time: fasync::MonotonicInstant::from_nanos(3_000_000_000)
240 },
241 ]
242 );
243 }
244
245 #[derive(Debug, PartialEq)]
246 enum TestEnum {
247 Foo,
248 Bar,
249 }
250
251 #[fuchsia::test]
252 fn test_time_since_last_event() {
253 let _exec = TestExecutor::new();
255
256 let mut event_history = EventHistory::<TestEnum>::new(u32::MAX);
259
260 let foo_time: i64 = 1_123_123_123;
262 let bar_time: i64 = 2_222_222_222;
263 event_history.events = vec![
264 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(foo_time) },
265 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(bar_time) },
266 ];
267
268 let start_time = fasync::MonotonicInstant::now().into_nanos();
271 let time_since_foo =
272 event_history.time_since_last_event(TestEnum::Foo).expect("Foo was not retained");
273 let time_since_bar =
274 event_history.time_since_last_event(TestEnum::Bar).expect("Bar was not retained");
275 let end_time = fasync::MonotonicInstant::now().into_nanos();
276
277 assert_lt!(time_since_foo.into_nanos(), end_time - foo_time);
279 assert_gt!(time_since_foo.into_nanos(), start_time - foo_time);
280
281 assert_lt!(time_since_bar.into_nanos(), end_time - bar_time);
282 assert_gt!(time_since_bar.into_nanos(), start_time - bar_time);
283 }
284
285 #[fuchsia::test]
286 fn test_time_since_last_event_retention() {
287 let _exec = TestExecutor::new();
289
290 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
293 let mut event_history = EventHistory::<()>::new((curr_time_seconds - 1) as u32);
294
295 event_history
298 .events
299 .push(Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) });
300
301 assert_eq!(event_history.time_since_last_event(()), None);
302 }
303 #[fuchsia::test]
304 fn test_add_event() {
305 let _exec = TestExecutor::new();
307 let mut event_history = EventHistory::<()>::new(u32::MAX);
308
309 let num_events = 3;
311 let start_time = fasync::MonotonicInstant::now().into_nanos();
312 for _ in 0..num_events {
313 event_history.add_event(());
314 }
315 let end_time = fasync::MonotonicInstant::now().into_nanos();
316
317 assert_eq!(event_history.events.len(), num_events);
319
320 for event in event_history.events {
322 let event_time = event.time.into_nanos();
323 assert_lt!(event_time, end_time);
324 assert_gt!(event_time, start_time);
325 }
326 }
327
328 #[fuchsia::test]
329 fn test_add_event_retention() {
330 let _exec = TestExecutor::new();
332
333 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
336 let mut event_history = EventHistory::<()>::new((curr_time_seconds - 1) as u32);
337
338 event_history
341 .events
342 .push(Event::<()> { value: (), time: fasync::MonotonicInstant::from_nanos(0) });
343
344 let start_time = fasync::MonotonicInstant::now().into_nanos();
346 event_history.add_event(());
347 assert_eq!(event_history.events.len(), 1);
348
349 event_history.add_event(());
351 event_history.add_event(());
352 let end_time = fasync::MonotonicInstant::now().into_nanos();
353
354 assert_eq!(event_history.events.len(), 3);
356
357 for event in event_history.events {
359 let event_time = event.time.into_nanos();
360 assert_lt!(event_time, end_time);
361 assert_gt!(event_time, start_time);
362 }
363 }
364
365 #[fuchsia::test]
366 fn test_event_count() {
367 let _exec = TestExecutor::new();
369 let mut event_history = EventHistory::<TestEnum>::new(u32::MAX);
370
371 event_history.events = vec![
372 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
373 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(1) },
374 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(2) },
375 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::from_nanos(3) },
376 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(4) },
377 ];
378
379 assert_eq!(event_history.event_count(TestEnum::Foo), 3);
380 assert_eq!(event_history.event_count(TestEnum::Bar), 2);
381 }
382
383 #[fuchsia::test]
384 fn test_event_count_retention() {
385 let _exec = TestExecutor::new();
387
388 let curr_time_seconds = fasync::MonotonicInstant::now().into_nanos() / 1_000_000_000;
391 let mut event_history = EventHistory::<TestEnum>::new((curr_time_seconds - 1) as u32);
392
393 event_history.events = vec![
394 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
395 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::from_nanos(0) },
396 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::now() },
397 Event { value: TestEnum::Bar, time: fasync::MonotonicInstant::now() },
398 Event { value: TestEnum::Foo, time: fasync::MonotonicInstant::now() },
399 ];
400
401 assert_eq!(event_history.event_count(TestEnum::Foo), 1);
402 assert_eq!(event_history.event_count(TestEnum::Bar), 2);
403 }
404
405 #[fuchsia::test]
406 fn test_failure_equality() {
407 let mut rng = rand::rng();
408 assert_eq!(
409 IfaceFailure::CanceledScan { iface_id: rng.random() },
410 IfaceFailure::CanceledScan { iface_id: rng.random() }
411 );
412 assert_eq!(
413 IfaceFailure::FailedScan { iface_id: rng.random() },
414 IfaceFailure::FailedScan { iface_id: rng.random() }
415 );
416 assert_eq!(
417 IfaceFailure::EmptyScanResults { iface_id: rng.random() },
418 IfaceFailure::EmptyScanResults { iface_id: rng.random() }
419 );
420 assert_eq!(
421 IfaceFailure::ApStartFailure { iface_id: rng.random() },
422 IfaceFailure::ApStartFailure { iface_id: rng.random() }
423 );
424 assert_eq!(
425 IfaceFailure::ConnectionFailure { iface_id: rng.random() },
426 IfaceFailure::ConnectionFailure { iface_id: rng.random() }
427 );
428 assert_eq!(
429 IfaceFailure::Timeout { iface_id: rng.random(), source: TimeoutSource::Scan },
430 IfaceFailure::Timeout { iface_id: rng.random(), source: TimeoutSource::ApStart }
431 );
432 }
433}