1use std::borrow::Borrow;
9use std::rc::Rc;
10
11use fidl::Persistable;
12use futures::stream::{FuturesUnordered, StreamFuture};
13use futures::StreamExt;
14use {fuchsia_async as fasync, fuchsia_trace as ftrace};
15
16use crate::accessibility::types::AccessibilityInfo;
17use crate::agent::{self, AgentCreator, Context, CreationFunc, Lifespan};
18use crate::audio::types::AudioInfo;
19#[cfg(test)]
20use crate::base::UnknownInfo;
21use crate::base::{SettingInfo, SettingType};
22use crate::display::types::DisplayInfo;
23use crate::do_not_disturb::types::DoNotDisturbInfo;
24use crate::factory_reset::types::FactoryResetInfo;
25use crate::input::types::InputInfoSources;
26use crate::intl::types::IntlInfo;
27use crate::keyboard::types::KeyboardInfo;
28use crate::light::types::LightInfo;
29use crate::message::base::{MessageEvent, MessengerType};
30use crate::message::receptor::Receptor;
31use crate::night_mode::types::NightModeInfo;
32use crate::privacy::types::PrivacyInfo;
33use crate::service::{self, Address};
34use crate::setup::types::SetupInfo;
35use crate::storage::{Error, Payload, StorageInfo, StorageRequest, StorageResponse, StorageType};
36use crate::{payload_convert, trace, trace_guard};
37use settings_storage::device_storage::{DeviceStorage, DeviceStorageConvertible};
38use settings_storage::fidl_storage::{DefaultDispatcher, FidlStorage, FidlStorageConvertible};
39use settings_storage::storage_factory::StorageFactory;
40use settings_storage::UpdateState;
41
42pub(crate) fn create_registrar<T, F>(
43 device_storage_factory: Rc<T>,
44 fidl_storage_factory: Rc<F>,
45) -> AgentCreator
46where
47 T: StorageFactory<Storage = DeviceStorage> + 'static,
48 F: StorageFactory<Storage = FidlStorage> + 'static,
49{
50 AgentCreator {
51 debug_id: "StorageAgent",
52 create: CreationFunc::Dynamic(Rc::new(move |context| {
53 let device_storage_factory = device_storage_factory.clone();
54 let fidl_storage_factory = fidl_storage_factory.clone();
55 Box::pin(async move {
56 StorageAgent::create(context, device_storage_factory, fidl_storage_factory).await;
57 })
58 })),
59 }
60}
61
62pub(crate) struct StorageAgent<T, F>
63where
64 T: StorageFactory<Storage = DeviceStorage>,
65 F: StorageFactory<Storage = FidlStorage>,
66{
67 delegate: service::message::Delegate,
69 device_storage_factory: Rc<T>,
70 fidl_storage_factory: Rc<F>,
71}
72
73impl<T, F> StorageAgent<T, F>
74where
75 T: StorageFactory<Storage = DeviceStorage> + 'static,
76 F: StorageFactory<Storage = FidlStorage> + 'static,
77{
78 async fn create(context: Context, device_storage_factory: Rc<T>, fidl_storage_factory: Rc<F>) {
79 let mut storage_agent = StorageAgent {
80 delegate: context.delegate,
81 device_storage_factory,
82 fidl_storage_factory,
83 };
84
85 let unordered = FuturesUnordered::new();
86 unordered.push(context.receptor.into_future());
87 fasync::Task::local(async move {
88 let id = ftrace::Id::new();
89 trace!(id, c"storage_agent");
90 storage_agent.handle_messages(id, unordered).await
91 })
92 .detach();
93 }
94
95 async fn handle_messages(
96 &mut self,
97 id: ftrace::Id,
98 mut unordered: FuturesUnordered<StreamFuture<Receptor>>,
99 ) {
100 let storage_management = StorageManagement {
101 device_storage_factory: Rc::clone(&self.device_storage_factory),
102 fidl_storage_factory: Rc::clone(&self.fidl_storage_factory),
103 };
104 while let Some((event, stream)) = unordered.next().await {
105 let event = if let Some(event) = event {
106 event
107 } else {
108 continue;
109 };
110
111 match event {
112 MessageEvent::Message(
113 service::Payload::Agent(agent::Payload::Invocation(invocation)),
114 client,
115 ) => {
116 trace!(id, c"agent event");
117 if let Lifespan::Initialization = invocation.lifespan {
119 let receptor = self
120 .delegate
121 .create(MessengerType::Addressable(Address::Storage))
122 .await
123 .expect("should acquire messenger")
124 .1;
125
126 unordered.push(receptor.into_future());
127 }
128
129 let _ = client.reply(service::Payload::Agent(agent::Payload::Complete(Ok(()))));
131 }
132 MessageEvent::Message(
133 service::Payload::Storage(Payload::Request(storage_request)),
134 responder,
135 ) => {
136 trace!(id, c"storage event");
137 storage_management.handle_request(storage_request, responder).await;
138 }
139 _ => {} }
141
142 unordered.push(stream.into_future());
145 }
146 }
147}
148
149macro_rules! into_storage_info {
150 ($ty:ty => $intermediate_ty:ty) => {
151 impl From<$ty> for StorageInfo {
152 fn from(info: $ty) -> StorageInfo {
153 let info: $intermediate_ty = info.into();
154 info.into()
155 }
156 }
157 };
158}
159
160#[cfg(test)]
161into_storage_info!(UnknownInfo => SettingInfo);
162into_storage_info!(AccessibilityInfo => SettingInfo);
163into_storage_info!(AudioInfo => SettingInfo);
164into_storage_info!(DisplayInfo => SettingInfo);
165into_storage_info!(FactoryResetInfo => SettingInfo);
166into_storage_info!(LightInfo => SettingInfo);
167into_storage_info!(DoNotDisturbInfo => SettingInfo);
168into_storage_info!(InputInfoSources => SettingInfo);
169into_storage_info!(IntlInfo => SettingInfo);
170into_storage_info!(KeyboardInfo => SettingInfo);
171into_storage_info!(NightModeInfo => SettingInfo);
172into_storage_info!(PrivacyInfo => SettingInfo);
173into_storage_info!(SetupInfo => SettingInfo);
174
175struct StorageManagement<T, F>
176where
177 T: StorageFactory<Storage = DeviceStorage>,
178 F: StorageFactory<Storage = FidlStorage>,
179{
180 device_storage_factory: Rc<T>,
181 fidl_storage_factory: Rc<F>,
182}
183
184impl<T, F> StorageManagement<T, F>
185where
186 T: StorageFactory<Storage = DeviceStorage>,
187 F: StorageFactory<Storage = FidlStorage>,
188{
189 async fn read<S>(&self, id: ftrace::Id, responder: service::message::MessageClient)
190 where
191 S: DeviceStorageConvertible + Into<StorageInfo>,
192 {
193 let guard = trace_guard!(id, c"get store");
194 let store = self.device_storage_factory.get_store().await;
195 drop(guard);
196
197 let guard = trace_guard!(id, c"get data");
198 let storable: S = store.get::<S::Storable>().await.into();
199 drop(guard);
200
201 let guard = trace_guard!(id, c"reply");
202 let _ = responder.reply(Payload::Response(StorageResponse::Read(storable.into())).into());
204 drop(guard);
205 }
206
207 async fn write<S>(&self, data: S, responder: service::message::MessageClient)
208 where
209 S: DeviceStorageConvertible,
210 {
211 let update_result = {
212 let store = self.device_storage_factory.get_store().await;
213 let storable_value = data.get_storable();
214 let storable_value: &S::Storable = storable_value.borrow();
215 if storable_value == &store.get::<S::Storable>().await {
216 Ok(UpdateState::Unchanged)
217 } else {
218 store
219 .write::<S::Storable>(storable_value)
220 .await
221 .map_err(|e| Error { message: format!("{e:?}") })
222 }
223 };
224
225 let _ = responder.reply(service::Payload::Storage(Payload::Response(
227 StorageResponse::Write(update_result),
228 )));
229 }
230
231 async fn fidl_read<S>(&self, id: ftrace::Id, responder: service::message::MessageClient)
232 where
233 S: FidlStorageConvertible + Into<StorageInfo>,
234 S::Storable: Persistable,
235 S::Loader: DefaultDispatcher<S>,
236 {
237 let guard = trace_guard!(id, c"get fidl store");
238 let store = self.fidl_storage_factory.get_store().await;
239 drop(guard);
240
241 let guard = trace_guard!(id, c"get data");
242 let storable: S = store.get::<S>().await;
243 drop(guard);
244
245 let guard = trace_guard!(id, c"reply");
246 let _ = responder.reply(Payload::Response(StorageResponse::Read(storable.into())).into());
248 drop(guard);
249 }
250
251 async fn fidl_write<S>(&self, data: S, responder: service::message::MessageClient)
252 where
253 S: FidlStorageConvertible,
254 S::Storable: Persistable,
255 {
256 let update_result = {
257 let store = self.fidl_storage_factory.get_store().await;
258 store.write::<S>(data).await.map_err(|e| Error { message: format!("{e:?}") })
259 };
260
261 let _ = responder.reply(service::Payload::Storage(Payload::Response(
263 StorageResponse::Write(update_result),
264 )));
265 }
266
267 async fn handle_request(
268 &self,
269 storage_request: StorageRequest,
270 responder: service::message::MessageClient,
271 ) {
272 match storage_request {
273 StorageRequest::Read(StorageType::SettingType(setting_type), id) => {
274 match setting_type {
275 #[cfg(test)]
276 SettingType::Unknown => self.read::<UnknownInfo>(id, responder).await,
277 SettingType::Accessibility => {
278 self.read::<AccessibilityInfo>(id, responder).await
279 }
280 SettingType::Audio => {
281 trace!(id, c"audio storage read");
282 self.read::<AudioInfo>(id, responder).await
283 }
284 SettingType::Display => self.read::<DisplayInfo>(id, responder).await,
285 SettingType::DoNotDisturb => self.read::<DoNotDisturbInfo>(id, responder).await,
286 SettingType::FactoryReset => self.read::<FactoryResetInfo>(id, responder).await,
287 SettingType::Input => self.read::<InputInfoSources>(id, responder).await,
288 SettingType::Intl => self.read::<IntlInfo>(id, responder).await,
289 SettingType::Keyboard => self.read::<KeyboardInfo>(id, responder).await,
290 SettingType::Light => self.fidl_read::<LightInfo>(id, responder).await,
291 SettingType::NightMode => self.read::<NightModeInfo>(id, responder).await,
292 SettingType::Privacy => self.read::<PrivacyInfo>(id, responder).await,
293 SettingType::Setup => self.read::<SetupInfo>(id, responder).await,
294 }
295 }
296 StorageRequest::Write(StorageInfo::SettingInfo(setting_info), id) => match setting_info
297 {
298 #[cfg(test)]
299 SettingInfo::Unknown(info) => self.write(info, responder).await,
300 SettingInfo::Accessibility(info) => self.write(info, responder).await,
301 SettingInfo::Audio(info) => {
302 trace!(id, c"audio storage write");
303 self.write(info, responder).await
304 }
305 SettingInfo::Brightness(info) => self.write(info, responder).await,
306 SettingInfo::DoNotDisturb(info) => self.write(info, responder).await,
307 SettingInfo::FactoryReset(info) => self.write(info, responder).await,
308 SettingInfo::Input(info) => self.write(info, responder).await,
309 SettingInfo::Intl(info) => self.write(info, responder).await,
310 SettingInfo::Keyboard(info) => self.write(info, responder).await,
311 SettingInfo::Light(info) => self.fidl_write(info, responder).await,
312 SettingInfo::NightMode(info) => self.write(info, responder).await,
313 SettingInfo::Privacy(info) => self.write(info, responder).await,
314 SettingInfo::Setup(info) => self.write(info, responder).await,
315 },
316 }
317 }
318}
319
320payload_convert!(Storage, Payload);