diff --git a/src/core/adb.rs b/src/core/adb.rs index 4441a9c..b33d933 100644 --- a/src/core/adb.rs +++ b/src/core/adb.rs @@ -242,6 +242,14 @@ impl ShellCommand { self.0.0.arg("reboot"); self.0.run() } + + /// Execute an arbitrary shell action string on the device's default shell. + /// The action string is passed as a single argument to `adb shell` and + /// interpreted by the remote shell (which splits on spaces). + pub fn raw(mut self, action: &str) -> Result { + self.0.0.arg(action); + self.0.run() + } } #[must_use] diff --git a/src/core/sync.rs b/src/core/sync.rs index 1235ef7..75750fa 100644 --- a/src/core/sync.rs +++ b/src/core/sync.rs @@ -1,14 +1,10 @@ use crate::core::{ - adb::{ACommand as AdbCommand, PM_CLEAR_PACK, to_trimmed_utf8}, + adb::{ACommand as AdbCommand, PM_CLEAR_PACK}, uad_lists::PackageState, }; use crate::gui::{views::list::PackageInfo, widgets::package_row::PackageRow}; use retry::{OperationResult, delay::Fixed, retry}; use serde::{Deserialize, Serialize}; -use std::process::Command; - -#[cfg(target_os = "windows")] -use std::os::windows::process::CommandExt; /// An Android device, typically a phone #[derive(Debug, Clone, PartialEq, Eq)] @@ -61,64 +57,21 @@ pub enum AdbError { Generic(String), } -/// # WARNING -/// Use `adb::ACommand::shell` with `async` blocks instead. -/// This `fn` is prone to abuse! -/// -/// # About -/// Runs an **arbitrary command** on the device's default `sh` implementation. -/// Typically MKSH, but could be Ash. -/// [More info](https://chromium.googlesource.com/aosp/platform/system/core/+/refs/heads/upstream/shell_and_utilities). -/// -/// If `serial` is empty, it lets ADB choose the default device. -pub async fn adb_shell_command>( +/// Run an arbitrary shell action via the typed ADB wrapper. +/// This replaces the deprecated `adb_shell_command`. +pub async fn run_adb_action>( device_serial: S, action: String, p: PackageInfo, ) -> Result { let serial = device_serial.as_ref(); - let label = &p.removal; - let mut cmd = Command::new("adb"); - if !serial.is_empty() { - cmd.args(["-s", serial]); - } - cmd.arg("shell"); - // this works because `sh` splits spaces - cmd.arg(&action); - - #[cfg(target_os = "windows")] - let cmd = cmd.creation_flags(0x0800_0000); // do not open a cmd window - - match match cmd.output() { - Err(e) => { - error!("ADB: {e}"); - Err("Cannot run ADB, likely not found".to_string()) - } + match AdbCommand::new().shell(serial).raw(&action) { Ok(o) => { - let stdout = to_trimmed_utf8(o.stdout); - if o.status.success() { - Ok(stdout) - } else { - let stderr = to_trimmed_utf8(o.stderr); - - // ADB does really weird things. Some errors are not redirected to stderr - let err = if stdout.is_empty() { stderr } else { stdout }; - Err(err) - } - } - } { - Ok(o) => { - // On old devices, adb commands can return the `0` exit code even if there - // is an error. On Android 4.4, ADB doesn't check if the package exists. - // It does not return any error if you try to `pm block` a non-existent package. - // Some commands are even killed by ADB before finishing and UAD-ng can't catch - // the output. if ["Error", "Failure"].iter().any(|&e| o.contains(e)) { return Err(AdbError::Generic(format!("[{label}] {action} -> {o}"))); } - info!("[{label}] {action} -> {o}"); Ok(p) } diff --git a/src/gui/views/list.rs b/src/gui/views/list.rs index 7b4295f..970a6e5 100644 --- a/src/gui/views/list.rs +++ b/src/gui/views/list.rs @@ -1,6 +1,6 @@ use crate::core::config::DeviceSettings; use crate::core::helpers::button_primary; -use crate::core::sync::{AdbError, Phone, User, adb_shell_command, apply_pkg_state_commands}; +use crate::core::sync::{AdbError, Phone, User, apply_pkg_state_commands, run_adb_action}; use crate::core::theme::Theme; use crate::core::uad_lists::{ Opposite, PackageHashMap, PackageState, Removal, UadList, UadListState, load_debloat_lists, @@ -1067,7 +1067,7 @@ fn build_action_pkg_commands( // In the end there is only one package state change // even if we run multiple adb commands commands.push(Task::perform( - adb_shell_command( + run_adb_action( // this is typically small, // so it's fine. device.adb_id.clone(), diff --git a/src/gui/views/settings.rs b/src/gui/views/settings.rs index 19a022c..2e6a24e 100644 --- a/src/gui/views/settings.rs +++ b/src/gui/views/settings.rs @@ -2,7 +2,7 @@ use crate::core::{ config::{BackupSettings, Config, DeviceSettings, GeneralSettings}, helpers::button_primary, save::{backup_phone, list_available_backup_user, list_available_backups, restore_backup}, - sync::{AdbError, Phone, User, adb_shell_command, get_android_sdk, supports_multi_user}, + sync::{AdbError, Phone, User, get_android_sdk, run_adb_action, supports_multi_user}, theme::Theme, utils::{ DisplayablePath, Error, NAME, export_packages, generate_backup_name, open_folder, open_url, @@ -183,7 +183,7 @@ impl Settings { commands.push(Task::perform( // This is "safe" thanks to serde: // https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/issues/760 - adb_shell_command(phone.adb_id.clone(), command, p_info.clone()), + run_adb_action(phone.adb_id.clone(), command, p_info.clone()), Message::RestoringDevice, )); }