Skip to main content

recovery_util/ota/
action.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::crash::CrashReporter;
6use crate::ota::actions::factory_reset::FactoryResetAction;
7use crate::ota::actions::finalize_reinstall::FinalizeReinstallAction;
8use crate::ota::actions::get_wifi_networks::GetWifiNetworksAction;
9use crate::ota::actions::ota_reinstall::OtaReinstallAction;
10use crate::ota::actions::reboot_device::RebootAction;
11use crate::ota::actions::set_sharing_consent::SetSharingConsentAction;
12use crate::ota::actions::wifi_connect::WifiConnectAction;
13use crate::ota::controller::EventSender;
14use crate::ota::state_machine::{State, StateHandler};
15use fuchsia_async as fasync;
16use ota_lib::OtaManager;
17use std::rc::Rc;
18use std::sync::Arc;
19
20/// This file initiates all the non-ui, background actions that are required to satisfy
21/// the OTA UX UI slides. In general some states cause a background task to be run which
22/// may  produce one or more state machine events. Actions may reboot the device.
23pub struct Action {
24    event_sender: EventSender,
25    ota_manager: Arc<dyn OtaManager>,
26    crash_reporter: Option<Rc<CrashReporter>>,
27}
28
29impl Action {
30    pub fn new(
31        event_sender: EventSender,
32        ota_manager: Arc<dyn OtaManager>,
33        crash_reporter: Option<Rc<CrashReporter>>,
34    ) -> Self {
35        Self { event_sender, ota_manager, crash_reporter }
36    }
37}
38
39impl StateHandler for Action {
40    fn handle_state(&mut self, state: State) {
41        let event_sender = Box::new(self.event_sender.clone());
42        match state {
43            State::GetWiFiNetworks => GetWifiNetworksAction::run(event_sender),
44            State::Connecting(network, password) => {
45                WifiConnectAction::run(event_sender, network, password, self.crash_reporter.clone())
46            }
47            State::Rebooting(delay) => RebootAction::run(event_sender, delay),
48            State::ReinstallConfirm { desired: user_data_sharing_consent, reported } => {
49                SetSharingConsentAction::run(event_sender, user_data_sharing_consent, reported)
50            }
51            State::ExecuteReinstall => {
52                OtaReinstallAction::run(event_sender, self.ota_manager.clone())
53            }
54            State::ReinstallRunning { status: Some(status), .. } => {
55                // TODO(b/253084947): Remove call to tell ota_manager the OTA is complete
56                let ota_manager = self.ota_manager.clone();
57                fasync::Task::local(async move {
58                    ota_manager.complete_ota(status).await;
59                })
60                .detach();
61            }
62            State::FinalizeReinstall(status) => FinalizeReinstallAction::run(event_sender, status),
63            State::FactoryReset => FactoryResetAction::run(event_sender),
64            // We ignore all other states
65            _ => {}
66        };
67    }
68}
69
70#[cfg(test)]
71mod test {
72    use super::{Action, StateHandler};
73    use crate::ota::controller::EventSender;
74    use crate::ota::state_machine::{Event, OtaStatus, State};
75    use anyhow::Error;
76    use async_trait::async_trait;
77    use fuchsia_sync::Mutex;
78    use futures::channel::{mpsc, oneshot};
79    use ota_lib::OtaManager;
80    use std::sync::Arc;
81
82    struct FakeOtaManager {
83        sender: Mutex<Option<oneshot::Sender<OtaStatus>>>,
84    }
85
86    impl FakeOtaManager {
87        pub fn new() -> (Arc<Self>, oneshot::Receiver<OtaStatus>) {
88            let (tx, rx) = oneshot::channel();
89            (Arc::new(Self { sender: Mutex::new(Some(tx)) }), rx)
90        }
91    }
92
93    #[async_trait]
94    impl OtaManager for FakeOtaManager {
95        async fn start_and_wait_for_result(&self) -> Result<(), Error> {
96            Ok(())
97        }
98        async fn stop(&self) -> Result<(), Error> {
99            Ok(())
100        }
101        async fn complete_ota(&self, status: OtaStatus) {
102            self.sender.lock().take().expect("only one event expected").send(status).unwrap();
103        }
104    }
105
106    #[fuchsia::test]
107    async fn reinstall_progress_with_ota_status_completes_ota() {
108        let (sender, _receiver) = mpsc::channel::<Event>(10);
109        let event_sender = EventSender::new(sender);
110
111        // Verify that status propagates to complete_ota by trying a few different values.
112        for status in [OtaStatus::Succeeded, OtaStatus::Failed, OtaStatus::Cancelled] {
113            let (ota_manager, on_complete_ota) = FakeOtaManager::new();
114            let mut action = Action::new(event_sender.clone(), ota_manager, None);
115
116            action.handle_state(State::ReinstallRunning {
117                status: Some(status.clone()),
118                progress: 100,
119            });
120            assert_eq!(status, on_complete_ota.await.unwrap());
121        }
122    }
123}