settings_factory_reset/
factory_reset_controller.rs1use crate::factory_reset_fidl_handler::Publisher;
6use crate::types::FactoryResetInfo;
7use anyhow::{Context, Error};
8use fidl_fuchsia_recovery_policy::{DeviceMarker, DeviceProxy};
9use fuchsia_async as fasync;
10use futures::StreamExt;
11use futures::channel::mpsc::UnboundedReceiver;
12use futures::channel::oneshot::Sender;
13use settings_common::call;
14use settings_common::inspect::event::{
15 ExternalEventPublisher, ResponseType, SettingValuePublisher,
16};
17use settings_common::service_context::{ExternalServiceProxy, ServiceContext};
18use settings_storage::UpdateState;
19use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
20use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
21use std::borrow::Cow;
22use std::rc::Rc;
23
24impl DeviceStorageCompatible for FactoryResetInfo {
25 type Loader = NoneT;
26 const KEY: &'static str = "factory_reset_info";
27}
28
29impl Default for FactoryResetInfo {
30 fn default() -> Self {
31 FactoryResetInfo::new(true)
32 }
33}
34
35#[allow(clippy::enum_variant_names)]
38#[derive(thiserror::Error, Debug)]
39pub(crate) enum FactoryResetError {
40 #[error("Failed to initialize controller: {0:?}")]
41 InitFailure(Error),
42 #[error("External failure for FactoryReset: dependency: {0:?} request:{1:?} error:{2}")]
43 ExternalFailure(Cow<'static, str>, Cow<'static, str>, Cow<'static, str>),
44 #[error("Write failed for FactoryReset: {0:?}")]
45 WriteFailure(Error),
46}
47
48impl From<&FactoryResetError> for ResponseType {
49 fn from(error: &FactoryResetError) -> Self {
50 match error {
51 FactoryResetError::InitFailure(..) => ResponseType::InitFailure,
52 FactoryResetError::ExternalFailure(..) => ResponseType::ExternalFailure,
53 FactoryResetError::WriteFailure(..) => ResponseType::StorageFailure,
54 }
55 }
56}
57
58pub(crate) enum Request {
59 Set(FactoryResetInfo, Sender<Result<(), FactoryResetError>>),
60}
61
62pub struct FactoryResetController {
63 store: Rc<DeviceStorage>,
64 is_local_reset_allowed: bool,
65 factory_reset_policy_service: ExternalServiceProxy<DeviceProxy, ExternalEventPublisher>,
66 publisher: Option<Publisher>,
67 setting_value_publisher: SettingValuePublisher<FactoryResetInfo>,
68}
69
70impl StorageAccess for FactoryResetController {
71 type Storage = DeviceStorage;
72 type Data = FactoryResetInfo;
73 const STORAGE_KEY: &'static str = FactoryResetInfo::KEY;
74}
75
76impl FactoryResetController {
77 pub(crate) async fn new<F>(
78 service_context: &ServiceContext,
79 storage_factory: Rc<F>,
80 setting_value_publisher: SettingValuePublisher<FactoryResetInfo>,
81 external_publisher: ExternalEventPublisher,
82 ) -> Result<FactoryResetController, FactoryResetError>
83 where
84 F: StorageFactory<Storage = DeviceStorage>,
85 {
86 let factory_reset_policy_service = service_context
87 .connect_with_publisher::<DeviceMarker, _>(external_publisher)
88 .await
89 .context("connecting to factory reset service")
90 .map_err(FactoryResetError::InitFailure)?;
91 Ok(Self {
92 store: storage_factory.get_store().await,
93 is_local_reset_allowed: true,
94 factory_reset_policy_service,
95 publisher: None,
96 setting_value_publisher,
97 })
98 }
99
100 pub(crate) fn register_publisher(&mut self, publisher: Publisher) {
101 self.publisher = Some(publisher);
102 }
103
104 fn publish(&self, info: FactoryResetInfo) {
105 let _ = self.setting_value_publisher.publish(&info);
106 if let Some(publisher) = self.publisher.as_ref() {
107 publisher.set(info);
108 }
109 }
110
111 pub(crate) async fn handle(
112 mut self,
113 mut request_rx: UnboundedReceiver<Request>,
114 ) -> fasync::Task<()> {
115 fasync::Task::local(async move {
116 while let Some(request) = request_rx.next().await {
117 let Request::Set(info, tx) = request;
118 let res =
119 self.set_local_reset_allowed(info.is_local_reset_allowed).await.map(|info| {
120 if let Some(info) = info {
121 self.publish(info);
122 }
123 });
124 let _ = tx.send(res);
125 }
126 })
127 }
128
129 pub(crate) async fn restore(&mut self) -> Result<FactoryResetInfo, FactoryResetError> {
130 let info = self.store.get::<FactoryResetInfo>().await;
131 self.is_local_reset_allowed = info.is_local_reset_allowed;
132 call!(self.factory_reset_policy_service =>
133 set_is_local_reset_allowed(info.is_local_reset_allowed)
134 )
135 .map_err(|e| {
136 FactoryResetError::ExternalFailure(
137 "factory_reset_policy".into(),
138 "restore_reset_state".into(),
139 format!("{e:?}").into(),
140 )
141 })?;
142
143 Ok(info)
144 }
145
146 async fn set_local_reset_allowed(
147 &mut self,
148 is_local_reset_allowed: bool,
149 ) -> Result<Option<FactoryResetInfo>, FactoryResetError> {
150 let mut info = self.store.get::<FactoryResetInfo>().await;
151 self.is_local_reset_allowed = is_local_reset_allowed;
152 info.is_local_reset_allowed = is_local_reset_allowed;
153 call!(self.factory_reset_policy_service =>
154 set_is_local_reset_allowed(info.is_local_reset_allowed)
155 )
156 .map_err(|e| {
157 FactoryResetError::ExternalFailure(
158 "factory_reset_policy".into(),
159 "set_local_reset_allowed".into(),
160 format!("{e:?}").into(),
161 )
162 })?;
163 self.store
164 .write(&info)
165 .await
166 .map(|state| (UpdateState::Updated == state).then_some(info))
167 .context("writing factory reset")
168 .map_err(FactoryResetError::WriteFailure)
169 }
170}