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 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 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 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 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 let installer = installer::FuchsiaInstaller::new(Rc::clone(&app_set));
97
98 let stash = storage::Stash::new("omaha-client").await;
100 let stash_ref = Rc::new(Mutex::new(stash));
101
102 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 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 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 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}