update/
install.rs

1// Copyright 2020 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
5use anyhow::{Context, Error, anyhow};
6use fidl_fuchsia_update_installer::{InstallerMarker, InstallerProxy, RebootControllerMarker};
7use fidl_fuchsia_update_installer_ext::{self as installer, Options, StateId, start_update};
8use fuchsia_component::client::connect_to_protocol;
9use futures::prelude::*;
10
11pub async fn handle_force_install(
12    update_pkg_url: String,
13    reboot: bool,
14    service_initiated: bool,
15) -> Result<(), Error> {
16    let installer = connect_to_protocol::<InstallerMarker>()
17        .context("connecting to fuchsia.update.installer")?;
18    handle_force_install_impl(update_pkg_url, reboot, service_initiated, &installer).await
19}
20
21async fn handle_force_install_impl(
22    update_url: String,
23    reboot: bool,
24    service_initiated: bool,
25    installer: &InstallerProxy,
26) -> Result<(), Error> {
27    let update_url = update_url.parse().context("parsing update url")?;
28
29    let options = Options {
30        initiator: if service_initiated {
31            installer::Initiator::Service
32        } else {
33            installer::Initiator::User
34        },
35        should_write_recovery: true,
36        allow_attach_to_existing_attempt: true,
37    };
38
39    let (reboot_controller, reboot_controller_server_end) =
40        fidl::endpoints::create_proxy::<RebootControllerMarker>();
41
42    let mut update_attempt =
43        start_update(&update_url, options, installer, Some(reboot_controller_server_end), None)
44            .await
45            .context("starting update")?;
46
47    println!(
48        "Installing an update.
49Progress reporting is based on the fraction of packages resolved, so if one package is much
50larger than the others, then the reported progress could appear to stall near the end.
51Until the update process is improved to have more granular reporting, try using
52    ffx inspect show 'core/pkg-resolver'
53for more detail on the progress of update-related downloads.
54"
55    );
56    if !reboot {
57        reboot_controller.detach().context("notify installer do not reboot")?;
58    }
59    while let Some(state) = update_attempt.try_next().await.context("getting next state")? {
60        println!("State: {state:?}");
61        if state.id() == StateId::WaitToReboot {
62            if reboot {
63                return Ok(());
64            }
65        } else if state.is_success() {
66            return Ok(());
67        } else if state.is_failure() {
68            anyhow::bail!("Encountered failure state");
69        }
70    }
71
72    Err(anyhow!("Installation ended unexpectedly"))
73}