blob: 66758ae036faef535a455143be8a5a76beb5ace4 [file] [log] [blame]
// Copyright 2019 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 anyhow::{Context as _, Error};
use brightness_manager_config::Config;
use fuchsia_component::server::ServiceObjLocal;
use fuchsia_inspect::component::inspector;
use futures::lock::Mutex;
use futures::prelude::*;
use std::pin::Pin;
use std::sync::Arc;
// Include Brightness Control FIDL bindings
use control::{
Control, ControlTrait, WatcherAdjustmentResponder, WatcherAutoResponder,
WatcherCurrentResponder,
};
use fidl_fuchsia_ui_brightness::ControlRequestStream;
use fuchsia_async::{self as fasync};
use fuchsia_component::server::ServiceFs;
use futures::channel::mpsc::UnboundedReceiver;
use futures::future::{AbortHandle, Abortable};
use lib::backlight::Backlight;
use lib::sensor::Sensor;
use sender_channel::SenderChannel;
use watch_handler::WatchHandler;
mod control;
mod sender_channel;
const ADJUSTMENT_DELTA: f32 = 0.1;
async fn run_brightness_server(
mut stream: ControlRequestStream,
control: Arc<Mutex<dyn ControlTrait>>,
) -> Result<(), Error> {
let (initial_current, initial_auto) = get_initial_value(control.clone()).await?;
let watch_auto_handler: Arc<Mutex<WatchHandler<bool, WatcherAutoResponder>>> =
Arc::new(Mutex::new(WatchHandler::create(Some(initial_auto))));
let (auto_channel_sender, auto_channel_receiver) = futures::channel::mpsc::unbounded::<bool>();
let watch_current_handler: Arc<Mutex<WatchHandler<f32, WatcherCurrentResponder>>> =
Arc::new(Mutex::new(WatchHandler::create(Some(initial_current))));
let (current_channel_sender, current_channel_receiver) =
futures::channel::mpsc::unbounded::<f32>();
let watch_adjustment_handler: Arc<Mutex<WatchHandler<f32, WatcherAdjustmentResponder>>> =
Arc::new(Mutex::new(WatchHandler::create_with_change_fn(
Box::new(move |old_data: &f32, new_data: &f32| {
(*new_data - *old_data).abs() >= ADJUSTMENT_DELTA
}),
Some(0.0),
)));
let (adjustment_channel_sender, adjustment_channel_receiver) =
futures::channel::mpsc::unbounded::<f32>();
let control_clone = control.clone();
{
let mut control = control_clone.lock().await;
control.add_current_sender_channel(current_channel_sender).await;
control.add_auto_sender_channel(auto_channel_sender).await;
control.add_adjustment_sender_channel(adjustment_channel_sender).await;
}
let listen_current_task_abort_handle = start_listen_task(
watch_current_handler.clone(),
Arc::new(Mutex::new(current_channel_receiver)),
);
let listen_auto_task_abort_handle =
start_listen_task(watch_auto_handler.clone(), Arc::new(Mutex::new(auto_channel_receiver)));
let listen_adjustment_task_abort_handle = start_listen_task(
watch_adjustment_handler.clone(),
Arc::new(Mutex::new(adjustment_channel_receiver)),
);
while let Some(request) = stream.try_next().await.context("error running brightness server")? {
let mut control = control.lock().await;
control
.handle_request(
request,
watch_current_handler.clone(),
watch_auto_handler.clone(),
watch_adjustment_handler.clone(),
)
.await;
}
listen_current_task_abort_handle.abort();
listen_auto_task_abort_handle.abort();
listen_adjustment_task_abort_handle.abort();
Ok(())
}
fn start_listen_task<T: std::marker::Send, ST: std::marker::Send>(
watch_handler: Arc<Mutex<WatchHandler<T, ST>>>,
receiver: Arc<Mutex<UnboundedReceiver<T>>>,
) -> AbortHandle
where
T: std::clone::Clone + 'static,
ST: watch_handler::Sender<T> + 'static,
{
let (abort_handle, abort_registration) = AbortHandle::new_pair();
let receiver = receiver.clone();
fasync::Task::spawn(
Abortable::new(
async move {
while let Some(value) = receiver.lock().await.next().await {
let mut handler_lock = watch_handler.lock().await;
handler_lock.set_value(value);
}
},
abort_registration,
)
.unwrap_or_else(|_| ()),
)
.detach();
abort_handle
}
async fn get_initial_value(control: Arc<Mutex<dyn ControlTrait>>) -> Result<(f32, bool), Error> {
let mut control = control.lock().await;
let (backlight, auto_brightness_on) = control.get_backlight_and_auto_brightness_on();
let initial_brightness = backlight.get_brightness().await.unwrap_or_else(|e| {
tracing::warn!(
"Didn't get the initial brightness in watch due to err {}, assuming 1.0.",
e
);
1.0
});
Ok((initial_brightness as f32, auto_brightness_on))
}
async fn run_brightness_service(
fs: ServiceFs<ServiceObjLocal<'static, ControlRequestStream>>,
control: Arc<Mutex<dyn ControlTrait>>,
run_server: impl Fn(
ControlRequestStream,
Arc<Mutex<dyn ControlTrait>>,
) -> Pin<Box<dyn Future<Output = Result<(), Error>>>>,
) -> Result<(), Error> {
const MAX_CONCURRENT: usize = 10_000;
let fut = fs.for_each_concurrent(MAX_CONCURRENT, |stream| {
let control = control.clone();
run_server(stream, control).unwrap_or_else(|e| tracing::info!("{:?}", e))
});
fut.await;
Ok(())
}
#[fuchsia::main(logging_tags = ["auto-brightness"])]
async fn main() -> Result<(), Error> {
tracing::info!("Started");
let config = Config::take_from_startup_handle();
inspector().root().record_child("config", |config_node| config.record_inspect(config_node));
let mut fs = ServiceFs::new_local();
fs.dir("svc").add_fidl_service(|stream: ControlRequestStream| stream);
fs.take_and_serve_directory_handle()?;
let inspector = inspector();
let _inspect_server_task =
inspect_runtime::publish(inspector, inspect_runtime::PublishOptions::default());
let backlight = if config.manage_display_power {
Backlight::with_display_power(config.power_off_delay_millis, config.power_on_delay_millis)
.await?
} else {
Backlight::without_display_power()?
};
let backlight = Arc::new(backlight);
let sensor = Sensor::new().await;
let sensor = Arc::new(Mutex::new(sensor));
let current_sender_channel: SenderChannel<f32> = SenderChannel::new();
let current_sender_channel = Arc::new(Mutex::new(current_sender_channel));
let auto_sender_channel: SenderChannel<bool> = SenderChannel::new();
let auto_sender_channel = Arc::new(Mutex::new(auto_sender_channel));
let adjustment_sender_channel: SenderChannel<f32> = SenderChannel::new();
let adjustment_sender_channel = Arc::new(Mutex::new(adjustment_sender_channel));
let control = Control::new(
sensor,
backlight,
current_sender_channel,
auto_sender_channel,
adjustment_sender_channel,
)
.await;
let control = Arc::new(Mutex::new(control));
run_brightness_service(fs, control, |stream, control| {
Box::pin(run_brightness_server(stream, control))
})
.await?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
fn mock_sender_channel() -> SenderChannel<f64> {
SenderChannel::new()
}
#[fasync::run_singlethreaded(test)]
async fn test_send_value_in_channel_without_remove_any_sender() {
let (channel_sender1, mut channel_receiver1) = futures::channel::mpsc::unbounded::<f64>();
let (channel_sender2, mut channel_receiver2) = futures::channel::mpsc::unbounded::<f64>();
let mut mock_sender_channel = mock_sender_channel();
mock_sender_channel.add_sender_channel(channel_sender1).await;
mock_sender_channel.add_sender_channel(channel_sender2).await;
mock_sender_channel.send_value(12.0);
assert_eq!(Some(12.0), channel_receiver1.next().await);
assert_eq!(Some(12.0), channel_receiver2.next().await);
}
#[fasync::run_singlethreaded(test)]
async fn test_send_value_in_channel_with_remove_a_sender() {
let (channel_sender1, mut channel_receiver1) = futures::channel::mpsc::unbounded::<f64>();
let (channel_sender2, mut channel_receiver2) = futures::channel::mpsc::unbounded::<f64>();
let mut mock_sender_channel = mock_sender_channel();
mock_sender_channel.add_sender_channel(channel_sender1).await;
mock_sender_channel.add_sender_channel(channel_sender2).await;
mock_sender_channel.sender_channel_vec.write()[0].close_channel();
mock_sender_channel.send_value(12.0);
assert_eq!(None, channel_receiver1.next().await);
assert_eq!(Some(12.0), channel_receiver2.next().await);
}
}