AOSP Framework & Internals
6 min read

UserManagerService

Learn about UserManagerService.

When Android was first built, a phone belonged to one person. As the platform expanded to tablets, automotive systems, and enterprise environments, relying on a single global user became a major security liability. If multiple people or distinct personas share a physical device, their data, settings, and runtime states must remain strictly isolated.

UserManagerService governs identity and user lifecycles across the system. It multiplexes the underlying hardware so that each Android user feels like they own the entire device. To understand how this service achieves isolation without breaking the application sandbox, we have to look at how it manipulates Linux user IDs. Understanding this mechanism is the first step in building apps that behave predictably in multi-user environments.

The Math of Isolation

Android's core security model maps the traditional Linux user ID to an individual application rather than a human user. Every installed app gets its own isolated sandbox. When you introduce multiple human users to the same device, this one-to-one mapping breaks down. The system needs a way to guarantee that an app running for a primary user cannot read the local databases of that exact same app running for a guest user.

To solve this collision, UserManagerService coordinates with PackageManagerService to multiplex the Linux user ID space. Instead of handing out raw IDs, the system calculates a composite ID for every application process based on the active Android user.

The flowchart below shows how the system interprets identity assignments based on the active user profile. This visualizes the mathematical shift that keeps the same application isolated across different user spaces. Look for how the single application ID of 10050 results in two completely separate Linux IDs that the kernel treats as mutually untrusted processes.

The system multiplies the Android user ID by 100,000 and adds the internal application ID. If an app receives the internal ID of 10050, it runs as 10050 for the primary device owner. When a secondary user launches that same app, the kernel sees the process running under 1010050. This mathematical shift guarantees strict kernel-level enforcement. The Linux kernel blocks any attempt to cross the boundary, just like it blocks two different apps from reading each other's memory.

The Taxonomy of User Spaces

Multiplexing process IDs handles the kernel isolation, but not all user spaces serve the same product requirement. A transient guest borrowing a tablet has entirely different lifecycle needs than a permanent work profile managed by an enterprise IT department. The system must track and enforce these behavioral differences at the framework level.

Android defines four core user types natively within the platform. The primary user is created on first boot and retains exclusive control over device-level hardware states and network configurations. Secondary users are fully independent spaces with their own accounts, settings, and lock screens. Guest users are transient secondary spaces whose data is automatically wiped the moment their session ends. Profiles, like the work profile, are tethered spaces that share a launcher UI with their parent user but maintain separate encrypted storage and network routing.

UserManagerService tracks the state of these identities and persists them to disk in /data/system/users/. The master manifest lives in userlist.xml, while each specific user gets a dedicated file like 0.xml or 10.xml. These XML files store critical metadata including creation timestamps, profile group linkages, and active restriction flags. When a subsystem needs to know if the current user is allowed to install unknown apps or modify Wi-Fi settings, it queries this service to check those exact flags.

Orchestrating the Handoff

Having multiple isolated spaces means the system needs a secure way to transition the foreground interface and background execution states between them. Swapping the launcher is not enough. A user switch requires freezing the outgoing user's processes, securely decrypting the incoming user's storage, and re-routing all hardware inputs to a new window hierarchy.

This heavy orchestration is driven by ActivityManagerService, which relies directly on UserManagerService to manage the identity transitions.

The sequence diagram below details the handoffs between the activity manager, user manager, storage daemon, and window manager during a user switch. It helps visualize the strict ordering required to transition state securely. Notice how the user manager coordinates with vold to decrypt the credential directory before the system is allowed to wake the target user's apps.

The switch begins when the activity manager receives a transition request. The framework immediately freezes the outgoing user's activities to prevent background data leaks and reclaim memory. ActivityManagerService then calls into the user manager, which communicates with the native volume daemon to access the Credential Encrypted storage directory if the incoming user provides a valid credential.

Once storage is ready, the system begins starting the target user's persistent services and interface components. Android either aggressively caches or completely kills apps belonging to the background user, depending on memory constraints. Finally, the window manager switches the visible surface layers to the target user's activity stack, and the framework fires a broadcast to notify registered services of the new state.

Developers often need a fast way to verify how their app behaves when pushed to the background during a profile transition. You can trigger this exact orchestration from the command line using adb.

adb shell am switch-user 10

The terminal will output a simple confirmation, but the device screen will immediately transition to the target user's lock screen or launcher.

Common Mistake: Engineers frequently test background behaviors by just pressing the home button. This is inadequate for multi-user scenarios because standard backgrounding does not freeze the app's process or revoke access to hardware components the way a true user switch does.

UserManagerService bends the Linux kernel's single-user design into a multi-tenant environment through ID multiplexing. It tracks behavioral rules via configuration files and orchestrates secure data decryption alongside activity manager handoffs. Isolating identities and storage is only half of the security equation. The other half involves ensuring that apps cannot abuse the hardware access they have been granted, which introduces the need for permission management.