blob: e0084fd987bf5a6f3e65a8d70f3777d42f0fad84 [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 poller;
mod rate_limiter;
mod update_manager;
mod update_monitor;
mod update_service;
use {
crate::{
channel_handler::ChannelHandler,
config::Config,
poller::run_periodic_update_check,
update_service::{RealUpdateManager, UpdateService},
},
anyhow::{anyhow, Context as _, Error},
fidl_fuchsia_update_channel::ProviderRequestStream,
fidl_fuchsia_update_channelcontrol::ChannelControlRequestStream,
fidl_fuchsia_update_ext::{CheckOptions, Initiator},
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")?;
main_inner().await.map_err(|err| {
// Use anyhow to print the error chain.
let err = anyhow!(err);
fuchsia_syslog::fx_log_err!("error running system-update-checker: {:#}", err);
err
})
}
async fn main_inner() -> Result<(), Error> {
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 (mut update_manager, update_manager_fut) = RealUpdateManager::new(
Arc::clone(&target_channel_manager),
Arc::clone(&current_channel_manager),
inspector.root().create_child("update-manager"),
)
.await
.start();
futures.push(update_manager_fut.boxed());
let mut fs = ServiceFs::new();
let update_manager_clone = update_manager.clone();
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, UpdateService::new(update_manager_clone.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());
// In order to ensure cobalt gets a valid channel quickly, we sometimes perform an additional
// update check 60 seconds in.
futures.push(
async move {
if config.poll_frequency().is_some() {
fasync::Timer::new(fasync::Time::after(Duration::from_secs(60).into())).await;
let options = CheckOptions::builder().initiator(Initiator::Service).build();
if let Err(e) = update_manager.try_start_update(options, None).await {
fx_log_warn!("Update check failed with error: {:?}", e);
}
}
}
.boxed(),
);
futures.collect::<()>().await;
Ok(())
}
enum IncomingServices {
Manager(fidl_fuchsia_update::ManagerRequestStream, UpdateService),
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, mut 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
}
}
}