settings/agent/
storage_agent.rs

1// Copyright 2021 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
5//! The [StorageAgent](storage_agent::StorageAgent) is responsible for all reads and writes to
6//! storage for the settings service.
7
8use 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    /// The factory for creating a messenger to receive messages.
68    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                    // Only initialize the message receptor once during Initialization.
118                    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                    // Always reply with an Ok for invocations. Ignore the receptor result.
130                    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                _ => {} // Other messages are ignored
140            }
141
142            // When we have received an event, we need to make sure to add the rest of the events
143            // back onto the unordered list.
144            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        // Ignore the receptor result.
203        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        // Ignore the receptor result.
226        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        // Ignore the receptor result.
247        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        // Ignore the receptor result.
262        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);