blob: c4de34248e107dced6191962378e04c54f4f36ec [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::audio::policy::{self as audio, State};
use crate::base::SettingType;
use crate::generate_inspect_with_info;
use crate::handler::device_storage::DeviceStorageFactory;
use crate::payload_convert;
use crate::policy::policy_handler::PolicyHandler;
use crate::policy::response::Response;
use crate::service;
use anyhow::Error;
use async_trait::async_trait;
use futures::future::BoxFuture;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::sync::Arc;
use thiserror::Error;
/// Defines the policy handler trait, which describes a component that persists and applies the
/// policies specified by policy clients
pub mod policy_handler;
/// Defines a proxy between the policy FIDL handler and policy handler that is responsible for
/// intercepting incoming setting requests and returning responses to the policy FIDL handler.
pub mod policy_proxy;
/// Defines a factory for creating policy handlers on demand.
pub mod policy_handler_factory_impl;
/// The policy types supported by the service.
#[derive(PartialEq, Debug, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
pub enum PolicyType {
/// This type is reserved for testing purposes.
#[cfg(test)]
Unknown,
Audio,
}
impl PolicyType {
/// Returns the corresponding setting type that this policy controls.
pub fn setting_type(&self) -> SettingType {
match self {
#[cfg(test)]
PolicyType::Unknown => SettingType::Unknown,
PolicyType::Audio => SettingType::Audio,
}
}
/// Initialize the storage needed for this particular policy handler.
pub async fn initialize_storage<T>(&self, storage_factory: &Arc<T>) -> Result<(), Error>
where
T: DeviceStorageFactory,
{
match self {
#[cfg(test)]
Self::Unknown => Ok(()),
Self::Audio => {
storage_factory
.initialize::<audio::audio_policy_handler::AudioPolicyHandler>()
.await
}
}
}
}
generate_inspect_with_info! {
/// Enumeration over the possible policy state information for all policies.
#[derive(PartialEq, Debug, Clone)]
pub enum PolicyInfo {
/// This value is reserved for testing purposes.
#[cfg(test)]
Unknown(UnknownInfo),
Audio(State),
}
}
/// This struct is reserved for testing purposes.
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[cfg(test)]
pub struct UnknownInfo(pub bool);
/// This trait implementation is reserved for testing purposes.
#[cfg(test)]
impl Into<PolicyInfo> for UnknownInfo {
fn into(self) -> PolicyInfo {
PolicyInfo::Unknown(self)
}
}
#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
pub enum Address {
// Policy(PolicyType),
}
#[derive(PartialEq, Clone, Debug)]
pub enum Payload {
Request(Request),
Response(Response),
}
payload_convert!(Policy, Payload);
/// `Role` defines grouping for responsibilities on the policy message hub.
#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
pub enum Role {
/// This role indicates that the messenger handles and enacts policy requests.
PolicyHandler,
}
/// `Request` defines the request space for all policies handled by
/// the Setting Service. Note that the actions that can be taken upon each
/// policy should be defined within each policy's Request enum.
#[derive(PartialEq, Debug, Clone)]
pub enum Request {
/// Fetches the current policy state.
Get,
/// Request targeted to the Audio policy.
Audio(audio::Request),
}
pub mod response {
use super::*;
pub type Response = Result<Payload, Error>;
/// `Payload` defines the possible successful responses for a request. There
/// should be a corresponding policy response payload type for each request type.
#[derive(PartialEq, Debug, Clone)]
pub enum Payload {
PolicyInfo(PolicyInfo),
Audio(audio::Response),
}
/// The possible errors that can be returned from a request. Note that
/// unlike the request and response space, errors are not type specific.
#[derive(Error, Debug, Clone, PartialEq)]
pub enum Error {
#[error("Unexpected error")]
Unexpected,
#[error("Communication error")]
CommunicationError,
#[error("Invalid input argument for policy: {0:?} argument:{1:?} value:{2:?}")]
InvalidArgument(PolicyType, Cow<'static, str>, Cow<'static, str>),
#[error("Write failed for policy: {0:?}")]
WriteFailure(PolicyType),
}
}
pub type BoxedHandler = Box<dyn PolicyHandler + Send + Sync>;
pub type GenerateHandlerResult = Result<BoxedHandler, Error>;
pub type GenerateHandler<T> =
Box<dyn Fn(Context<T>) -> BoxFuture<'static, GenerateHandlerResult> + Send + Sync>;
/// Context captures all details necessary for a policy handler to execute in a given
/// settings service environment.
pub struct Context<T: DeviceStorageFactory> {
pub policy_type: PolicyType,
pub service_messenger: service::message::Messenger,
pub storage_factory: Arc<T>,
pub id: u64,
}
/// A factory capable of creating a policy handler for a given setting on-demand. If no
/// viable handler can be created, None will be returned.
#[async_trait]
pub trait PolicyHandlerFactory {
async fn generate(
&mut self,
policy_type: PolicyType,
service_messenger: service::message::Messenger,
) -> Result<BoxedHandler, PolicyHandlerFactoryError>;
}
#[derive(thiserror::Error, Debug, Clone, PartialEq)]
pub enum PolicyHandlerFactoryError {
#[error("Policy type {0:?} not registered in environment")]
PolicyNotFound(PolicyType),
#[error("Setting type {0:?} for policy {0:?} not registered in environment")]
SettingNotFound(SettingType, PolicyType),
#[error("Cannot find policy handler generator for {0:?}")]
GeneratorNotFound(PolicyType),
#[error("Policy handler {0:?} failed to startup")]
HandlerStartupError(PolicyType),
}