How Dry-Run Mode Works in UAD-ng CLI Operations: A Complete Technical Guide
When you append --dry-run to UAD-ng CLI commands like uninstall, enable, or disable, the tool executes the full package-state workflow but only prints the ADB commands it would run, without ever sending them to the device.
The Universal Android Debloater Next Generation (UAD-ng) provides a safe preview mechanism through its dry-run mode, allowing users to verify exactly which shell commands will be executed before modifying their Android device. This feature is crucial when auditing pre-installed bloatware or testing package state changes across multiple user profiles. Understanding how dry-run mode works in UAD-ng CLI operations helps prevent accidental data loss and ensures predictable device management.
What Is Dry-Run Mode in UAD-ng?
Dry-run mode is a safety feature implemented in the command-line interface of universal-android-debloater-next-generation. When activated via the --dry-run flag, the CLI processes all logic required to transition packages to their target states—building ADB command lists, validating device connections, and iterating through selected packages—but stops short of actual execution. Instead, it outputs the exact shell commands that would run during a live operation, prefixed with "Would run:" for clarity.
How the Dry-Run Flag Is Parsed
The dry-run functionality begins at the argument parsing level in crates/uad-cli/src/main.rs. For sub-commands such as Uninstall, Enable, and Disable, the CLI defines a boolean dry_run flag that is passed directly to the core command handler.
When you invoke a command like uad uninstall com.example.app --dry-run, the flag is captured in the command-line interface definitions and forwarded to commands::change_package_state. This ensures the dry-run state persists through the entire execution chain, from initial parsing through to the final package processing loop.
The Dry-Run Execution Flow
Inside crates/uad-cli/src/commands.rs, the change_package_state function orchestrates the dry-run behavior through a conditional execution path that prioritizes transparency over action.
Displaying the Dry-Run Notice
Upon entering the command execution logic, the system immediately checks the dry_run boolean. If set to true, it prints a clear header to stderr/logger:
if dry_run {
println!("DRY RUN - No changes will be made\n");
}
This notification appears at lines 68-71 of commands.rs, ensuring users cannot miss the fact that they are in simulation mode before any package processing begins.
Generating ADB Commands Without Execution
For each target package, the function calls process_package_state_change, which internally utilizes apply_pkg_state_commands to construct the specific ADB shell commands required to reach the desired state. However, the critical branch occurs at lines 30-34 of commands.rs:
if dry_run {
for cmd in &commands {
println!(" Would run: {}", cmd);
}
} else {
execute_with_fallback(...);
}
When dry-run is active, the system iterates through the prepared command vectors and prints them with indentation. The execute_with_fallback function—responsible for actual ADB shell execution—is completely bypassed, guaranteeing zero device interaction.
Practical Examples of UAD-ng Dry-Run Commands
The following CLI commands demonstrate how dry-run mode behaves across different package operations:
# Preview uninstall commands for a single package
uad uninstall com.example.app --dry-run
# Preview enable commands for a disabled package
uad enable com.example.app --dry-run
# Preview disable commands across multiple packages on a specific device
uad disable com.one.app com.two.app --dry-run -d xyz123
Typical output when running these commands:
Uninstalling 2 package(s) on: Nexus 6P (XYZ123)
DRY RUN - No changes will be made
com.one.app (Enabled)
Would run: pm uninstall -k --user 0 com.one.app
com.two.app (Disabled)
Would run: pm uninstall -k --user 0 com.two.app
Dry run completed. No changes were made.
Key Source Files Involved
Understanding the dry-run implementation requires familiarity with three primary locations in the UAD-ng codebase:
crates/uad-cli/src/main.rs– Defines the--dry-runCLI flags for all state-changing sub-commands and routes them to the appropriate handlers.crates/uad-cli/src/commands.rs– Contains thechange_package_statefunction, the dry-run notice logic, and the conditional branch that prints "Would run:" instead of callingexecute_with_fallback.crates/uad-core/src/sync.rs– Provides theapply_pkg_state_commandsutility that generates the actual shell command strings; dry-run mode simply displays these strings rather than executing them.
Summary
- Dry-run mode in UAD-ng CLI operations allows safe previewing of ADB commands before execution.
- The
--dry-runflag is parsed inmain.rsand passed tochange_package_stateincommands.rs. - When active, the system prints "DRY RUN - No changes will be made" followed by indented "Would run:" statements for each generated command.
- No actual ADB shell commands are executed; the
execute_with_fallbackfunction is skipped entirely. - This mode works with
uninstall,enable, anddisablesub-commands across single or multiple packages.
Frequently Asked Questions
What happens when I use --dry-run with uninstall?
The CLI processes the uninstall logic for the specified package, generates the ADB command (typically pm uninstall -k --user 0 <package>), and prints it with the "Would run:" prefix. The package remains installed on the device, and no user data is removed.
Does dry-run mode require a connected device?
Yes, dry-run mode still requires a connected Android device because the logic path validates device connectivity and enumerates packages to determine the correct state transitions. However, it only displays the commands it would execute rather than modifying the device state.
Can I use dry-run with multiple packages?
Absolutely. You can pass multiple package names to any state-changing command with --dry-run, and UAD-ng will display the generated ADB commands for each package sequentially. This is useful for auditing bulk operations before committing changes.
Where is the dry-run logic implemented?
The core logic resides in crates/uad-cli/src/commands.rs within the change_package_state function. The flag definition exists in crates/uad-cli/src/main.rs, while the command generation utilities are located in crates/uad-core/src/sync.rs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →