refactor: rm all regex, and properly parse pm list users

This commit is contained in:
Rudxain 2025-07-08 09:48:39 -04:00
commit c5799702e2
No known key found for this signature in database
GPG key ID: 0DAC837DDEF8E96C
4 changed files with 63 additions and 62 deletions

39
Cargo.lock generated
View file

@ -37,15 +37,6 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
@ -3100,35 +3091,6 @@ dependencies = [
"thiserror 2.0.12",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "renderdoc-sys"
version = "1.1.0"
@ -3934,7 +3896,6 @@ dependencies = [
"flate2",
"iced",
"log",
"regex",
"retry",
"rfd",
"serde",

View file

@ -27,7 +27,6 @@ chrono = { version = "^0.4", default-features = false, features = [
"clock",
] }
log = "^0.4"
regex = "^1.10.2"
toml = "^0"
dirs = "^6"
ureq = { version = "3", features = ["json"] }

View file

@ -356,15 +356,66 @@ impl PmCommand {
})
}
/// `list users` sub-command.
/// Output isn't parsed, because
/// we don't know if the format is stable across Android versions.
/// `list users` sub-command, deserialized/parsed.
///
/// - <https://source.android.com/docs/devices/admin/multi-user-testing>
/// - <https://stackoverflow.com/questions/37495126/android-get-list-of-users-and-profile-name>
pub fn list_users(mut self) -> Result<String, String> {
pub fn list_users(mut self) -> Result<Box<[UserInfo]>, String> {
self.0.0.0.args(["list", "users"]);
self.0.0.run()
Ok(self
.0
.0
.run()?
.lines()
.skip(1) // omit header
.map(|ln| {
// this could be optimized by making more API-stability assumptions
let ln = ln.trim_ascii_start();
let ln = ln.strip_prefix("UserInfo").unwrap_or(ln).trim_ascii_start();
let ln = ln.strip_prefix('{').unwrap_or(ln).trim_ascii();
let ln = ln.strip_suffix('}').unwrap_or(ln).trim_ascii_end();
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/content/pm/UserInfo.java
// the format seems to be stable across Android versions:
// "\tUserInfo{<id>:<name>:<flags>}"
let mut comps = ln.split(':');
let id = comps
.next()
.expect("There must be at least 1 ':'-separated component")
.parse()
.expect("string assumed to be UID numeral");
//let name = comps
// .next()
// .expect("There must be at least 2 ':'-separated components. 2nd is user-name");
//let flags = u32::from_str_radix(
// comps.next().expect(
// "There must be at least 3 ':'-separated components. 3rd is user bit-flags",
// ),
// 16,
//)
//.expect("string assumed to be hexadecimal bit-flags");
UserInfo {
id,
//name: name.into(),
//flags,
}
})
.collect())
}
}
/// Mirror of AOSP `UserInfo` Java Class
#[derive(Debug, Clone)]
pub struct UserInfo {
id: u16,
//name: Box<str>,
//flags: u32,
}
impl UserInfo {
#[must_use]
pub const fn get_id(&self) -> u16 {
self.id
}
}

View file

@ -3,11 +3,9 @@ use crate::core::{
uad_lists::PackageState,
};
use crate::gui::{views::list::PackageInfo, widgets::package_row::PackageRow};
use regex::Regex;
use retry::{OperationResult, delay::Fixed, retry};
use serde::{Deserialize, Serialize};
use std::process::Command;
use std::sync::LazyLock;
#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;
@ -43,6 +41,7 @@ impl std::fmt::Display for Phone {
}
}
/// `UserInfo` but relevant to UAD
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct User {
pub id: u16,
@ -292,29 +291,20 @@ pub fn is_protected_user<S: AsRef<str>>(user_id: u16, device_serial: S) -> bool
.is_err()
}
/// `pm list users` parsed into a vector with extra info
pub fn list_users_parsed(device_serial: &str) -> Vec<User> {
// this could be thread-local (no lock overhead),
// but then each thread would compile its own clone of the regex,
// I guess?
static RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"\{([0-9]+)").unwrap_or_else(|_| unreachable!()));
pub fn list_users_idx_prot(device_serial: &str) -> Vec<User> {
AdbCommand::new()
.shell(device_serial)
.pm()
.list_users()
.map(|out| {
RE.find_iter(&out)
out.into_iter()
.enumerate()
.map(|(i, user)| {
let u = user.as_str()[1..]
.parse()
.unwrap_or_else(|_| unreachable!("User ID must always be a valid `u16`"));
let id = user.get_id();
User {
id: u,
id,
index: i,
protected: is_protected_user(u, device_serial),
protected: is_protected_user(id, device_serial),
}
})
.collect()
@ -338,7 +328,7 @@ pub async fn get_devices_list() -> Vec<Phone> {
device_list.push(Phone {
model: format!("{} {}", get_device_brand(serial), get_device_model(serial)),
android_sdk: get_android_sdk(serial),
user_list: list_users_parsed(serial),
user_list: list_users_idx_prot(serial),
adb_id: serial.to_string(),
});
}