settings/setup/
setup_controller.rs

1// Copyright 2019 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::base::{SettingInfo, SettingType};
6use crate::call_async;
7use crate::handler::base::Request;
8use crate::handler::setting_handler::persist::{controller as data_controller, ClientProxy};
9use crate::handler::setting_handler::{
10    controller, ControllerError, IntoHandlerResult, SettingHandlerResult,
11};
12use crate::service_context::ServiceContext;
13use crate::setup::types::SetupInfo;
14use async_trait::async_trait;
15use fidl_fuchsia_hardware_power_statecontrol::{RebootOptions, RebootReason2};
16
17use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
18use settings_storage::storage_factory::{NoneT, StorageAccess};
19
20async fn reboot(service_context_handle: &ServiceContext) -> Result<(), ControllerError> {
21    let hardware_power_statecontrol_admin = service_context_handle
22        .connect::<fidl_fuchsia_hardware_power_statecontrol::AdminMarker>()
23        .await
24        .map_err(|e| {
25            ControllerError::ExternalFailure(
26                SettingType::Setup,
27                "hardware_power_statecontrol_manager".into(),
28                "connect".into(),
29                format!("{e:?}").into(),
30            )
31        })?;
32
33    let reboot_err = |e: String| {
34        ControllerError::ExternalFailure(
35            SettingType::Setup,
36            "hardware_power_statecontrol_manager".into(),
37            "reboot".into(),
38            e.into(),
39        )
40    };
41
42    call_async!(hardware_power_statecontrol_admin => perform_reboot(&RebootOptions{
43        reasons: Some(vec![RebootReason2::UserRequest]), ..Default::default()
44    }))
45    .await
46    .map_err(|e| reboot_err(format!("{e:?}")))
47    .and_then(|r| {
48        r.map_err(|zx_status| reboot_err(format!("{:?}", zx::Status::from_raw(zx_status))))
49    })
50}
51
52impl DeviceStorageCompatible for SetupInfo {
53    type Loader = NoneT;
54    const KEY: &'static str = "setup_info";
55}
56
57impl From<SetupInfo> for SettingInfo {
58    fn from(info: SetupInfo) -> SettingInfo {
59        SettingInfo::Setup(info)
60    }
61}
62
63pub struct SetupController {
64    client: ClientProxy,
65}
66
67impl StorageAccess for SetupController {
68    type Storage = DeviceStorage;
69    type Data = SetupInfo;
70    const STORAGE_KEY: &'static str = SetupInfo::KEY;
71}
72
73#[async_trait(?Send)]
74impl data_controller::Create for SetupController {
75    async fn create(client: ClientProxy) -> Result<Self, ControllerError> {
76        Ok(Self { client })
77    }
78}
79
80#[async_trait(?Send)]
81impl controller::Handle for SetupController {
82    async fn handle(&self, request: Request) -> Option<SettingHandlerResult> {
83        match request {
84            Request::SetConfigurationInterfaces(params) => {
85                let id = fuchsia_trace::Id::new();
86                let mut info = self.client.read_setting::<SetupInfo>(id).await;
87                info.configuration_interfaces = params.config_interfaces_flags;
88
89                let write_setting_result =
90                    self.client.write_setting(info.into(), id).await.into_handler_result();
91
92                // If the write succeeded, reboot if necessary.
93                if write_setting_result.is_ok() && params.should_reboot {
94                    let reboot_result =
95                        reboot(&self.client.get_service_context()).await.map(|_| None);
96                    if reboot_result.is_err() {
97                        // This will result in fidl_fuchsia_settings::Error::Failed in the caller.
98                        return Some(reboot_result);
99                    }
100                }
101                Some(write_setting_result)
102            }
103            Request::Get => Some(
104                self.client
105                    .read_setting_info::<SetupInfo>(fuchsia_trace::Id::new())
106                    .await
107                    .into_handler_result(),
108            ),
109            _ => None,
110        }
111    }
112}