mirror of
https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation.git
synced 2026-08-26 15:34:19 +02:00
parent
f653696423
commit
e095d48e71
9 changed files with 201 additions and 32 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -10,3 +10,13 @@ and `Removed`.
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- UAD now comes with a logger. Debug information will be written to a `uad.log` file (Warning level log in *stdout*) (#2)
|
||||
|
||||
### Changed
|
||||
- UAD will no longer crash at start if it doesn't find ADB but display a useful message (#25)
|
||||
- Better handling of ADB errors (#3)
|
||||
|
||||
### Fixed
|
||||
- Spelling mistake
|
||||
-
|
||||
|
|
|
|||
68
Cargo.lock
generated
68
Cargo.lock
generated
|
|
@ -85,6 +85,17 @@ dependencies = [
|
|||
"libloading 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
|
|
@ -196,6 +207,19 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "4.2.1"
|
||||
|
|
@ -287,6 +311,17 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"lazy_static",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "copyless"
|
||||
version = "0.1.5"
|
||||
|
|
@ -654,6 +689,16 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fern"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.0"
|
||||
|
|
@ -1526,6 +1571,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
|
|
@ -2301,6 +2356,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.2.0"
|
||||
|
|
@ -2371,7 +2436,10 @@ dependencies = [
|
|||
name = "uad_gui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fern",
|
||||
"iced",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"static_init",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ iced = { git = "https://github.com/hecrj/iced.git", features = ["svg"] }
|
|||
serde = { version = "^1.0", features = ["derive"] }
|
||||
serde_json = "^1.0"
|
||||
static_init = "^1.0"
|
||||
fern = { version = "^0.6", features = ["colored"] }
|
||||
log = "^0.4"
|
||||
chrono = "^0.4"
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::process::Command;
|
||||
use std::collections::HashSet;
|
||||
use crate::core::uad_lists::Removal;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
|
@ -11,26 +12,34 @@ pub fn adb_shell_command(args: &str) -> Result<String,String> {
|
|||
let output = Command::new("adb")
|
||||
.args(&["shell", args])
|
||||
.creation_flags(0x08000000) // do not open a cmd window
|
||||
.output()
|
||||
.expect("adb command failed to start. Do you have ADB installed?");
|
||||
.output();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let output = Command::new("adb")
|
||||
.args(&["shell", args])
|
||||
.output()
|
||||
.expect("adb command failed to start. Do you have ADB installed?");
|
||||
.output();
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||
let output = Command::new("adb")
|
||||
.args(&["shell", args])
|
||||
.output()
|
||||
.expect("adb command failed to start. Do you have ADB installed?");
|
||||
.output();
|
||||
|
||||
if !output.status.success() {
|
||||
Err(String::from_utf8(output.stderr).unwrap())
|
||||
} else {
|
||||
Ok(String::from_utf8(output.stdout).unwrap())
|
||||
}
|
||||
match output {
|
||||
Err(e) => {
|
||||
error!("ADB: {}", e);
|
||||
Err("ADB was not found".to_string())
|
||||
},
|
||||
Ok(o) => {
|
||||
if !o.status.success() {
|
||||
let stderr = String::from_utf8(o.stderr).unwrap().trim_end().to_string();
|
||||
error!("ADB: {}", stderr);
|
||||
Err(stderr)
|
||||
} else {
|
||||
Ok(String::from_utf8(o.stdout).unwrap().trim_end().to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -42,33 +51,46 @@ pub fn list_all_system_packages() -> String {
|
|||
}
|
||||
|
||||
pub fn hashset_installed_system_packages() -> HashSet<String> {
|
||||
let hashet: HashSet<String> = adb_shell_command("pm list packages -s")
|
||||
adb_shell_command("pm list packages -s")
|
||||
.unwrap_or("".to_string())
|
||||
.replace("package:", "")
|
||||
.lines()
|
||||
.map(String::from)
|
||||
.collect();
|
||||
|
||||
hashet
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
pub fn uninstall_package(package: String) -> String {
|
||||
pub fn uninstall_package(package: String, removal: Removal) {
|
||||
let arg = "pm uninstall --user 0 ".to_string() + &package;
|
||||
let output = adb_shell_command(&arg).unwrap();
|
||||
if output.contains("Success") {
|
||||
info!("REMOVE [{}]: {}", removal, package);
|
||||
|
||||
} else {
|
||||
error!("REMOVE [{}]: {}", removal, output);
|
||||
}
|
||||
|
||||
adb_shell_command(&arg).unwrap()
|
||||
}
|
||||
|
||||
|
||||
pub fn restore_package(package: String) -> String {
|
||||
pub fn restore_package(package: String, removal: Removal) {
|
||||
let arg = "cmd package install-existing --user 0 ".to_string() + &package;
|
||||
let output = adb_shell_command(&arg).unwrap();
|
||||
|
||||
if output.contains("installed for user") {
|
||||
info!("RESTORE [{}]: {}", removal, package);
|
||||
} else {
|
||||
error!("RESTORE: {} -- ", output);
|
||||
}
|
||||
|
||||
adb_shell_command(&arg).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_phone_model() -> String {
|
||||
match adb_shell_command("getprop ro.product.model") {
|
||||
Ok(model) => model,
|
||||
Ok(model) => {
|
||||
model
|
||||
},
|
||||
|
||||
Err(err) => {
|
||||
if err.contains("adb: no devices/emulators found") {
|
||||
"adb: no devices/emulators found".to_string()
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ impl Application for UadGui {
|
|||
UadGui::Loaded(state) => match message {
|
||||
Message::CatalogRefreshPress => {
|
||||
state.list_view = ListView::default();
|
||||
state.device_name = get_phone_brand();
|
||||
info!("PHONE_MODEL: {}", state.device_name);
|
||||
state.list_view.update(ListMessage::LoadSettings(state.settings_view.clone()));
|
||||
state.view = View::List;
|
||||
Command::perform(Self::load_phone_packages(), Message::CatalogAction)
|
||||
|
|
@ -121,7 +123,6 @@ impl Application for UadGui {
|
|||
Command::none()
|
||||
}
|
||||
Message::CatalogAction(msg) => {
|
||||
state.device_name = get_phone_brand();
|
||||
state.list_view.update(msg).map(Message::CatalogAction)
|
||||
}
|
||||
Message::SettingsAction(msg) => {
|
||||
|
|
@ -238,6 +239,7 @@ impl UadGui {
|
|||
State::default()
|
||||
}
|
||||
pub async fn load_phone_packages() -> ListMessage {
|
||||
info!("PHONE_MODEL: {}", get_phone_brand());
|
||||
ListMessage::LoadPackages(&UAD_LISTS)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use crate::core::sync::{
|
|||
pub struct SelectionPackage {
|
||||
pub name: String,
|
||||
pub state: PackageState,
|
||||
pub removal: Removal,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
|
|
@ -138,7 +139,8 @@ impl List {
|
|||
self.selected_packages.push(
|
||||
SelectionPackage {
|
||||
name: self.filtered_packages[i].name.clone(),
|
||||
state: self.filtered_packages[i].state
|
||||
state: self.filtered_packages[i].state,
|
||||
removal: self.filtered_packages[i].removal,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
|
@ -170,17 +172,20 @@ impl List {
|
|||
Message::ApplyActionOnSelection => {
|
||||
for p in &self.selected_packages {
|
||||
match p.state {
|
||||
PackageState::Installed => uninstall_package(p.name.clone()),
|
||||
PackageState::Uninstalled => restore_package(p.name.clone()),
|
||||
PackageState::All => "[DEBUG] ApplySelectionAction: Unknown package state".to_string(), // This can't happen
|
||||
PackageState::Installed => uninstall_package(p.name.clone(), p.removal),
|
||||
PackageState::Uninstalled => restore_package(p.name.clone(), p.removal),
|
||||
PackageState::All => error!("ApplySelectionAction: Unknown package state"), // This can't happen
|
||||
};
|
||||
|
||||
for phone_p in &mut self.phone_packages {
|
||||
if p.name == phone_p.name {
|
||||
phone_p.state = match phone_p.state {
|
||||
PackageState::Installed => PackageState::Uninstalled,
|
||||
PackageState::Uninstalled => PackageState::Installed,
|
||||
PackageState::All => PackageState::All, // This can't happen (Like... never)
|
||||
PackageState::Uninstalled => PackageState::Installed,
|
||||
PackageState::All => {
|
||||
error!("ApplyActionOnSelection: Unknown package state");
|
||||
PackageState::All // This can't happen (like... never)
|
||||
}
|
||||
};
|
||||
break
|
||||
}
|
||||
|
|
@ -193,7 +198,7 @@ impl List {
|
|||
let mut package;
|
||||
for p in &mut self.filtered_packages {
|
||||
p.selected = true;
|
||||
package = SelectionPackage { name: p.name.clone(), state: p.state };
|
||||
package = SelectionPackage { name: p.name.clone(), state: p.state, removal: p.removal };
|
||||
if !self.selected_packages.contains(&package) {
|
||||
self.selected_packages.push(package);
|
||||
}
|
||||
|
|
@ -408,13 +413,13 @@ impl PackageRow {
|
|||
pub fn update(&mut self, message: RowMessage) -> Command<RowMessage> {
|
||||
match message {
|
||||
RowMessage::RemovePressed(package) => {
|
||||
uninstall_package(package.name);
|
||||
uninstall_package(package.name, self.removal);
|
||||
self.state = PackageState::Uninstalled;
|
||||
self.selected = false;
|
||||
Command::none()
|
||||
}
|
||||
RowMessage::RestorePressed(package) => {
|
||||
restore_package(package.name);
|
||||
restore_package(package.name, self.removal);
|
||||
self.state = PackageState::Installed;
|
||||
self.selected = false;
|
||||
Command::none()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
pub mod list;
|
||||
pub mod package;
|
||||
pub mod settings;
|
||||
pub mod about;
|
||||
|
|
@ -24,6 +24,7 @@ impl Settings {
|
|||
pub fn update(&mut self, msg: Message) {
|
||||
match msg {
|
||||
Message::ExpertModeToogle(toggled) => {
|
||||
info!("Expert mode {}", if toggled {"enabled"} else {"disabled"});
|
||||
self.expert_mode = toggled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
59
src/main.rs
59
src/main.rs
|
|
@ -1,9 +1,68 @@
|
|||
#![windows_subsystem = "windows"]
|
||||
#![feature(drain_filter)]
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
use chrono;
|
||||
use std::{fs::OpenOptions, fmt::Arguments};
|
||||
use fern::{FormatCallback, colors::{Color, ColoredLevelConfig}};
|
||||
use log::Record;
|
||||
|
||||
mod core;
|
||||
mod gui;
|
||||
|
||||
fn main() {
|
||||
setup_logger().expect("setup logging");
|
||||
gui::UadGui::start();
|
||||
}
|
||||
|
||||
pub fn setup_logger() -> Result<(), fern::InitError> {
|
||||
|
||||
let colors = ColoredLevelConfig::new().info(Color::Green);
|
||||
|
||||
let make_formatter = |use_colors: bool| {
|
||||
move |out: FormatCallback, message: &Arguments, record: &Record| {
|
||||
out.finish(format_args!(
|
||||
"{} {} [{}:{}] {}",
|
||||
chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
|
||||
if use_colors {
|
||||
format!("{:5}", colors.color(record.level()))
|
||||
} else {
|
||||
format!("{:5}", record.level().to_string())
|
||||
},
|
||||
record.file().unwrap_or("?".into()),
|
||||
record
|
||||
.line()
|
||||
.map(|l| l.to_string())
|
||||
.unwrap_or(String::new()),
|
||||
message
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let default_log_level = log::LevelFilter::Warn;
|
||||
let log_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.append(false)
|
||||
.truncate(true)
|
||||
.open("uad.log")?;
|
||||
|
||||
let file_dispatcher = fern::Dispatch::new()
|
||||
.format(make_formatter(false))
|
||||
.level(default_log_level)
|
||||
.level_for("uad_gui", log::LevelFilter::Debug)
|
||||
.chain(log_file);
|
||||
|
||||
let stdout_dispatcher = fern::Dispatch::new()
|
||||
.format(make_formatter(true))
|
||||
.level(default_log_level)
|
||||
.level_for("uad_gui", log::LevelFilter::Warn)
|
||||
.chain(std::io::stdout());
|
||||
|
||||
fern::Dispatch::new()
|
||||
.chain(stdout_dispatcher)
|
||||
.chain(file_dispatcher)
|
||||
.apply()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue