settings/handler/
base.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::accessibility::types::AccessibilityInfo;
6use crate::audio::types::SetAudioStream;
7use crate::base::{SettingInfo, SettingType};
8use crate::display::types::SetDisplayInfo;
9use crate::do_not_disturb::types::DoNotDisturbInfo;
10use crate::handler::setting_handler::ControllerError;
11use crate::input::types::InputDevice;
12use crate::intl::types::IntlInfo;
13use crate::keyboard::types::KeyboardInfo;
14use crate::night_mode::types::NightModeInfo;
15use crate::payload_convert;
16use crate::service::message::{Delegate, Messenger, Receptor, Signature};
17use crate::service_context::ServiceContext;
18use crate::setup::types::SetConfigurationInterfacesParams;
19use settings_light::types::LightState;
20use settings_media_buttons::MediaButtons;
21
22use async_trait::async_trait;
23use fuchsia_trace as ftrace;
24use futures::future::LocalBoxFuture;
25use std::borrow::Cow;
26use std::collections::HashSet;
27use std::rc::Rc;
28
29pub type ControllerGenerateResult = Result<(), anyhow::Error>;
30
31pub(crate) type GenerateHandler =
32    Box<dyn Fn(Context) -> LocalBoxFuture<'static, ControllerGenerateResult>>;
33
34pub type Response = Result<Option<SettingInfo>, Error>;
35
36/// This macro takes an enum, which has variants associated with various numbers of data, and
37/// generates the same enum and implements a for_inspect method.
38/// The for_inspect method returns variants' names.
39#[macro_export]
40macro_rules! generate_inspect {
41    (@underscore $_type:ty) => { _ };
42    ($(#[$metas:meta])* pub enum $name:ident {
43        $(
44            $(#[$variant_meta:meta])*
45            $variant:ident
46            $( ($($data:ty),+ $(,)?) )?
47        ),* $(,)?
48    }
49    ) => {
50        $(#[$metas])*
51        pub enum $name {
52            $(
53                $(#[$variant_meta])*
54                $variant$(($($data,)+))?,
55            )*
56        }
57
58        impl $name {
59            pub(crate) fn for_inspect(&self) -> &'static str {
60                match self {
61                    $(
62                        $name::$variant $(
63                            ( $(generate_inspect!(@underscore $data)),+ )
64                        )? => stringify!($variant),
65                    )*
66                }
67            }
68        }
69    };
70}
71
72generate_inspect! {
73    /// The possible requests that can be made on a setting. The sink will expect a
74    /// subset of the values defined below based on the associated type.
75    /// The types are arranged alphabetically.
76    #[derive(PartialEq, Debug, Clone)]
77    pub enum Request {
78        /// Returns the current setting information.
79        Get,
80
81        /// Requests ongoing updates when the setting changes.
82        Listen,
83
84        // Camera watcher events.
85        OnCameraSWState(bool),
86
87        // Input events.
88        OnButton(MediaButtons),
89
90        // Accessibility requests.
91        SetAccessibilityInfo(AccessibilityInfo),
92
93        // Audio requests.
94        SetVolume(Vec<SetAudioStream>, ftrace::Id),
95
96        // Display requests.
97        SetDisplayInfo(SetDisplayInfo),
98
99        // Do not disturb requests.
100        SetDnD(DoNotDisturbInfo),
101
102        // Factory Reset requests.
103        SetLocalResetAllowed(bool),
104
105        // Input requests.
106        SetInputStates(Vec<InputDevice>),
107
108        // Intl requests.
109        SetIntlInfo(IntlInfo),
110
111        // Keyboard requests.
112        SetKeyboardInfo(KeyboardInfo),
113
114        // Light requests.
115        SetLightGroupValue(String, Vec<LightState>),
116
117        // Night mode requests.
118        SetNightModeInfo(NightModeInfo),
119
120        // Restores settings to outside dependencies.
121        Restore,
122
123        // Instructs handler to rebroadcast its current value.
124        Rebroadcast,
125
126        // Privacy requests.
127        SetUserDataSharingConsent(Option<bool>),
128
129        // Setup info requests.
130        SetConfigurationInterfaces(SetConfigurationInterfacesParams),
131    }
132}
133
134impl From<MediaButtons> for Request {
135    fn from(event: MediaButtons) -> Self {
136        Request::OnButton(event)
137    }
138}
139
140/// The data that is sent to and from setting handlers through the service
141/// MessageHub.
142#[derive(Clone, PartialEq, Debug)]
143pub enum Payload {
144    /// The `Request` payload communicates actions to be taken upon the setting.
145    /// These actions can be around access (get/listen) and changes (set). Note
146    /// that there is not necessarily a 1:1 relationship between `Request` and
147    /// [`Response`] defined later. It is possible a single `Request` will
148    /// result into multiple [`Response`] that are delivered on the same
149    /// MessageHub receptor.
150    Request(Request),
151    /// The `Response` payload represents the result of a `Request` action. Note
152    /// that Response is a Result; receipients should confirm whether an error
153    /// was returned and if a successful result (wich is an Option) has a value.
154    Response(Response),
155}
156
157// Conversions for Handler Payload.
158payload_convert!(Setting, Payload);
159
160#[derive(thiserror::Error, Debug, Clone, PartialEq)]
161// If any new variants are added here, they should also be updated in the response types
162// for inspect in inspect::utils::enums::ResponseType.
163pub enum Error {
164    #[error("Unimplemented Request:{0:?} for setting type: {1:?}")]
165    UnimplementedRequest(SettingType, Request),
166
167    #[error("Storage failure for setting type: {0:?}")]
168    StorageFailure(SettingType),
169
170    #[error("Initialization failure: cause {0:?}")]
171    InitFailure(Cow<'static, str>),
172
173    #[error("Restoration of setting on controller startup failed: cause {0:?}")]
174    RestoreFailure(Cow<'static, str>),
175
176    #[error("Invalid argument for setting type: {0:?} argument:{1:?} value:{2:?}")]
177    InvalidArgument(SettingType, Cow<'static, str>, Cow<'static, str>),
178
179    #[error(
180        "Incompatible argument values passed: {setting_type:?} argument:{main_arg:?} cannot be \
181         combined with arguments:[{other_args:?}] with respective values:[{values:?}]. {reason:?}"
182    )]
183    IncompatibleArguments {
184        setting_type: SettingType,
185        main_arg: Cow<'static, str>,
186        other_args: Cow<'static, str>,
187        values: Cow<'static, str>,
188        reason: Cow<'static, str>,
189    },
190
191    #[error("External failure for setting type:{0:?} dependency: {1:?} request:{2:?} error:{3}")]
192    ExternalFailure(SettingType, Cow<'static, str>, Cow<'static, str>, Cow<'static, str>),
193
194    #[error("Unhandled type: {0:?}")]
195    UnhandledType(SettingType),
196
197    #[error("Delivery error for type: {0:?} received by: {1:?}")]
198    DeliveryError(SettingType, SettingType),
199
200    #[error("Unexpected error: {0}")]
201    UnexpectedError(Cow<'static, str>),
202
203    #[error("Undeliverable Request:{1:?} for setting type: {0:?}")]
204    UndeliverableError(SettingType, Request),
205
206    #[error("Unsupported request for setting type: {0:?}")]
207    UnsupportedError(SettingType),
208
209    #[error("Communication error")]
210    CommunicationError,
211
212    #[error("Irrecoverable error")]
213    IrrecoverableError,
214
215    #[error("Timeout error")]
216    TimeoutError,
217}
218
219impl From<ControllerError> for Error {
220    fn from(error: ControllerError) -> Self {
221        match error {
222            ControllerError::UnimplementedRequest(setting_type, request) => {
223                Error::UnimplementedRequest(setting_type, request)
224            }
225            ControllerError::WriteFailure(setting_type) => Error::StorageFailure(setting_type),
226            ControllerError::InitFailure(description) => Error::InitFailure(description),
227            ControllerError::RestoreFailure(description) => Error::RestoreFailure(description),
228            ControllerError::ExternalFailure(setting_type, dependency, request, error) => {
229                Error::ExternalFailure(setting_type, dependency, request, error)
230            }
231            ControllerError::InvalidArgument(setting_type, argument, value) => {
232                Error::InvalidArgument(setting_type, argument, value)
233            }
234            ControllerError::IncompatibleArguments {
235                setting_type,
236                main_arg,
237                other_args,
238                values,
239                reason,
240            } => {
241                Error::IncompatibleArguments { setting_type, main_arg, other_args, values, reason }
242            }
243            ControllerError::UnhandledType(setting_type) => Error::UnhandledType(setting_type),
244            ControllerError::UnexpectedError(error) => Error::UnexpectedError(error),
245            ControllerError::UndeliverableError(setting_type, request) => {
246                Error::UndeliverableError(setting_type, request)
247            }
248            ControllerError::UnsupportedError(setting_type) => {
249                Error::UnsupportedError(setting_type)
250            }
251            ControllerError::DeliveryError(setting_type, setting_type_2) => {
252                Error::DeliveryError(setting_type, setting_type_2)
253            }
254            ControllerError::IrrecoverableError => Error::IrrecoverableError,
255            ControllerError::TimeoutError => Error::TimeoutError,
256            ControllerError::ExitError => Error::IrrecoverableError,
257        }
258    }
259}
260
261#[derive(thiserror::Error, Debug, Clone, PartialEq)]
262pub enum SettingHandlerFactoryError {
263    #[error("Setting type {0:?} not registered in environment")]
264    SettingNotFound(SettingType),
265
266    #[error("Cannot find setting handler generator for {0:?}")]
267    GeneratorNotFound(SettingType),
268
269    #[error("MessageHub Messenger for setting handler could not be created")]
270    HandlerMessengerError,
271
272    #[error("MessageHub Messenger for controller messenger could not be created")]
273    ControllerMessengerError,
274
275    #[error("MessageHub Messenger for lifecycle messenger could not be created")]
276    LifecycleMessengerError,
277
278    #[error("Setting handler for {0:?} failed to startup. cause: {1:?}")]
279    HandlerStartupError(SettingType, Cow<'static, str>),
280}
281
282/// A factory capable of creating a handler for a given setting on-demand. If no
283/// viable handler can be created, None will be returned.
284#[async_trait(?Send)]
285pub(crate) trait SettingHandlerFactory {
286    async fn generate(
287        &mut self,
288        setting_type: SettingType,
289        delegate: Delegate,
290        notifier_signature: Signature,
291    ) -> Result<Signature, SettingHandlerFactoryError>;
292}
293
294pub struct Environment {
295    pub settings: HashSet<SettingType>,
296    pub service_context: Rc<ServiceContext>,
297}
298
299impl Clone for Environment {
300    fn clone(&self) -> Environment {
301        Environment::new(self.settings.clone(), self.service_context.clone())
302    }
303}
304
305impl Environment {
306    pub(crate) fn new(
307        settings: HashSet<SettingType>,
308        service_context: Rc<ServiceContext>,
309    ) -> Environment {
310        Environment { settings, service_context }
311    }
312}
313
314/// Context captures all details necessary for a handler to execute in a given
315/// settings service environment.
316pub struct Context {
317    pub setting_type: SettingType,
318    pub messenger: Messenger,
319    pub receptor: Receptor,
320    pub notifier_signature: Signature,
321    pub environment: Environment,
322    pub id: u64,
323}
324
325impl Context {
326    pub(crate) fn new(
327        setting_type: SettingType,
328        messenger: Messenger,
329        receptor: Receptor,
330        notifier_signature: Signature,
331        environment: Environment,
332        id: u64,
333    ) -> Context {
334        Context { setting_type, messenger, receptor, notifier_signature, environment, id }
335    }
336}
337
338/// ContextBuilder is a convenience builder to facilitate creating a Context
339/// (and associated environment).
340#[cfg(test)]
341pub(crate) struct ContextBuilder {
342    setting_type: SettingType,
343    settings: HashSet<SettingType>,
344    service_context: Option<Rc<ServiceContext>>,
345    messenger: Messenger,
346    receptor: Receptor,
347    notifier_signature: Signature,
348    id: u64,
349}
350
351#[cfg(test)]
352impl ContextBuilder {
353    pub(crate) fn new(
354        setting_type: SettingType,
355        messenger: Messenger,
356        receptor: Receptor,
357        notifier_signature: Signature,
358        id: u64,
359    ) -> Self {
360        Self {
361            setting_type,
362            settings: HashSet::new(),
363            service_context: None,
364            messenger,
365            receptor,
366            notifier_signature,
367            id,
368        }
369    }
370
371    /// Generates the Context.
372    pub(crate) fn build(self) -> Context {
373        let service_context =
374            self.service_context.unwrap_or_else(|| Rc::new(ServiceContext::new(None, None)));
375        let environment = Environment::new(self.settings, service_context);
376
377        // Note: ContextBuilder should use the same context id system as the SettingHandlerFactoryImpl.
378        // If it is used in conjunction with Context::new, then a new way of tracking unique Contexts
379        // may need to be devised. If it replaces all usages of Context::new, the id creation can
380        // be moved to the ContextBuilder struct.
381        Context::new(
382            self.setting_type,
383            self.messenger,
384            self.receptor,
385            self.notifier_signature,
386            environment,
387            self.id,
388        )
389    }
390}