Когда устройство поддерживает нескольких пользователей , его приложения должны получать информацию об этих отдельных пользователях.
Некоторые приложения должны иметь некоторые компоненты, работающие как синглтоны, и могут принимать запросы от любого пользователя. В настоящее время эту функцию могут использовать только системные приложения.
Этот объект:
- Экономит ресурсы
- Арбитражирует один или несколько общих ресурсов между пользователями
- Снижает нагрузку на сеть за счет использования одного подключения к серверу.
См. диаграмму ниже для изображения потока разрешений с несколькими пользователями.
Включение одноэлементного компонента
Чтобы идентифицировать приложение как одноэлементное, добавьте android:singleUser=”true”
к службе, получателю или поставщику в манифесте Android.
Система создаст экземпляр этого компонента в процессе, работающем только от имени пользователя 0. Любые запросы на подключение к этому провайдеру или службе или на трансляцию на этот приемник от любого пользователя будут направляться процессу пользователя 0. Если это единственный компонент в вашем приложении, будет запущен только один экземпляр вашего приложения.
Действия в вашем пакете по-прежнему будут запускаться в отдельном процессе для каждого пользователя с UID, находящимся в диапазоне UID для этого пользователя (например, 1010034).
Взаимодействие с пользователями
Установить разрешения
Эти разрешения необходимы
INTERACT_ACROSS_USERS (signature|system) INTERACT_ACROSS_USERS_FULL (signature)
Используйте API
Используйте следующие API, чтобы приложения знали о нескольких пользователях.
- Извлеките дескриптор пользователя из входящих вызовов Binder:
-
int userHandle = UserHandle.getCallingUserId()
-
- Используйте новые защищенные API для запуска сервисов, активностей, трансляций для конкретного пользователя:
-
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)
- Возможно, вам потребуется создать прокси-компоненты, которые запускаются в процессе пользователя, а затем получают доступ к компоненту
singleUser
пользователя 0. - Запрашивайте пользователей и их дескрипторы с помощью новой системной службы
UserManager
:-
UserManager.getUsers()
-
UserManager.getUserInfo()
-
UserManager.supportsMultipleUsers()
-
UserManager.getUserSerialNumber(int userHandle)
— непереработанный номер, соответствующий дескриптору пользователя. -
UserManager.getUserHandle(int serialNumber)
-
UserManager.getUserProfiles()
— возвращает коллекцию собственных и управляемых профилей, если таковые имеются.
-
- Зарегистрируйтесь, чтобы прослушивать определенных или всех пользователей и обратные вызовы с помощью новых API-интерфейсов на ContentObserver, PackageMonitor, BroadcastReceiver, которые предоставляют дополнительную информацию о том, какой пользователь вызвал обратный вызов.
Услуги для нескольких пользователей или профилей
Не всем службам нужно запускать экземпляр в другом пользовательском или рабочем профиле. Если вашей системной службе нужно работать только от имени пользователя 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()
для отключения всего приложения.