# How Device-Specific Settings Are Isolated in UAD-NG’s Configuration System

> Learn how UAD-NG isolates device-specific settings in its config.toml using unique device_id fields within a Vec<DeviceSettings> for seamless preference management.

- Repository: [Universal-Debloater-Alliance/universal-android-debloater-next-generation](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation)
- Tags: internals
- Published: 2026-06-20

---

**UAD-NG isolates device-specific settings by storing them in a `Vec<DeviceSettings>` within the global `Config` struct, using unique `device_id` fields to separate preferences per Android device while maintaining a single [`config.toml`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/config.toml) file.**

UAD-NG (Universal Android Debloater Next Generation) manages user preferences for multiple Android devices through a centralized **configuration system** defined in the core crate. The architecture ensures that each connected device maintains independent settings without namespace collisions, storing all data in a single TOML file located in the application’s configuration directory.

## Configuration Architecture and the Config Struct

All persistent user preferences reside in [`config.toml`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/config.toml), which is defined and managed through the `Config` type in [`crates/uad-core/src/config.rs`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/crates/uad-core/src/config.rs). This struct serves as the single source of truth for both the GUI and CLI front-ends, containing a `general` field for application-wide settings and a **`devices` vector** that houses per-device configurations.

The `devices` field holds a `Vec<DeviceSettings>`, where each entry represents the complete configuration state for one specific Android device. This vector-based structure provides the foundation for **device-specific settings isolation** within the shared file.

## The DeviceSettings Struct and Device Identification

The `DeviceSettings` struct defined in [`crates/uad-core/src/config.rs`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/crates/uad-core/src/config.rs) contains the fields necessary to customize behavior for individual devices. Each instance includes a **`device_id`** field that acts as a unique identifier, ensuring the application can distinguish between different Android devices reliably.

When a user modifies settings for a specific device, the application creates a `DeviceSettings` instance populated with that device's `device_id` and the new preference values. This struct also contains a `backup` field of type `BackupSettings`, though this data is handled differently from persistent preferences.

## Saving and Isolating Device Configuration

The `Config::save_device_settings` method implements the core isolation logic. This method accepts a `DeviceSettings` instance and a `GeneralSettings` instance, then performs an atomic update to the configuration:

1. Searches the `devices` vector for an existing entry matching the incoming `device_id`
2. If found, replaces the existing entry with the new settings
3. If not found, appends the new `DeviceSettings` to the vector
4. Persists the entire `Config` to disk

This guarantees that updates to one device never overwrite another device's configuration.

```rust
let mut cfg = Config::load_configuration_file();
let dev_settings = DeviceSettings {
    device_id: "ABCD1234".into(),
    disable_mode: true,
    multi_user_mode: false,
    backup: BackupSettings::default(),
};
let general = cfg.general.clone(); // keep existing general settings
cfg.save_device_settings(dev_settings, general);

```

## Loading Configuration and Retrieving Device Settings

The configuration system uses `LazyLock` to initialize the `CONFIG_FILE` path exactly once at runtime. The **`load_configuration_file`** function safely reads the TOML from this path, automatically falling back to default configuration values if the file is missing or corrupted.

To retrieve settings for a specific device, the application iterates over the `devices` vector and matches on the `device_id`:

```rust
let cfg = Config::load_configuration_file();
let device_id = "ABCD1234";
let device_cfg = cfg.devices.iter()
    .find(|d| d.device_id == device_id);
if let Some(settings) = device_cfg {
    println!("Disable mode: {}", settings.disable_mode);
}

```

## Separating Volatile State with #[serde(skip)]

Within `DeviceSettings`, the `backup` field is marked with **`#[serde(skip)]`**, which prevents the serialization layer from writing `BackupSettings` to the TOML file. This isolates volatile runtime data from **persistent configuration**, ensuring that temporary backup state remains in memory only while static preferences like `disable_mode` and `multi_user_mode` are saved to disk.

## Shared Core Across GUI and CLI

The isolation mechanism is shared by both front-ends through the core crate. The GUI layer in [`crates/uad-gui/src/views/settings.rs`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/crates/uad-gui/src/views/settings.rs) reads from and writes to `Config` for the currently selected device, while the CLI implementation in [`crates/uad-cli/src/device.rs`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/crates/uad-cli/src/device.rs) manipulates per-device settings via the same `save_device_settings` API. This shared architecture ensures consistent **device-specific settings isolation** regardless of the interface used.

## Summary

- UAD-NG stores all preferences in a single [`config.toml`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/config.toml) file, with **device-specific settings** isolated in a `Vec<DeviceSettings>` within the `Config` struct.
- Each device is uniquely identified by its `device_id`, and the `save_device_settings` method ensures updates target only the correct device entry.
- The `#[serde(skip)]` attribute on `BackupSettings` prevents volatile runtime data from being persisted alongside static preferences.
- The system uses `LazyLock` for efficient path initialization and provides safe fallbacks to default values when the configuration file is unavailable.
- Both GUI and CLI front-ends share the same core configuration logic defined in [`crates/uad-core/src/config.rs`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/crates/uad-core/src/config.rs), ensuring consistent behavior across interfaces.

## Frequently Asked Questions

### How does UAD-NG prevent settings from one device affecting another?

UAD-NG maintains a vector of `DeviceSettings` structs inside the global `Config`, where each struct contains a unique `device_id` field. When saving settings, the `save_device_settings` method searches for an entry with the matching ID and updates only that specific index, ensuring complete isolation between devices.

### What happens if I connect a new device that has no saved configuration?

When a new device connects, the application attempts to find its `device_id` in the `devices` vector. If no entry exists, the system creates a new `DeviceSettings` instance with default values and appends it to the vector during the next save operation, automatically initializing configuration for that device without affecting existing entries.

### Why are backup settings not saved to the configuration file?

The `backup` field within `DeviceSettings` is marked with `#[serde(skip)]`, which instructs the TOML serializer to ignore this field. This design keeps transient backup state in memory only, preventing temporary runtime data from being written to disk and ensuring the configuration file contains only persistent user preferences.

### Where is the configuration file stored and how is it loaded?

The configuration file [`config.toml`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/config.toml) resides in the application's configuration directory. The system uses a `LazyLock`-protected `CONFIG_FILE` constant to compute this path once at runtime. The `load_configuration_file` function reads this file, but automatically falls back to default configuration values if the file is missing or corrupted, ensuring the application always starts with a valid configuration state.