| // 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 fuchsia_component::server::ServiceFs; |
| use futures::{lock::Mutex, prelude::*, stream::FuturesUnordered}; |
| use http_request::FuchsiaHyperHttpRequest; |
| use log::{error, info}; |
| use omaha_client::{state_machine::StateMachineBuilder, time::StandardTimeSource}; |
| use std::cell::RefCell; |
| use std::rc::Rc; |
| |
| mod channel; |
| mod cobalt; |
| mod configuration; |
| mod fidl; |
| mod http_request; |
| mod inspect; |
| mod install_plan; |
| mod installer; |
| mod metrics; |
| mod observer; |
| mod policy; |
| mod storage; |
| mod temp_installer; |
| mod timer; |
| |
| use configuration::ChannelSource; |
| |
| fn main() -> Result<(), Error> { |
| fuchsia_syslog::init().expect("Can't init logger"); |
| info!("Starting omaha client..."); |
| |
| let mut executor = fuchsia_async::Executor::new().context("Error creating executor")?; |
| |
| executor.run_singlethreaded(async { |
| let version = configuration::get_version().context("Failed to get version")?; |
| let channel_configs = channel::get_configs().ok(); |
| info!("Omaha channel config: {:?}", channel_configs); |
| let ((app_set, channel_source), config) = futures::join!( |
| configuration::get_app_set(&version, &channel_configs), |
| configuration::get_config(&version), |
| ); |
| info!("Omaha app set: {:?}", app_set.to_vec().await); |
| info!("Update config: {:?}", config); |
| |
| let futures = FuturesUnordered::new(); |
| |
| let (metrics_reporter, cobalt_fut) = metrics::CobaltMetricsReporter::new(); |
| futures.push(cobalt_fut.boxed_local()); |
| |
| let http = FuchsiaHyperHttpRequest::new(); |
| let installer = temp_installer::FuchsiaInstaller::new()?; |
| let stash = storage::Stash::new("omaha-client").await; |
| let stash_ref = Rc::new(Mutex::new(stash)); |
| let (state_machine_control, state_machine) = StateMachineBuilder::new( |
| policy::FuchsiaPolicyEngineBuilder.time_source(StandardTimeSource).build(), |
| http, |
| installer, |
| timer::FuchsiaTimer, |
| StandardTimeSource, |
| metrics_reporter, |
| stash_ref.clone(), |
| config.clone(), |
| app_set.clone(), |
| ) |
| .start() |
| .await; |
| |
| let mut fs = ServiceFs::new_local(); |
| fs.take_and_serve_directory_handle()?; |
| let inspector = fuchsia_inspect::Inspector::new(); |
| inspector.serve(&mut fs)?; |
| let root = inspector.root(); |
| let configuration_node = |
| inspect::ConfigurationNode::new(root.create_child("configuration")); |
| configuration_node.set(&config); |
| let apps_node = inspect::AppsNode::new(root.create_child("apps")); |
| apps_node.set(&app_set.to_vec().await); |
| let state_node = inspect::StateNode::new(root.create_child("state")); |
| let schedule_node = inspect::ScheduleNode::new(root.create_child("schedule")); |
| let protocol_state_node = |
| inspect::ProtocolStateNode::new(root.create_child("protocol_state")); |
| let last_results_node = inspect::LastResultsNode::new(root.create_child("last_results")); |
| let platform_metrics_node = root.create_child("platform_metrics"); |
| let _channel_source_property = |
| root.create_string("channel_source", format!("{:?}", channel_source)); |
| |
| let notify_cobalt = |
| channel_source == ChannelSource::VbMeta || channel_source == ChannelSource::SysConfig; |
| if notify_cobalt { |
| futures.push(cobalt::notify_cobalt_current_channel(app_set.clone()).boxed_local()); |
| } |
| |
| let fidl = fidl::FidlServer::new( |
| state_machine_control, |
| stash_ref, |
| app_set.clone(), |
| apps_node, |
| state_node, |
| channel_configs, |
| ); |
| let fidl = Rc::new(RefCell::new(fidl)); |
| |
| let mut observer = observer::FuchsiaObserver::new( |
| Rc::clone(&fidl), |
| schedule_node, |
| protocol_state_node, |
| last_results_node, |
| app_set, |
| notify_cobalt, |
| platform_metrics_node, |
| ); |
| |
| futures.push( |
| async move { |
| futures::pin_mut!(state_machine); |
| |
| while let Some(event) = state_machine.next().await { |
| observer.on_event(event).await; |
| } |
| } |
| .boxed_local(), |
| ); |
| futures.push(fidl::FidlServer::run(fidl, fs).boxed_local()); |
| |
| futures.push(check_and_set_system_health().boxed_local()); |
| |
| futures.collect::<()>().await; |
| Ok(()) |
| }) |
| } |
| |
| async fn check_and_set_system_health() { |
| if let Err(err) = system_health_check::check_system_health().await { |
| error!("error during system health check: {}", err); |
| return; |
| } |
| info!("Marking current slot as good..."); |
| system_health_check::set_active_configuration_healthy().await; |
| } |