How State, Removal, and List Filters Are Implemented in the UAD-ng CLI
The UAD-ng CLI implements package filtering through three specialized enums—StateFilter, RemovalFilter, and ListFilter—defined in crates/uad-cli/src/filters.rs, which provide matches methods to evaluate packages against user-specified criteria.
The Universal Android Debloater Next Generation (UAD-ng) CLI provides granular control over Android package management through a sophisticated filtering system. Located in the crates/uad-cli directory, this implementation allows users to narrow down packages by installation state, recommended removal safety level, and upstream list origin using a composable filter architecture.
Filter Architecture: The Three Core Enums
The filtering system centers on three distinct enums, each responsible for a specific dimension of package selection.
StateFilter(lines 5‑15 ofcrates/uad-cli/src/filters.rs): Limits results to packages that are enabled, disabled, uninstalled, or all packages.RemovalFilter(lines 18‑25): Selects packages based on the UAD removal classification (Recommended, Advanced, Expert, Unsafe, or Unlisted).ListFilter(lines 28‑37): Restricts output to a specific upstream list (AOSP, Carrier, Google, Misc, OEM, Pending, or Unlisted).
Each enum implements a matches method that receives the relevant package data and returns a boolean indicating whether the package satisfies the filter criteria.
Core Filter Logic Implementation
Each filter enum provides a matches method that performs direct comparison against package metadata.
For installation state filtering, StateFilter::matches (lines 48‑55) evaluates the PackageState:
pub fn matches(self, pkg_state: PackageState) -> bool {
match self {
Self::All => true,
Self::Enabled => pkg_state == PackageState::Enabled,
Self::Disabled => pkg_state == PackageState::Disabled,
Self::Uninstalled => pkg_state == PackageState::Uninstalled,
}
}
Similar implementations exist for RemovalFilter::matches (lines 62‑74), which checks the package's removal classification, and ListFilter::matches (lines 82‑95), which validates the UadList origin.
Filter Composition via PackageListContext
Individual filters are aggregated into a composite structure that handles multi-criteria queries. The PackageListContext struct (lines 46‑53 of crates/uad-cli/src/commands.rs) holds optional instances of all three filter types plus a free-text search term:
pub struct PackageListContext {
pub state_filter: Option<StateFilter>,
pub removal_filter: Option<RemovalFilter>,
pub list_filter: Option<ListFilter>,
pub search: Option<String>,
}
The filter_package method (lines 55‑92) implements sequential evaluation using short-circuit logic. It processes filters in the order removal → state → list → search, returning false immediately if any filter fails:
if let Some(removal) = self.removal_filter {
if !removal.matches(pkg_info) { return false; }
}
// …repeat for state and list…
ADB Integration and Performance Optimization
The CLI optimizes performance by pushing state filtering down to the ADB layer. StateFilter::to_pm_flag() (lines 39‑46) converts the filter into a PmListPacksFlag that is passed directly to the pm list packages command. This reduces the initial data transfer by limiting the raw package set to enabled, disabled, or uninstalled packages before Rust-side filtering begins.
Dynamic Output Configuration
The filtering system influences terminal output through PackageListContext::display_config (lines 94‑100). This method determines column visibility based on filter specificity, hiding the state or removal columns when the corresponding filter is set to All:
DisplayConfig {
show_state: self.state_filter.is_none_or(|f| !f.is_specific()),
show_removal: self.removal_filter.is_none_or(|f| !f.is_specific()),
}
Practical CLI Usage Examples
Listing enabled packages marked Recommended for removal
uad list --state enabled --removal recommended
--state enabledinstantiatesStateFilter::Enabled--removal recommendedinstantiatesRemovalFilter::RecommendedPackageListContextrequires both conditions to returntrue
Querying uninstalled packages from the Google list
uad list --list google --state uninstalled
ListFilter::Googlerestricts matches toUadList::GoogleStateFilter::UninstalledtriggersPmListPacksFlag::IncludeUninstalledin the ADB query
Dry-run removal of unsafe packages
uad remove --removal unsafe --dry-run
RemovalFilter::Unsafeselects packages withRemoval::Unsafeclassification- The filter pipeline validates each package before generating the change plan
Summary
- Three specialized enums (
StateFilter,RemovalFilter,ListFilter) defined incrates/uad-cli/src/filters.rshandle distinct filtering dimensions. - Composable architecture via
PackageListContextincrates/uad-cli/src/commands.rsenables multi-criteria filtering with short-circuit evaluation. - ADB optimization through
to_pm_flag()pushes state filtering to the device level, minimizing data transfer. - Dynamic UI adjusts column visibility based on active filters to maintain concise output.
- Sequential evaluation in
filter_packageprocesses removal, state, list, and search criteria in order of computational cost.
Frequently Asked Questions
How does UAD-ng filter packages by installation state before fetching from the device?
The CLI converts StateFilter variants into PmListPacksFlag values via to_pm_flag() (lines 39‑46 of filters.rs). These flags are passed to the pm list packages ADB command, instructing the Android package manager to return only enabled, disabled, or uninstalled packages. This pre-filtering occurs before the Rust-side matches logic processes the results.
What is the difference between RemovalFilter and ListFilter in UAD-ng?
RemovalFilter selects packages based on the safety classification of removal (Recommended, Advanced, Expert, Unsafe, or Unlisted) as defined in the UAD database. ListFilter selects packages based on their upstream source category (AOSP, Google, OEM, Carrier, Misc, Pending, or Unlisted). A package can belong to the Google list while having an Unsafe removal classification, requiring both filters to isolate it.
Can multiple filters be combined in a single UAD-ng CLI command?
Yes. The PackageListContext struct accepts optional instances of all three filter types simultaneously. When you execute a command like uad list --state enabled --removal recommended --list google, the filter_package method evaluates each condition sequentially. A package must satisfy all specified filters to appear in the output.
How does the CLI determine which columns to display when filters are applied?
The display_config method (lines 94‑100 of commands.rs) checks whether state_filter or removal_filter is set to a specific variant (not All). If a specific filter is active, the corresponding column is hidden because the information is redundant—all displayed packages share that state or removal classification. This keeps the terminal output concise and readable.
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 →