自 2025 年 3 月 27 日起,我们建议您使用 android-latest-release
而非 aosp-main
构建 AOSP 并为其做出贡献。如需了解详情,请参阅 AOSP 的变更。
构建可感知多用户的应用
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
对于支持多用户的设备,其中的应用必须能够感知不同的用户。
某些应用需要将一些组件作为单例运行,并且可接受来自任意用户的请求。目前只有系统应用可以使用此功能。
这种便利功能有以下益处:
- 节约资源
- 可在用户间裁决一项或多项共享资源
- 由于使用单一服务器连接,可减少网络开销
下图描绘了涉及多用户时的权限流程。
图 1. 多用户权限
启用单例组件
如需将应用标识为单例,请将 android:singleUser="true"
添加至 Android 清单中的服务、接收器或提供程序。
系统仅在以用户 0 身份运行的进程中将相应组件实例化。任何用户若提出任何连接到相应提供程序或服务或者向相应接收器发送广播的请求,都会传送到以用户 0 身份运行的进程。如果相应组件是应用中的唯一组件,则只有一个应用实例会运行。
软件包中的 activity 仍将在每个用户各自的进程中启动,并且 UID 处于相应用户的 UID 范围内(例如 1010034)。
与用户互动
设置权限
需要下列权限:
INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)
使用 API
使用下列 API 可使应用能够感知多个用户。
- 从传入的 Binder 调用中提取用户句柄:
int userHandle = UserHandle.getCallingUserId()
- 使用受保护的新 API 为特定用户启动服务、Activity 和广播:
Context.startActivityAsUser(Intent, UserHandle)
Context.bindServiceAsUser(Intent, …, UserHandle)
Context.sendBroadcastAsUser(Intent, … , UserHandle)
Context.startServiceAsUser(Intent, …, UserHandle)
UserHandle
可以是显式用户,也可以是以下特殊句柄之一:UserHandle.CURRENT
或 UserHandle.ALL
。CURRENT
表示当前位于前台的用户。如果您想向所有用户发送广播,请使用 ALL
。
- 如需与您自己应用中的组件通信,请使用
(INTERACT_ACROSS_USERS)
;如需与其他应用中的组件通信,请使用 (INTERACT_ACROSS_USERS_FULL)
- 您可能需要创建代理组件,这些代理组件先在用户的进程中运行,之后会访问以用户 0 身份运行的
singleUser
组件。
- 使用新的
UserManager
系统服务查询用户及其句柄:
UserManager.getUsers()
UserManager.getUserInfo()
UserManager.supportsMultipleUsers()
UserManager.getUserSerialNumber(int userHandle)
- 与用户句柄对应的不可再循环数字。
UserManager.getUserHandle(int serialNumber)
UserManager.getUserProfiles()
- 返回用户本人个人资料和受管个人资料的集合(如有)。
- 注册即可借助 ContentObserver、PackageMonitor 和 BroadcastReceiver 上的新 API 监听特定或所有用户以及回调(可提供与回调发起用户相关的其他信息)。
多个用户或资料中的服务
并非所有服务都需要在其他用户或工作资料中运行实例。如果您的系统服务只需要以用户 0 的身份运行,则在以其他用户的身份运行时应停用该服务的组件,以帮助节省资源。下例显示了如何在服务的入口点执行此操作:
// Add on all entry points such as boot_completed or other manifest-listed receivers and providers
if (!UserManager.isSystemUser()) {
// Disable the service
ComponentName targetServiceName = new ComponentName(this, TargetService.class);
context.getPackageManager().setComponentEnabledSetting(
targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0);
}
该示例还可以使用 PackageManager.setApplicationEnabledSetting()
来停用整个应用。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[null,null,["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Build multiuser-aware apps\n\nWhen a device supports [multiple users](/docs/devices/admin/multi-user), its apps must be\nmade aware of these distinct users.\n\nCertain apps need to have some components run as singletons and can accept\nrequests from any user. Only system apps can currently use this feature.\n\nThis facility:\n\n- Conserves resources\n- Arbitrates one or more shared resources across users\n- Reduces network overhead by using a single server connection\n\nSee the diagram below for a depiction of permissions flow with multiple users.\n\n\n**Figure 1.** Multiple users permissions\n\nEnable a singleton component\n----------------------------\n\nTo identify an app as a singleton, add `android:singleUser=\"true\"` to your service,\nreceiver, or provider in the Android manifest.\n\nThe system instantiates that component in the process running as user 0\nonly. Any requests to connect to that provider or service, or to broadcast to that receiver, from\nany user is routed to the process in user 0. If this is the only component in your app,\nonly one instance of your app runs.\n\nActivities in your package are still launched in a separate process for\neach user, with the UID being in the UID range for that user (such as 1010034).\n\nInteract with users\n-------------------\n\n### Set permissions\n\nThese permissions are required: \n\n```\nINTERACT_ACROSS_USERS (signature|system)\nINTERACT_ACROSS_USERS_FULL (signature)\n```\n\n### Employ APIs\n\nUse the following APIs to make apps aware of multiple users.\n\n1. Extract the user handle from incoming Binder calls:\n - `int userHandle = UserHandle.getCallingUserId()`\n2. Use new, protected APIs to start services, activities, broadcasts on a specific user:\n - `Context.startActivityAsUser(Intent, UserHandle)`\n - `Context.bindServiceAsUser(Intent, ..., UserHandle)`\n - `Context.sendBroadcastAsUser(Intent, ... , UserHandle)`\n - `Context.startServiceAsUser(Intent, ..., UserHandle)`\n\n `UserHandle` can be an explicit user or one of the special handles: `UserHandle.CURRENT` or `UserHandle.ALL`. `CURRENT` indicates the user that is currently in the foreground. Use `ALL` when you want to send a broadcast to all users.\n3. Communicate with components in your own app: `(INTERACT_ACROSS_USERS)` Or with components in other apps: `(INTERACT_ACROSS_USERS_FULL)`\n4. You might need to create proxy components that run in the user's process that then access the `singleUser` component in user 0.\n5. Query users and their handles with the new `UserManager` system service:\n - `UserManager.getUsers()`\n - `UserManager.getUserInfo()`\n - `UserManager.supportsMultipleUsers()`\n - `UserManager.getUserSerialNumber(int userHandle)` - a nonrecycled number that corresponds to a user handle.\n - `UserManager.getUserHandle(int serialNumber)`\n - `UserManager.getUserProfiles()` - returns the collection of self and managed profiles, if any.\n6. Register to listen to specific or all users and the callbacks with new APIs on ContentObserver, PackageMonitor, BroadcastReceiver that provide additional information about which user has caused the callback.\n\n### Services in multiple users or profiles\n\nNot all services need to run an instance in another user or work profile. If your system service\nonly needs to run as user 0, disable the service's components when running under other users to\nhelp preserve resources. The following example shows how you might do this at your service's entry\npoints: \n\n```\n// Add on all entry points such as boot_completed or other manifest-listed receivers and providers\nif (!UserManager.isSystemUser()) {\n // Disable the service\n ComponentName targetServiceName = new ComponentName(this, TargetService.class);\n context.getPackageManager().setComponentEnabledSetting(\n targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0);\n}\n```\n\nThe example could also use `PackageManager.setApplicationEnabledSetting()` to disable\nthe entire app."]]