chore: replace deprecated adb_shell_command with run_adb_action

This commit is contained in:
iamanaws 2025-10-23 00:53:38 -07:00
commit 4ab886490e
4 changed files with 17 additions and 56 deletions

View file

@ -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<String, String> {
self.0.0.arg(action);
self.0.run()
}
}
#[must_use]

View file

@ -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<S: AsRef<str>>(
/// Run an arbitrary shell action via the typed ADB wrapper.
/// This replaces the deprecated `adb_shell_command`.
pub async fn run_adb_action<S: AsRef<str>>(
device_serial: S,
action: String,
p: PackageInfo,
) -> Result<PackageInfo, AdbError> {
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)
}

View file

@ -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(),

View file

@ -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,
));
}