omaha_client_service/
main.rs1#![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 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 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 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 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 let installer = installer::FuchsiaInstaller::new(Rc::clone(&app_set));
99
100 let stash = storage::Stash::new("omaha-client").await;
102 let stash_ref = Rc::new(Mutex::new(stash));
103
104 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 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 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 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}