Skip to content

Commit

Permalink
refactor: use AdbCmd, finish list_packs and add list_users
Browse files Browse the repository at this point in the history
  • Loading branch information
Rudxain committed Dec 8, 2024
1 parent 5674c9f commit f6fb9b6
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 32 deletions.
109 changes: 80 additions & 29 deletions src/core/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl std::fmt::Display for Device {
}
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Copy)]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct User {
pub id: u16,
pub index: usize,
Expand All @@ -66,6 +66,8 @@ impl std::fmt::Display for User {
///
/// This is not intended to model the entire ADB API.
/// It only models the subset that concerns UADNG.
///
/// [More info here](https://developer.android.com/tools/adb)
#[derive(Debug)]
pub struct AdbCmd(Command);
impl AdbCmd {
Expand All @@ -74,8 +76,9 @@ impl AdbCmd {
}
/// If `device_serial` is empty, it lets ADB choose the default device.
pub fn shell<S: AsRef<str>>(mut self, device_serial: S) -> AdbShCmd {
if !device_serial.as_ref().is_empty() {
self.0.args(["-s", device_serial.as_ref()]);
let serial = device_serial.as_ref();
if !serial.is_empty() {
self.0.args(["-s", serial]);
}
self.0.arg("shell");
AdbShCmd(self)
Expand All @@ -88,6 +91,7 @@ impl AdbCmd {
self.0.arg("devices");
self.run()
}
/// Reboots default device
pub fn reboot(mut self) -> Result<String, String> {
self.0.arg("reboot");
self.run()
Expand Down Expand Up @@ -126,6 +130,7 @@ impl AdbCmd {

/// Builder for a command that runs 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).
#[derive(Debug)]
pub struct AdbShCmd(AdbCmd);
Expand All @@ -134,18 +139,64 @@ impl AdbShCmd {
self.0 .0.arg("pm");
ApmCmd(self)
}
/// Reboots device
pub fn reboot(mut self) -> Result<String, String> {
self.0 .0.arg("reboot");
self.0.run()
}
}

/// `pm list packages` flag/state/type
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PmLsPackFlag {
/// All: Include uninstalled
U,
/// Only enabled
E,
/// Only disabled
D,
}
impl PmLsPackFlag {
// is there a trait for this?
fn to_str(self) -> &'static str {
match self {
PmLsPackFlag::U => "-u",
PmLsPackFlag::E => "-e",
PmLsPackFlag::D => "-d",
}
}
}
#[expect(clippy::to_string_trait_impl, reason = "This is not user-facing")]
impl ToString for PmLsPackFlag {
fn to_string(&self) -> String {
self.to_str().to_string()
}
}

/// Builder for an Android Package Manager command.
///
/// [More info](https://developer.android.com/tools/adb#pm)
#[derive(Debug)]
pub struct ApmCmd(AdbShCmd);
impl ApmCmd {
pub fn list(mut self, state: PackageState) -> Result<String, String> {
self.0 .0 .0.args(["list", "-s"]);
pub fn list_packs(
mut self,
f: Option<PmLsPackFlag>,
u: Option<User>,
) -> Result<String, String> {
let cmd = &mut self.0 .0 .0;
cmd.args(["list", "packages", "-s"]);
if let Some(s) = f {
cmd.arg(s.to_str());
};
if let Some(u) = u {
cmd.arg("--user");
cmd.arg(u.id.to_string());
};
self.0 .0.run()
}
pub fn list_users(mut self) -> Result<String, String> {
self.0 .0 .0.args(["list", "users"]);
self.0 .0.run()
}
}
Expand All @@ -157,25 +208,21 @@ impl ApmCmd {
/// If `serial` is empty, it lets ADB choose the default device.
///
/// If `shell`, it's likely you want `serial` to _not_ be empty.
pub fn adb_cmd(shell: bool, serial: &str, args: &str) -> Result<String, String> {
// this could be a `tinyvec` or `arrayvec`
let mut adb_args = Vec::with_capacity(4);
fn adb_cmd(shell: bool, serial: &str, args: &str) -> Result<String, String> {
let mut cmd = Command::new("adb");
if !serial.is_empty() {
adb_args.extend(["-s", serial]);
cmd.args(["-s", serial]);
};
if shell {
adb_args.push("shell");
cmd.arg("shell");
}
// the rest
adb_args.push(args);

let mut command = Command::new("adb");
command.args(adb_args);
// this works even without "shell"?
cmd.arg(args);

#[cfg(target_os = "windows")]
let command = command.creation_flags(0x0800_0000); // do not open a cmd window
let cmd = cmd.creation_flags(0x0800_0000); // do not open a cmd window

match command.output() {
match cmd.output() {
Err(e) => {
error!("ADB: {}", e);
Err("Cannot run ADB, likely not found".to_string())
Expand Down Expand Up @@ -249,7 +296,7 @@ pub async fn adb_sh_cmd<S: AsRef<str>>(
}

/// If `None`, returns an empty String, not " --user 0"
pub fn user_flag(user_id: Option<&User>) -> String {
pub fn user_flag(user_id: Option<User>) -> String {
user_id
.map(|user| format!(" --user {}", user.id))
.unwrap_or_default()
Expand All @@ -258,10 +305,11 @@ pub fn user_flag(user_id: Option<&User>) -> String {
/// Installed and uninstalled packages.
///
/// If `device_serial` is empty, it lets ADB choose the default device.
pub fn list_all_system_packages(device_serial: &str, user_id: Option<&User>) -> String {
let action = format!("{PM_LIST_PACKS} -s -u{}", user_flag(user_id));

adb_cmd(true, device_serial, &action)
pub fn list_all_system_packages(device_serial: &str, user_id: Option<User>) -> String {
AdbCmd::new()
.shell(device_serial)
.pm()
.list_packs(Some(PmLsPackFlag::U), user_id)
.unwrap_or_default()
.replace("package:", "")
}
Expand All @@ -270,7 +318,7 @@ pub fn list_all_system_packages(device_serial: &str, user_id: Option<&User>) ->
pub fn hashset_system_packages(
state: PackageState,
device_serial: &str,
user_id: Option<&User>,
user_id: Option<User>,
) -> HashSet<String> {
let user = user_flag(user_id);
let action = match state {
Expand Down Expand Up @@ -323,7 +371,7 @@ impl From<&PackageRow> for CorePackage {
pub fn apply_pkg_state_commands(
package: &CorePackage,
wanted_state: PackageState,
selected_user: &User,
selected_user: User,
dev: &Device,
) -> Vec<String> {
// https://github.com/Universal-Debloater-Alliance/universal-android-debloater/wiki/ADB-reference
Expand Down Expand Up @@ -368,7 +416,7 @@ pub fn apply_pkg_state_commands(
/// Build a command request to be sent via ADB to a device.
/// `commands` accepts one or more ADB shell commands
/// which act on a common `package` and `user`.
pub fn request_builder(commands: &[&str], package: &str, user: Option<&User>) -> Vec<String> {
pub fn request_builder(commands: &[&str], package: &str, user: Option<User>) -> Vec<String> {
let maybe_user_flag = user_flag(user);
commands
.iter()
Expand Down Expand Up @@ -438,11 +486,14 @@ pub fn is_protected_user(user_id: &str, device_serial: &str) -> bool {
.is_err()
}

/// If `device_serial` is empty, it lets ADB choose the default device.
pub fn get_user_list(device_serial: &str) -> Vec<User> {
/// `pm list users` parsed into a vec with extra info.
pub fn list_users_parsed(device_serial: &str) -> Vec<User> {
#[dynamic]
static RE: Regex = Regex::new(r"\{([0-9]+)").unwrap_or_else(|_| unreachable!());
adb_cmd(true, device_serial, "pm list users")
AdbCmd::new()
.shell(device_serial)
.pm()
.list_users()
.map(|users| {
RE.find_iter(&users)
.enumerate()
Expand Down Expand Up @@ -470,7 +521,7 @@ pub async fn get_devices_list() -> Vec<Device> {
device_list.push(Device {
model: get_device_brand(serial),
android_sdk: get_android_sdk(serial),
user_list: get_user_list(serial),
user_list: list_users_parsed(serial),
adb_id: serial.to_string(),
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub enum Error {
pub fn fetch_packages(
uad_lists: &PackageHashMap,
device_serial: &str,
user_id: Option<&User>,
user_id: Option<User>,
) -> Vec<PackageRow> {
let all_system_packages = list_all_system_packages(device_serial, user_id);
let enabled_system_packages =
Expand Down
4 changes: 2 additions & 2 deletions src/gui/views/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ impl List {
} else {
user_list
.iter()
.map(|user| fetch_packages(&uad_list, serial, Some(user)))
.map(|user| fetch_packages(&uad_list, serial, Some(*user)))
.collect()
}
}
Expand Down Expand Up @@ -972,7 +972,7 @@ fn build_action_pkg_commands(
u_pkg.state.opposite(settings.disable_mode)
};

let actions = apply_pkg_state_commands(&u_pkg.into(), wanted_state, u, device);
let actions = apply_pkg_state_commands(&u_pkg.into(), wanted_state, *u, device);
for (j, action) in actions.into_iter().enumerate() {
let p_info = PackageInfo {
i_user: u.index,
Expand Down

0 comments on commit f6fb9b6

Please sign in to comment.