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 config = omaha_client_structured_config::Config::take_from_startup_handle();
52
53    let ClientConfiguration { platform_config, app_set, channel_data } =
54        ClientConfiguration::initialize(channel_configs.as_ref(), &config)
55            .await
56            .expect("Unable to read necessary client configuration");
57
58    info!("Update config: {:?}", platform_config);
59
60    let futures = FuturesUnordered::new();
61
62    // Cobalt metrics
63    let (metrics_reporter, cobalt_fut) = metrics::CobaltMetricsReporter::new();
64    futures.push(cobalt_fut.boxed_local());
65
66    let (api_metrics_reporter, cobalt_fut) = api_metrics::CobaltApiMetricsReporter::new();
67    futures.push(cobalt_fut.boxed_local());
68
69    let mut fs = ServiceFs::new_local();
70    fs.take_and_serve_directory_handle().context("while serving directory handle")?;
71
72    // Inspect
73    let inspector = fuchsia_inspect::Inspector::default();
74    let _inspect_server_task =
75        inspect_runtime::publish(&inspector, inspect_runtime::PublishOptions::default());
76
77    let root = inspector.root();
78    let configuration_node = inspect::ConfigurationNode::new(root.create_child("configuration"));
79    configuration_node.set(&platform_config);
80    let apps_node = inspect::AppsNode::new(root.create_child("apps"));
81    apps_node.set(&app_set);
82    let state_node = inspect::StateNode::new(root.create_child("state"));
83    let schedule_node = inspect::ScheduleNode::new(root.create_child("schedule"));
84    let protocol_state_node = inspect::ProtocolStateNode::new(root.create_child("protocol_state"));
85    let last_results_node = inspect::LastResultsNode::new(root.create_child("last_results"));
86    let platform_metrics_node = root.create_child("platform_metrics");
87    root.record_string("channel_source", format!("{:?}", channel_data.source));
88
89    // HTTP
90    let http = http_request::FuchsiaHyperHttpRequest::new();
91
92    let cup_handler: Option<StandardCupv2Handler> =
93        platform_config.omaha_public_keys.as_ref().map(StandardCupv2Handler::new);
94
95    let app_set = Rc::new(Mutex::new(app_set));
96
97    // Installer
98    let installer = installer::FuchsiaInstaller::new(Rc::clone(&app_set));
99
100    // Storage
101    let stash = storage::Stash::new("omaha-client").await;
102    let stash_ref = Rc::new(Mutex::new(stash));
103
104    // Policy
105    let mut policy_engine_builder = policy::FuchsiaPolicyEngineBuilder::new_from_config(config)
106        .time_source(StandardTimeSource)
107        .metrics_reporter(metrics_reporter.clone());
108
109    if let Some(channel_config) = channel_data.config
110        && let Some(interval_secs) = channel_config.check_interval_secs
111    {
112        policy_engine_builder =
113            policy_engine_builder.periodic_interval(std::time::Duration::from_secs(interval_secs));
114    }
115
116    let policy_engine = policy_engine_builder.build();
117    futures.push(policy_engine.start_watching_ui_activity().boxed_local());
118    let policy_config = policy_engine.get_config();
119    let _policy_config_node =
120        inspect::PolicyConfigNode::new(root.create_child("policy_config"), policy_config);
121    let valid_service_url = !platform_config.service_url.is_empty();
122
123    // StateMachine
124    let (state_machine_control, state_machine) = StateMachineBuilder::new(
125        policy_engine,
126        http,
127        installer,
128        timer::FuchsiaTimer,
129        metrics_reporter,
130        Rc::clone(&stash_ref),
131        platform_config.clone(),
132        Rc::clone(&app_set),
133        cup_handler,
134    )
135    .start()
136    .await;
137
138    futures.push(feedback_annotation::publish_ids_to_feedback(Rc::clone(&app_set)).boxed_local());
139
140    // Serve FIDL API
141    let fidl = fidl::FidlServer::new(
142        state_machine_control,
143        stash_ref,
144        app_set,
145        apps_node,
146        state_node,
147        channel_configs,
148        Box::new(api_metrics_reporter),
149        channel_data.name,
150        valid_service_url,
151    );
152    let fidl = Rc::new(RefCell::new(fidl));
153
154    // Observe state machine events
155    let mut observer = observer::FuchsiaObserver::new(
156        Rc::clone(&fidl),
157        schedule_node,
158        protocol_state_node,
159        last_results_node,
160        platform_metrics_node,
161    );
162
163    futures.push(observer.start_handling_crash_reports());
164    futures.push(
165        async move {
166            futures::pin_mut!(state_machine);
167
168            while let Some(event) = state_machine.next().await {
169                observer.on_event(event).await;
170            }
171        }
172        .boxed_local(),
173    );
174    futures.push(fidl::FidlServer::run(fidl, fs).boxed_local());
175
176    futures.collect::<()>().await;
177    Ok(())
178}