blob: 779562fc3d2f1ed95f1f48ba15fc2f1a1a80c841 [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.
mod apply;
mod channel;
mod channel_handler;
mod check;
mod config;
mod connect;
mod errors;
mod last_update_storage;
mod poller;
mod rate_limiter;
mod update_manager;
mod update_monitor;
mod update_service;
use {
crate::{
apply::Initiator,
channel_handler::ChannelHandler,
config::Config,
poller::run_periodic_update_check,
update_service::{RealUpdateManager, RealUpdateService},
},
anyhow::{anyhow, Context as _, Error},
fidl_fuchsia_update_channel::ProviderRequestStream,
fidl_fuchsia_update_channelcontrol::ChannelControlRequestStream,
forced_fdr::perform_fdr_if_necessary,
fuchsia_async as fasync,
fuchsia_component::server::ServiceFs,
fuchsia_inspect as finspect,
fuchsia_syslog::{fx_log_err, fx_log_warn},
futures::{prelude::*, stream::FuturesUnordered},
std::{sync::Arc, time::Duration},
};
const MAX_CONCURRENT_CONNECTIONS: usize = 100;
#[fasync::run(1)]
async fn main() -> Result<(), Error> {
fuchsia_syslog::init_with_tags(&["system-update-checker"]).context("syslog init failed")?;
let config = Config::load_from_config_data_or_default();
if let Some(url) = config.update_package_url() {
fx_log_warn!("Ignoring custom update package url: {}", url);
}
let inspector = finspect::Inspector::new();
let target_channel_manager =
channel::TargetChannelManager::new(connect::ServiceConnector, "/misc/ota");
if let Err(e) = target_channel_manager.update().await {
fx_log_err!("while updating the target channel: {:#}", anyhow!(e));
}
let target_channel_manager = Arc::new(target_channel_manager);
let futures = FuturesUnordered::new();
let (current_channel_manager, current_channel_notifier) =
channel::build_current_channel_manager_and_notifier(
connect::ServiceConnector,
"/misc/ota",
)?;
futures.push(current_channel_notifier.run().boxed());
let current_channel_manager = Arc::new(current_channel_manager);
let update_manager = RealUpdateManager::new(
Arc::clone(&target_channel_manager),
Arc::clone(&current_channel_manager),
inspector.root().create_child("update-manager"),
)
.await;
let update_manager = Arc::new(update_manager);
let mut fs = ServiceFs::new();
let update_manager_clone = Arc::clone(&update_manager);
let channel_handler =
Arc::new(ChannelHandler::new(current_channel_manager, target_channel_manager));
let channel_handler_clone = Arc::clone(&channel_handler);
let channel_handler_provider_clone = Arc::clone(&channel_handler);
fs.dir("svc")
.add_fidl_service(move |stream| {
IncomingServices::Manager(
stream,
RealUpdateService::new(Arc::clone(&update_manager_clone)),
)
})
.add_fidl_service(move |stream| {
IncomingServices::Provider(stream, Arc::clone(&channel_handler_provider_clone))
})
.add_fidl_service(move |stream| {
IncomingServices::ChannelControl(stream, Arc::clone(&channel_handler_clone))
});
inspector.serve(&mut fs)?;
fs.take_and_serve_directory_handle().context("ServiceFs::take_and_serve_directory_handle")?;
futures.push(
fs.for_each_concurrent(MAX_CONCURRENT_CONNECTIONS, |incoming_service| {
handle_incoming_service(incoming_service).unwrap_or_else(|e| {
fx_log_err!("error handling client connection: {:#}", anyhow!(e))
})
})
.boxed(),
);
futures.push(run_periodic_update_check(update_manager.clone(), &config).boxed());
futures.push(
async move {
if config.poll_frequency().is_some() {
fasync::Timer::new(fasync::Time::after(Duration::from_secs(60).into())).await;
if let Err(e) =
update_manager.try_start_update(Initiator::Automatic, None, None).await
{
fx_log_warn!("Update check failed with error: {:?}", e);
}
}
}
.boxed(),
);
futures.push(perform_fdr_if_necessary().boxed());
futures.push(check_and_set_system_health().boxed());
futures.collect::<()>().await;
Ok(())
}
enum IncomingServices {
Manager(fidl_fuchsia_update::ManagerRequestStream, RealUpdateService),
Provider(ProviderRequestStream, Arc<ChannelHandler>),
ChannelControl(ChannelControlRequestStream, Arc<ChannelHandler>),
}
async fn handle_incoming_service(incoming_service: IncomingServices) -> Result<(), Error> {
match incoming_service {
IncomingServices::Manager(request_stream, update_service) => {
update_service.handle_request_stream(request_stream).await
}
IncomingServices::Provider(request_stream, handler) => {
handler.handle_provider_request_stream(request_stream).await
}
IncomingServices::ChannelControl(request_stream, handler) => {
handler.handle_control_request_stream(request_stream).await
}
}
}
async fn check_and_set_system_health() {
if let Err(err) = check_and_set_system_health_impl().await {
fx_log_err!("error during system health check: {:#}", anyhow!(err));
}
}
async fn check_and_set_system_health_impl() -> Result<(), Error> {
system_health_check::check_system_health().await?;
Ok(system_health_check::set_active_configuration_healthy().await)
}