Android 是多用户操作系统。设备开机那一刻,用户身份(user 0,系统用户)就处于激活状态,整个框架基于用户边界实现数据、进程、权限隔离。这套多用户能力不仅支撑设置中的 “用户” 页面,还支持工作配置文件、隐私空间、访客账户、受限配置文件、克隆配置文件。
本章基于真实 AOSP 源码梳理多用户架构,涵盖system_server中的UserManagerService、用户类型定义、生命周期管理、存储布局、配置文件隔离以及用户切换机制。
31.1 多用户架构
31.1.1 设计基础
Android 多用户模型构建在 Linux 基于 UID 的进程隔离之上:
| 概念 | Linux 底层基础 | Android 扩展实现 |
|---|---|---|
| 用户隔离 | UID 区间 | 每个 Android 用户分配 100 000 大小的 UID 区间 |
| 进程隔离 | 进程命名空间 | 应用运行 uid = userId * 100000 + appId |
| 文件隔离 | 文件所有权 | 用户私有数据目录:/data/user/<userId>/ |
| 存储加密 | dm‑crypt | 按用户划分 CE/DE(凭证加密 / 设备加密)存储 |
对于存在 user 0、user 10 的设备,appId 为 10045 的应用运行 UID 计算:
- User 0:UID 10045
- User 10:UID 1010045
该计算逻辑编码在UserHandle:
public static final int PER_USER_RANGE = 100000;
public static int getUid(int userId, int appId) {
return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
}
31.1.2 核心类

源码路径:
| 类名 | 源码路径 |
|---|---|
| UserManagerService | frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java |
| UserTypeFactory | frameworks/base/services/core/java/com/android/server/pm/UserTypeFactory.java |
| UserTypeDetails | frameworks/base/services/core/java/com/android/server/pm/UserTypeDetails.java |
| UserDataPreparer | frameworks/base/services/core/java/com/android/server/pm/UserDataPreparer.java |
| UserVisibilityMediator | frameworks/base/services/core/java/com/android/server/pm/UserVisibilityMediator.java |
| UserSystemPackageInstaller | frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java |
31.1.3 UserManagerService 初始化
UserManagerService是所有用户操作的核心管理服务,实现IUserManager.Stub,多把锁保护关键状态:
// 摘自 UserManagerService.java
public class UserManagerService extends IUserManager.Stub {
// 锁顺序:先 mPackagesLock,后 mUsersLock
private final Object mPackagesLock;
private final Object mUsersLock = LockGuard.installNewLock(LockGuard.INDEX_USER);
private final Object mRestrictionsLock = NamedLock.create("mRestrictionsLock");
private final Object mAppRestrictionsLock = NamedLock.create("mAppRestrictionsLock");
@GuardedBy("mUsersLock")
private final SparseArray<UserData> mUsers;
private final ArrayMap<String, UserTypeDetails> mUserTypes;
}
类中记录锁调用命名约定:
方法命名约定:
- 后缀
LAr:调用时需要持有mAppRestrictionsLock锁- 后缀
LP:调用时需要持有mPackagesLock锁- 后缀
LR:调用时需要持有mRestrictionsLock锁- 后缀
LU:调用时需要持有mUsersLock锁
Method naming convention:
- Methods suffixed with "LAr" should be called within the `mAppRestrictionsLock` lock.
- Methods suffixed with "LP" should be called within the `mPackagesLock` lock.
- Methods suffixed with "LR" should be called within the `mRestrictionsLock` lock.
- Methods suffixed with "LU" should be called within the `mUsersLock` lock.
31.1.4 持久化存储
用户元数据磁盘存放路径:/data/system/users/
/data/system/users/
userlist.xml # 全部用户列表与下一个序列号
user.list # 性能优化版用户列表
0/ # 系统用户 user 0
0.xml # user0的UserInfo
photo.png # 用户头像
res_*.xml # 用户限制配置
10/ # 次要用户 user10
10.xml
11/ # 工作配置文件 user11
11.xml
userlist.xml示例:
<users nextSerialNumber="15" version="11">
<user id="0" />
<user id="10" />
<user id="11" />
</users>
单个用户 XML 文件(<id>.xml)内容示例:
<user
id="10"
serialNumber="12"
flags="0x00000810"
type="android.os.usertype.full.SECONDARY"
created="1700000000000"
lastLoggedIn="1700100000000"
lastEnteredForeground="1700100000000"
lastLoggedInFingerprint="google/pixel/..." >
<name>John</name>
<restrictions />
<userProperties />
</user>
文件属性直接对应UserManagerService常量:
// 摘自 UserManagerService.java
private static final String ATTR_FLAGS = "flags";
private static final String ATTR_TYPE = "type";
private static final String ATTR_ID = "id";
private static final String ATTR_CREATION_TIME = "created";
private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
private static final String ATTR_LAST_ENTERED_FOREGROUND_TIME = "lastEnteredForeground";
private static final String ATTR_SERIAL_NO = "serialNumber";
private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
31.1.5 用户 ID 分配
用户 ID 从MIN_USER_ID(10) 开始顺序分配:
// 摘自 UserManagerService.java
@VisibleForTesting
static final int MIN_USER_ID = UserHandle.MIN_SECONDARY_USER_ID; // 10
@VisibleForTesting
static final int MAX_USER_ID = UserHandle.MAX_SECONDARY_USER_ID; // Integer.MAX_VALUE / 100000
- user 0 永远是系统用户;ID 1‑9 保留预留。
- 新建用户分配下一个可用 ID。
- 序列号单调递增,即使用户被删除也不会复用,用于保证数据溯源。
用户 ID 与序列号相互独立: userID=10,serialNumber 可以是 12;user10 删除后,新用户可以复用 ID=10,但序列号会分配为 15。
系统维护最近已删除 ID 列表,避免刚删除的 ID 被立刻复用。
@VisibleForTesting
static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100;
31.1.6 用户限制
用户限制由多来源叠加:

合并逻辑在updateUserRestrictionsInternalLR,输出生效用户限制,供系统服务执行。
服务将生效限制与基础限制分开缓存:
// 摘自 UserManagerService.java
@GuardedBy("mRestrictionsLock")
private final RestrictionsSet mBaseUserRestrictions = new RestrictionsSet();
@GuardedBy("mRestrictionsLock")
private final RestrictionsSet mCachedEffectiveUserRestrictions = new RestrictionsSet();
重要:修改限制时,总是新建 Bundle 对象,不能直接修改已有 Bundle 实例,因为 Bundle 会在基础限制集合与缓存生效集合之间共享。
31.2 用户类型
31.2.1 UserTypeDetails 机制
Android 使用基于类型的体系定义用户分类;每种类型由UserTypeDetails定义,通过UserTypeFactory注册。
源码:frameworks/base/services/core/java/com/android/server/pm/UserTypeFactory.java
// 摘自 UserTypeFactory.java
public static ArrayMap<String, UserTypeDetails> getUserTypes() {
final ArrayMap<String, UserTypeDetails.Builder> builders = getDefaultBuilders();
// OEM可通过 config_user_types XML自定义
try (XmlResourceParser parser =
Resources.getSystem().getXml(R.xml.config_user_types)) {
customizeBuilders(builders, parser);
}
// 构建全部用户类型
final ArrayMap<String, UserTypeDetails> types = new ArrayMap<>(builders.size());
for (int i = 0; i < builders.size(); i++) {
types.put(builders.keyAt(i), builders.valueAt(i).createUserTypeDetails());
}
return types;
}
OEM 厂商可提供res/xml/config_user_types.xml覆盖默认配置,修改最大允许数量、默认限制、属性等。
31.2.2 AOSP 内置用户类型清单
工厂注册的默认类型:

源码详细类型规格:
| 类型常量 | 基础标志 | 最大数量 | 是否需要父用户 | 关键属性 |
|---|---|---|---|---|
| USER_TYPE_FULL_SYSTEM | FLAG_SYSTEM | FLAG_FULL | 1 | 否 | 主用户、管理员、主账号 |
| USER_TYPE_FULL_SECONDARY | FLAG_FULL | 配置值 | 否 | 标准次要用户 |
| USER_TYPE_FULL_GUEST | FLAG_FULL | 1 | 否 | 可临时(销毁式) |
| USER_TYPE_FULL_DEMO | FLAG_FULL | 3 | 否 | 演示 /kiosk 模式 |
| USER_TYPE_FULL_RESTRICTED | FLAG_FULL | 配置值 | 否 | 受限用户 |
| USER_TYPE_PROFILE_MANAGED | FLAG_PROFILE | 配置值 | 是 | 工作配置文件 |
| USER_TYPE_PROFILE_CLONE | FLAG_PROFILE | 每个父用户最多 1 | 是 | 应用克隆 |
| USER_TYPE_PROFILE_PRIVATE | FLAG_PROFILE | 1 | 是 | 隐私空间 |
| USER_TYPE_PROFILE_COMMUNAL | FLAG_PROFILE | 1 | 否 | 共享模式 |
| USER_TYPE_PROFILE_SUPERVISING | FLAG_PROFILE | 1 | 否 | 受监管用户 |
| USER_TYPE_PROFILE_TEST | FLAG_PROFILE | 4(每个父用户最多 2) | 是 | 仅调试,用于自动化测试 |
| USER_TYPE_SYSTEM_HEADLESS | FLAG_SYSTEM | 1 | 否 | 无界面系统用户模式 |
USER_TYPE_PROFILE_TEST仅在Build.IS_DEBUGGABLE调试版本注册,复用 managed profile 角标,只用于自动化测试。上表为getDefaultBuilders()注册的默认配置。
31.2.3 完整系统用户
系统用户(user 0)具备特殊性,传统非 headless 模式:
// 摘自 UserTypeFactory.java
private static UserTypeDetails.Builder getDefaultTypeFullSystem() {
return new UserTypeDetails.Builder()
.setName(USER_TYPE_FULL_SYSTEM)
.setBaseType(FLAG_SYSTEM | FLAG_FULL)
.setDefaultUserInfoPropertyFlags(FLAG_PRIMARY | FLAG_ADMIN | FLAG_MAIN)
.setMaxAllowed(1)
.setDefaultRestrictions(getDefaultSystemUserRestrictions());
}
- ID 固定为 0,永久存在,不可删除;开机第一个启动。
- Headless System User 模式(HSUM,车载设备使用):user0 后台运行,对用户不可见,实际操作用户在之上启动。
31.2.4 次要用户
标准次要用户是可切换完整用户:
private static UserTypeDetails.Builder getDefaultTypeFullSecondary() {
return new UserTypeDetails.Builder()
.setName(USER_TYPE_FULL_SECONDARY)
.setBaseType(FLAG_FULL)
.setMaxAllowed(getDefaultMaxAllowedForSwitchableTypes())
.setDefaultRestrictions(getDefaultSecondaryUserRestrictions());
}
getDefaultMaxAllowedForSwitchableTypes()返回getMaxSwitchableUsers()‑1,该上限绑定整机可切换用户配额;克隆、受限配置文件复用该工具函数。
次要用户默认限制:
DISALLOW_OUTGOING_CALLS = true禁止外呼DISALLOW_SMS = true禁止短信 管理员用户可以解除以上限制。
31.2.5 访客用户
访客用户用于设备临时共享场景:
private static UserTypeDetails.Builder getDefaultTypeFullGuest() {
final boolean ephemeralGuests = Resources.getSystem()
.getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
final int flags = FLAG_GUEST | (ephemeralGuests ? FLAG_EPHEMERAL : 0);
return new UserTypeDetails.Builder()
.setName(USER_TYPE_FULL_GUEST)
.setBaseType(FLAG_FULL)
.setDefaultUserInfoPropertyFlags(flags)
.setEnabled(getMaxSwitchableUsers() > 1 ? 1 : 0)
.setMaxAllowed(1)
.setDefaultRestrictions(getDefaultGuestUserRestrictions());
}
访客关键特性:
- 同一时刻只允许一个访客
- 可设置为临时销毁:退出时清空数据,由
config_guestUserEphemeral控制 - 继承次要用户全部限制,额外增加:
DISALLOW_INSTALL_UNKNOWN_SOURCES、DISALLOW_CONFIG_CREDENTIALS;根据android.multiuser.Flags.userRestrictionConfigWifiSharedPrivate()增加DISALLOW_CONFIG_WIFI_SHARED或DISALLOW_CONFIG_WIFI - 单用户设备下自动禁用(
setEnabled(getMaxSwitchableUsers() > 1 ? 1 : 0))
31.2.6 托管配置文件(工作配置文件 Work Profile)
工作配置文件是使用最广泛的配置文件类型,由 DPC 设备策略控制器管理:
private static UserTypeDetails.Builder getDefaultTypeProfileManaged() {
return new UserTypeDetails.Builder()
.setName(USER_TYPE_PROFILE_MANAGED)
.setBaseType(FLAG_PROFILE)
.setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE)
.setMaxAllowed(getMaxManagedProfiles())
.setMaxAllowedPerParent(getMaxManagedProfiles())
.setProfileParentRequired(true)
// …角标、标签、颜色配置
.setDefaultUserProperties(new UserProperties.Builder()
.setStartWithParent(true)
.setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
.setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
.setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED)
.setShowInSharingSurfaces(
UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
.setCredentialShareableWithParent(true));
}
属性释义:
startWithParent=true:父用户启动时,配置文件自动启动SHOW_IN_LAUNCHER_SEPARATE:工作应用在启动器带独立角标显示SHOW_IN_QUIET_MODE_PAUSED:静默模式开启,应用显示为暂停状态credentialShareableWithParent=true:可与父用户共用锁屏凭证
31.2.7 克隆配置文件(Clone Profile)
克隆配置文件允许同一应用运行第二个实例,多用于社交 / 消息类 App:
private static UserTypeDetails.Builder getDefaultTypeProfileClone() {
return new UserTypeDetails.Builder()
.setName(USER_TYPE_PROFILE_CLONE)
.setBaseType(FLAG_PROFILE)
.setMaxAllowedPerParent(1)
.setProfileParentRequired(true)
.setDefaultUserProperties(new UserProperties.Builder()
.setStartWithParent(true)
.setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT)
.setShowInSettings(UserProperties.SHOW_IN_SETTINGS_WITH_PARENT)
.setInheritDevicePolicy(
UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
.setUseParentsContacts(true)
.setMediaSharedWithParent(true)
.setCredentialShareableWithParent(true)
.setDeleteAppWithParent(true));
}
克隆配置文件特有属性:
SHOW_IN_LAUNCHER_WITH_PARENT:和父用户应用并列展示,不使用独立分页useParentsContacts=true:复用父用户联系人数据库mediaSharedWithParent=true:媒体存储与父用户共享deleteAppWithParent=true:父用户卸载应用时克隆版本同步卸载
31.2.8 受限配置文件(Restricted Profiles)
多用于平板设备,和父用户共享部分数据集,但访问权限受限:
private static UserTypeDetails.Builder getDefaultTypeFullRestricted() {
return new UserTypeDetails.Builder()
.setName(USER_TYPE_FULL_RESTRICTED)
.setBaseType(FLAG_FULL)
.setDefaultUserInfoPropertyFlags(FLAG_RESTRICTED)


1522

被折叠的 条评论
为什么被折叠?



