omaha_client_service/
main.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![allow(clippy::let_unit_value)]
6
7use anyhow::{Context as _, Error, anyhow};
8use fuchsia_component::server::ServiceFs;
9use futures::lock::Mutex;
10use futures::prelude::*;
11use futures::stream::FuturesUnordered;
12use log::{error, info};
13use omaha_client::cup_ecdsa::StandardCupv2Handler;
14use omaha_client::state_machine::StateMachineBuilder;
15use omaha_client::time::StandardTimeSource;
16use omaha_client_fuchsia::{app_set, http_request, installer, timer};
17use std::cell::RefCell;
18use std::rc::Rc;
19
20mod api_metrics;
21mod channel;
22mod configuration;
23mod feedback_annotation;
24mod fidl;
25mod inspect;
26mod metrics;
27mod observer;
28mod policy;
29mod storage;
30
31use configuration::ClientConfiguration;
32
33#[fuchsia::main]
34pub fn main() -> Result<(), Error> {
35    info!("Starting omaha client...");
36
37    let mut executor = fuchsia_async::LocalExecutorBuilder::new().build();
38
39    executor.run_singlethreaded(main_inner()).map_err(|err| {
40        // Use anyhow to print the error chain.
41        let err = anyhow!(err);
42        error!("error running omaha-client: {:#}", err);
43        err
44    })
45}
46
47async fn main_inner() -> Result<(), Error> {
48    let channel_configs = channel::get_configs().ok();
49    info!("Omaha channel config: {:?}", channel_configs);
50
51    let ClientConfiguration { platform_config, app_set, channel_data } =
52        ClientConfiguration::initialize(channel_configs.as_ref())
53            .await
54            .expect("Unable to read necessary client configuration");
55
56    info!("Update config: {:?}", platform_config);
57
58    let futures = FuturesUnordered::new();
59
60    // Cobalt metrics
61    let (metrics_reporter, cobalt_fut) = metrics::CobaltMetricsReporter::new();
62    futures.push(cobalt_fut.boxed_local());
63
64    let (api_metrics_reporter, cobalt_fut) = api_metrics::CobaltApiMetricsReporter::new();
65    futures.push(cobalt_fut.boxed_local());
66
67    let mut fs = ServiceFs::new_local();
68    fs.take_and_serve_directory_handle().context("while serving directory handle")?;
69
70    // Inspect
71    let inspector = fuchsia_inspect::Inspector::default();
72    let _inspect_server_task =
73        inspect_runtime::publish(&inspector, inspect_runtime::PublishOptions::default());
74
75    let root = inspector.root();
76    let configuration_node = inspect::ConfigurationNode::new(root.create_child("configuration"));
77    configuration_node.set(&platform_config);
78    let apps_node = inspect::AppsNode::new(root.create_child("apps"));
79    apps_node.set(&app_set);
80    let state_node = inspect::StateNode::new(root.create_child("state"));
81    let schedule_node = inspect::ScheduleNode::new(root.create_child("schedule"));
82    let protocol_state_node = inspect::ProtocolStateNode::new(root.create_child("protocol_state"));
83    let last_results_node = inspect::LastResultsNode::new(root.create_child("last_results"));
84    let platform_metrics_node = root.create_child("platform_metrics");
85    root.record_string("channel_source", format!("{:?}", channel_data.source));
86
87    // HTTP
88    let http = http_request::FuchsiaHyperHttpRequest::new();
89
90    let cup_handler: Option<StandardCupv2Handler> =
91        platform_config.omaha_public_keys.as_ref().map(StandardCupv2Handler::new);
92
93    let app_set = Rc::new(Mutex::new(app_set));
94
95    // Installer
96    let installer = installer::FuchsiaInstaller::new(Rc::clone(&app_set));
97
98    // Storage
99    let stash = storage::Stash::new("omaha-client").await;
100    let stash_ref = Rc::new(Mutex::new(stash));
101
102    // Policy
103    let mut policy_engine_builder = policy::FuchsiaPolicyEngineBuilder::new_from_args()
104        .time_source(StandardTimeSource)
105        .metrics_reporter(metrics_reporter.clone());
106
107    if let Some(channel_config) = channel_data.config
108        && let Some(interval_secs) = channel_config.check_interval_secs
109    {
110        policy_engine_builder =
111            policy_engine_builder.periodic_interval(std::time::Duration::from_secs(interval_secs));
112    }
113
114    let policy_engine = policy_engine_builder.build();
115    futures.push(policy_engine.start_watching_ui_activity().boxed_local());
116    let policy_config = policy_engine.get_config();
117    let _policy_config_node =
118        inspect::PolicyConfigNode::new(root.create_child("policy_config"), policy_config);
119    let valid_service_url = !platform_config.service_url.is_empty();
120
121    // StateMachine
122    let (state_machine_control, state_machine) = StateMachineBuilder::new(
123        policy_engine,
124        http,
125        installer,
126        timer::FuchsiaTimer,
127        metrics_reporter,
128        Rc::clone(&stash_ref),
129        platform_config.clone(),
130        Rc::clone(&app_set),
131        cup_handler,
132    )
133    .start()
134    .await;
135
136    futures.push(feedback_annotation::publish_ids_to_feedback(Rc::clone(&app_set)).boxed_local());
137
138    // Serve FIDL API
139    let fidl = fidl::FidlServer::new(
140        state_machine_control,
141        stash_ref,
142        app_set,
143        apps_node,
144        state_node,
145        channel_configs,
146        Box::new(api_metrics_reporter),
147        channel_data.name,
148        valid_service_url,
149    );
150    let fidl = Rc::new(RefCell::new(fidl));
151
152    // Observe state machine events
153    let mut observer = observer::FuchsiaObserver::new(
154        Rc::clone(&fidl),
155        schedule_node,
156        protocol_state_node,
157        last_results_node,
158        platform_metrics_node,
159    );
160
161    futures.push(observer.start_handling_crash_reports());
162    futures.push(
163        async move {
164            futures::pin_mut!(state_machine);
165
166            while let Some(event) = state_machine.next().await {
167                observer.on_event(event).await;
168            }
169        }
170        .boxed_local(),
171    );
172    futures.push(fidl::FidlServer::run(fidl, fs).boxed_local());
173
174    futures.collect::<()>().await;
175    Ok(())
176}