From 7080e84224053b5e047a7aa15af42a4fc4ed0f51 Mon Sep 17 00:00:00 2001 From: E1int <110526002+E1int@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:55:21 +0000 Subject: [PATCH] refactor(launcher): refactor client APK installation from launcher (#2531) * Refactor client APK installation from launcher * Apply requested changes --- Cargo.lock | 142 +++++++++++++---------------------- alvr/adb/src/commands.rs | 2 +- alvr/adb/src/lib.rs | 8 +- alvr/launcher/Cargo.toml | 2 + alvr/launcher/src/actions.rs | 140 +++++++++++++++------------------- 5 files changed, 122 insertions(+), 172 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79b84d4af1..9dabb901b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -338,7 +338,9 @@ dependencies = [ name = "alvr_launcher" version = "20.11.1" dependencies = [ + "alvr_adb", "alvr_common", + "alvr_filesystem", "alvr_gui_common", "anyhow", "eframe", @@ -346,7 +348,7 @@ dependencies = [ "futures-util", "ico", "open", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde_json", "tar", "tokio", @@ -1090,7 +1092,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.70", ] @@ -1110,7 +1112,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.70", ] @@ -1251,9 +1253,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.8.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bzip2" @@ -2627,9 +2629,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -2782,9 +2784,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -2799,7 +2801,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2847,16 +2849,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -2867,13 +2869,13 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "rustls", "rustls-pki-types", @@ -2898,20 +2900,19 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.10" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.4.1", + "http-body 1.0.1", + "hyper 1.5.0", "pin-project-lite", "socket2 0.5.7", "tokio", - "tower", "tower-service", "tracing", ] @@ -3491,7 +3492,7 @@ dependencies = [ "indexmap", "log", "num-traits", - "rustc-hash", + "rustc-hash 1.1.0", "spirv", "termcolor", "thiserror", @@ -4207,26 +4208,6 @@ version = "0.5.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.70", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -4421,16 +4402,17 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", + "socket2 0.5.7", "thiserror", "tokio", "tracing", @@ -4438,14 +4420,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.8" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", "ring", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "slab", "thiserror", @@ -4455,9 +4437,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.4" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" dependencies = [ "libc", "once_cell", @@ -4689,19 +4671,19 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", "futures-core", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-rustls", "hyper-util", "ipnet", @@ -4713,7 +4695,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -4818,6 +4800,12 @@ version = "1.1.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustix" version = "0.37.27" @@ -4871,19 +4859,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.2.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -5674,27 +5661,6 @@ dependencies = [ "winnow 0.6.13", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - [[package]] name = "tower-service" version = "0.3.2" @@ -5837,7 +5803,7 @@ version = "0.5.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -6079,9 +6045,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -6291,7 +6257,7 @@ dependencies = [ "parking_lot", "profiling", "raw-window-handle 0.6.2", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror", "web-sys", @@ -6335,7 +6301,7 @@ dependencies = [ "range-alloc", "raw-window-handle 0.6.2", "renderdoc-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror", "wasm-bindgen", diff --git a/alvr/adb/src/commands.rs b/alvr/adb/src/commands.rs index 03d0c778be..5457f7b251 100644 --- a/alvr/adb/src/commands.rs +++ b/alvr/adb/src/commands.rs @@ -34,7 +34,7 @@ fn get_command(adb_path: &str, args: &[&str]) -> Command { command } -fn download(url: &str, progress_callback: impl Fn(usize, Option)) -> Result> { +pub fn download(url: &str, progress_callback: impl Fn(usize, Option)) -> Result> { let agent = ureq::builder() .timeout_connect(REQUEST_TIMEOUT) .timeout_read(REQUEST_TIMEOUT) diff --git a/alvr/adb/src/lib.rs b/alvr/adb/src/lib.rs index a0ee62e009..9308d65a55 100644 --- a/alvr/adb/src/lib.rs +++ b/alvr/adb/src/lib.rs @@ -1,4 +1,4 @@ -mod commands; +pub mod commands; mod parse; use alvr_common::anyhow::Result; @@ -6,9 +6,9 @@ use alvr_common::{dbg_connection, error}; use alvr_session::{ClientFlavor, ConnectionConfig}; use std::collections::HashSet; -const PACKAGE_NAME_STORE: &str = "alvr.client"; -const PACKAGE_NAME_GITHUB_DEV: &str = "alvr.client.dev"; -const PACKAGE_NAME_GITHUB_STABLE: &str = "alvr.client.stable"; +pub const PACKAGE_NAME_STORE: &str = "alvr.client"; +pub const PACKAGE_NAME_GITHUB_DEV: &str = "alvr.client.dev"; +pub const PACKAGE_NAME_GITHUB_STABLE: &str = "alvr.client.stable"; pub enum WiredConnectionStatus { Ready, diff --git a/alvr/launcher/Cargo.toml b/alvr/launcher/Cargo.toml index 3469c294b0..5f8bae2f1f 100644 --- a/alvr/launcher/Cargo.toml +++ b/alvr/launcher/Cargo.toml @@ -7,7 +7,9 @@ authors.workspace = true license.workspace = true [dependencies] +alvr_adb.workspace = true alvr_common.workspace = true +alvr_filesystem.workspace = true alvr_gui_common.workspace = true anyhow = "1" diff --git a/alvr/launcher/src/actions.rs b/alvr/launcher/src/actions.rs index 8b0759e0d2..9743b2c4cb 100644 --- a/alvr/launcher/src/actions.rs +++ b/alvr/launcher/src/actions.rs @@ -1,8 +1,8 @@ use crate::{ InstallationInfo, Progress, ReleaseChannelsInfo, ReleaseInfo, UiMessage, WorkerMessage, }; -use alvr_common::{anyhow::Result, ToAny}; -use anyhow::bail; +use alvr_common::{anyhow::Result, semver::Version, ToAny}; +use anyhow::{bail, Context}; use flate2::read::GzDecoder; use futures_util::StreamExt; use std::{ @@ -14,21 +14,6 @@ use std::{ sync::mpsc::{Receiver, Sender}, }; -#[cfg(not(windows))] -const ADB_EXECUTABLE: &str = "adb"; -#[cfg(windows)] -const ADB_EXECUTABLE: &str = "adb.exe"; - -#[cfg(target_os = "linux")] -const PLATFORM_TOOLS_DL_LINK: &str = - "https://dl.google.com/android/repository/platform-tools-latest-linux.zip"; -#[cfg(target_os = "macos")] -const PLATFORM_TOOLS_DL_LINK: &str = - "https://dl.google.com/android/repository/platform-tools-latest-macos.zip"; -#[cfg(windows)] -const PLATFORM_TOOLS_DL_LINK: &str = - "https://dl.google.com/android/repository/platform-tools-latest-windows.zip"; - const APK_NAME: &str = "client.apk"; pub fn installations_dir() -> PathBuf { @@ -68,7 +53,7 @@ pub fn worker( install_server(&worker_message_sender, release, &client).await } UiMessage::InstallClient(release_info) => { - install_apk(&worker_message_sender, release_info, &client).await + install_and_launch_apk(&worker_message_sender, release_info) } }; match res { @@ -137,85 +122,82 @@ pub fn get_release( }) } -async fn install_apk( +fn install_and_launch_apk( worker_message_sender: &Sender, release: ReleaseInfo, - client: &reqwest::Client, ) -> anyhow::Result<()> { worker_message_sender.send(WorkerMessage::ProgressUpdate(Progress { message: "Starting install".into(), progress: 0.0, }))?; - let installation_dir = installations_dir().join(&release.version); - - let apk_path = installation_dir.clone().join(APK_NAME); - + let root = installations_dir().join(&release.version); + let apk_name = "alvr_client_android.apk"; + let apk_path = root.join(apk_name); if !apk_path.exists() { - let apk_buffer = download( - worker_message_sender, - "Downloading Client APK", - release - .assets - .get("alvr_client_android.apk") - .ok_or(anyhow::anyhow!("Unable to determine download URL"))?, - client, - ) - .await?; - + let apk_url = release + .assets + .get(apk_name) + .ok_or(anyhow::anyhow!("Unable to determine download URL"))?; + let apk_buffer = alvr_adb::commands::download(apk_url, |downloaded, total| { + let progress = total.map(|t| downloaded as f32 / t as f32).unwrap_or(0.0); + worker_message_sender + .send(WorkerMessage::ProgressUpdate(Progress { + message: "Downloading Client APK".into(), + progress, + })) + .ok(); + })?; let mut file = File::create(&apk_path)?; file.write_all(&apk_buffer)?; } + let layout = alvr_filesystem::Layout::new(&root); + let adb_path = alvr_adb::commands::require_adb(&layout, |downloaded, total| { + let progress = total.map(|t| downloaded as f32 / t as f32).unwrap_or(0.0); + worker_message_sender + .send(WorkerMessage::ProgressUpdate(Progress { + message: "Downloading ADB".into(), + progress, + })) + .ok(); + })?; + + let device_serial = alvr_adb::commands::list_devices(&adb_path)? + .iter() + .find_map(|d| d.serial.clone()) + .ok_or(anyhow::anyhow!("Failed to find connected device"))?; + + let v = if release.version.starts_with('v') { + release.version[1..].to_string() + } else { + release.version + }; + let version = Version::parse(&v).context("Failed to parse release version")?; + let stable = version.pre.is_empty() && !version.build.contains("nightly"); + let application_id = if stable { + alvr_adb::PACKAGE_NAME_GITHUB_STABLE + } else { + alvr_adb::PACKAGE_NAME_GITHUB_DEV + }; + + if alvr_adb::commands::is_package_installed(&adb_path, &device_serial, application_id)? { + worker_message_sender.send(WorkerMessage::ProgressUpdate(Progress { + message: "Uninstalling old APK".into(), + progress: 0.0, + }))?; + alvr_adb::commands::uninstall_package(&adb_path, &device_serial, application_id)?; + } + worker_message_sender.send(WorkerMessage::ProgressUpdate(Progress { - message: "Installing APK".into(), + message: "Installing new APK".into(), progress: 0.0, }))?; + alvr_adb::commands::install_package(&adb_path, &device_serial, &apk_path.to_string_lossy())?; - let res = match Command::new(ADB_EXECUTABLE) - .arg("install") - .arg("-d") - .arg(&apk_path) - .output() - { - Ok(res) => res, - Err(_) => { - let adb_path = data_dir().join("platform-tools").join(ADB_EXECUTABLE); - - if !adb_path.exists() { - let mut buffer = Cursor::new( - download( - worker_message_sender, - "Downloading Android Platform Tools", - PLATFORM_TOOLS_DL_LINK, - client, - ) - .await?, - ); - - zip::ZipArchive::new(&mut buffer)?.extract(data_dir())?; - } - - worker_message_sender.send(WorkerMessage::ProgressUpdate(Progress { - message: "Installing APK".into(), - progress: 0.0, - }))?; + alvr_adb::commands::start_application(&adb_path, &device_serial, application_id)?; - Command::new(adb_path) - .arg("install") - .arg("-r") - .arg(&apk_path) - .output()? - } - }; - if res.status.success() { - Ok(()) - } else { - Err(anyhow::anyhow!( - "ADB install failed: {}", - String::from_utf8_lossy(&res.stderr) - )) - } + Ok(()) } async fn download(