/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.server.am; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM; import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP; import static android.app.ActivityManager.USER_OP_IS_CURRENT; import static android.app.ActivityManager.USER_OP_SUCCESS; import static android.content.Context.KEYGUARD_SERVICE; import static android.os.Process.SYSTEM_UID; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY; import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL; import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE; import static com.android.server.am.ActivityManagerService.MY_PID; import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG; import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG; import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG; import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG; import static com.android.server.am.ActivityManagerService.SYSTEM_USER_UNLOCK_MSG; import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG; import static com.android.server.am.UserState.STATE_BOOTING; import static com.android.server.am.UserState.STATE_RUNNING_LOCKED; import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKED; import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKING; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.Dialog; import android.app.IStopUserCallback; import android.app.IUserSwitchObserver; import android.app.KeyguardManager; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.BatteryStats; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.IProgressListener; import android.os.IRemoteCallback; import android.os.IUserManager; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.util.ArraySet; import android.util.IntArray; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.pm.UserManagerService; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; /** * Helper class for {@link ActivityManagerService} responsible for multi-user functionality. */ final class UserController { private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM; // Maximum number of users we allow to be running at a time. static final int MAX_RUNNING_USERS = 3; // Amount of time we wait for observers to handle a user switch before // giving up on them and unfreezing the screen. static final int USER_SWITCH_TIMEOUT = 2 * 1000; private final ActivityManagerService mService; private final Handler mHandler; // Holds the current foreground user's id private int mCurrentUserId = UserHandle.USER_SYSTEM; // Holds the target user's id during a user switch private int mTargetUserId = UserHandle.USER_NULL; /** * Which users have been started, so are allowed to run code. */ @GuardedBy("mService") private final SparseArray<UserState> mStartedUsers = new SparseArray<>(); /** * LRU list of history of current users. Most recently current is at the end. */ private final ArrayList<Integer> mUserLru = new ArrayList<>(); /** * Constant array of the users that are currently started. */ private int[] mStartedUserArray = new int[] { 0 }; // If there are multiple profiles for the current user, their ids are here // Currently only the primary user can have managed profiles private int[] mCurrentProfileIds = new int[] {}; /** * Mapping from each known user ID to the profile group ID it is associated with. */ private final SparseIntArray mUserProfileGroupIdsSelfLocked = new SparseIntArray(); /** * Registered observers of the user switching mechanics. */ private final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers = new RemoteCallbackList<>(); /** * Currently active user switch callbacks. */ private volatile ArraySet<String> mCurWaitingUserSwitchCallbacks; private volatile UserManagerService mUserManager; private final LockPatternUtils mLockPatternUtils; private UserManagerInternal mUserManagerInternal; UserController(ActivityManagerService service) { mService = service; mHandler = mService.mHandler; // User 0 is the first and only user that runs at boot. final UserState uss = new UserState(UserHandle.SYSTEM); mStartedUsers.put(UserHandle.USER_SYSTEM, uss); mUserLru.add(UserHandle.USER_SYSTEM); mLockPatternUtils = new LockPatternUtils(mService.mContext); updateStartedUserArrayLocked(); } void finishUserSwitch(UserState uss) { synchronized (mService) { finishUserBoot(uss); startProfilesLocked(); stopRunningUsersLocked(MAX_RUNNING_USERS); } } void stopRunningUsersLocked(int maxRunningUsers) { int num = mUserLru.size(); int i = 0; while (num > maxRunningUsers && i < mUserLru.size()) { Integer oldUserId = mUserLru.get(i); UserState oldUss = mStartedUsers.get(oldUserId); if (oldUss == null) { // Shouldn't happen, but be sane if it does. mUserLru.remove(i); num--; continue; } if (oldUss.state == UserState.STATE_STOPPING || oldUss.state == UserState.STATE_SHUTDOWN) { // This user is already stopping, doesn't count. num--; i++; continue; } if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) { // Owner/System user and current user can't be stopped. We count it as running // when it is not a pure system user. if (UserInfo.isSystemOnly(oldUserId)) { num--; } i++; continue; } // This is a user to be stopped. if (stopUsersLocked(oldUserId, false, null) != USER_OP_SUCCESS) { num--; } num--; i++; } } private void finishUserBoot(UserState uss) { finishUserBoot(uss, null); } private void finishUserBoot(UserState uss, IIntentReceiver resultTo) { final int userId = uss.mHandle.getIdentifier(); Slog.d(TAG, "Finishing user boot " + userId); synchronized (mService) { // Bail if we ended up with a stale user if (mStartedUsers.get(userId) != uss) return; // We always walk through all the user lifecycle states to send // consistent developer events. We step into RUNNING_LOCKED here, // but we might immediately step into RUNNING below if the user // storage is already unlocked. if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) { getUserManagerInternal().setUserState(userId, uss.state); int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000); MetricsLogger.histogram(mService.mContext, "framework_locked_boot_completed", uptimeSeconds); Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mService.broadcastIntentLocked(null, null, intent, null, resultTo, 0, null, null, new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, AppOpsManager.OP_BOOT_COMPLETED, null, true, false, MY_PID, SYSTEM_UID, userId); } // We need to delay unlocking managed profiles until the parent user // is also unlocked. if (getUserManager().isManagedProfile(userId)) { final UserInfo parent = getUserManager().getProfileParent(userId); if (parent != null && isUserRunningLocked(parent.id, ActivityManager.FLAG_AND_UNLOCKED)) { Slog.d(TAG, "User " + userId + " (parent " + parent.id + "): attempting unlock because parent is unlocked"); maybeUnlockUser(userId); } else { String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id); Slog.d(TAG, "User " + userId + " (parent " + parentId + "): delaying unlock because parent is locked"); } } else { maybeUnlockUser(userId); } } } /** * Step from {@link UserState#STATE_RUNNING_LOCKED} to * {@link UserState#STATE_RUNNING_UNLOCKING}. */ private void finishUserUnlocking(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); boolean proceedWithUnlock = false; synchronized (mService) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; // Only keep marching forward if user is actually unlocked if (!StorageManager.isUserKeyUnlocked(userId)) return; if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) { getUserManagerInternal().setUserState(userId, uss.state); proceedWithUnlock = true; } } if (proceedWithUnlock) { uss.mUnlockProgress.start(); // Prepare app storage before we go any further uss.mUnlockProgress.setProgress(5, mService.mContext.getString(R.string.android_start_title)); mUserManager.onBeforeUnlockUser(userId); uss.mUnlockProgress.setProgress(20); // Dispatch unlocked to system services; when fully dispatched, // that calls through to the next "unlocked" phase mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) .sendToTarget(); } } /** * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to * {@link UserState#STATE_RUNNING_UNLOCKED}. */ void finishUserUnlocked(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; // Only keep marching forward if user is actually unlocked if (!StorageManager.isUserKeyUnlocked(userId)) return; if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) { getUserManagerInternal().setUserState(userId, uss.state); uss.mUnlockProgress.finish(); // Dispatch unlocked to external apps final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED); unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); unlockedIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); mService.broadcastIntentLocked(null, null, unlockedIntent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, userId); if (getUserInfo(userId).isManagedProfile()) { UserInfo parent = getUserManager().getProfileParent(userId); if (parent != null) { final Intent profileUnlockedIntent = new Intent( Intent.ACTION_MANAGED_PROFILE_UNLOCKED); profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId)); profileUnlockedIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); mService.broadcastIntentLocked(null, null, profileUnlockedIntent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, parent.id); } } // Send PRE_BOOT broadcasts if user fingerprint changed; we // purposefully block sending BOOT_COMPLETED until after all // PRE_BOOT receivers are finished to avoid ANR'ing apps final UserInfo info = getUserInfo(userId); if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) { // Suppress double notifications for managed profiles that // were unlocked automatically as part of their parent user // being unlocked. final boolean quiet; if (info.isManagedProfile()) { quiet = !uss.tokenProvided || !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId); } else { quiet = false; } new PreBootBroadcaster(mService, userId, null, quiet) { @Override public void onFinished() { finishUserUnlockedCompleted(uss); } }.sendNext(); } else { finishUserUnlockedCompleted(uss); } } } } private void finishUserUnlockedCompleted(UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; final UserInfo userInfo = getUserInfo(userId); if (userInfo == null) { return; } // Only keep marching forward if user is actually unlocked if (!StorageManager.isUserKeyUnlocked(userId)) return; // Remember that we logged in mUserManager.onUserLoggedIn(userId); if (!userInfo.isInitialized()) { if (userId != UserHandle.USER_SYSTEM) { Slog.d(TAG, "Initializing user #" + userId); Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mService.broadcastIntentLocked(null, null, intent, null, new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { // Note: performReceive is called with mService lock held getUserManager().makeInitialized(userInfo.id); } }, 0, null, null, null, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); } } Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId); int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000); MetricsLogger.histogram(mService.mContext, "framework_boot_completed", uptimeSeconds); final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null, new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, AppOpsManager.OP_BOOT_COMPLETED, null, true, false, MY_PID, SYSTEM_UID, userId); } } int stopUser(final int userId, final boolean force, final IStopUserCallback callback) { if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: switchUser() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + INTERACT_ACROSS_USERS_FULL; Slog.w(TAG, msg); throw new SecurityException(msg); } if (userId < 0 || userId == UserHandle.USER_SYSTEM) { throw new IllegalArgumentException("Can't stop system user " + userId); } mService.enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId); synchronized (mService) { return stopUsersLocked(userId, force, callback); } } /** * Stops the user along with its related users. The method calls * {@link #getUsersToStopLocked(int)} to determine the list of users that should be stopped. */ private int stopUsersLocked(final int userId, boolean force, final IStopUserCallback callback) { if (userId == UserHandle.USER_SYSTEM) { return USER_OP_ERROR_IS_SYSTEM; } if (isCurrentUserLocked(userId)) { return USER_OP_IS_CURRENT; } int[] usersToStop = getUsersToStopLocked(userId); // If one of related users is system or current, no related users should be stopped for (int i = 0; i < usersToStop.length; i++) { int relatedUserId = usersToStop[i]; if ((UserHandle.USER_SYSTEM == relatedUserId) || isCurrentUserLocked(relatedUserId)) { if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked cannot stop related user " + relatedUserId); // We still need to stop the requested user if it's a force stop. if (force) { Slog.i(TAG, "Force stop user " + userId + ". Related users will not be stopped"); stopSingleUserLocked(userId, callback); return USER_OP_SUCCESS; } return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP; } } if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked usersToStop=" + Arrays.toString(usersToStop)); for (int userIdToStop : usersToStop) { stopSingleUserLocked(userIdToStop, userIdToStop == userId ? callback : null); } return USER_OP_SUCCESS; } private void stopSingleUserLocked(final int userId, final IStopUserCallback callback) { if (DEBUG_MU) Slog.i(TAG, "stopSingleUserLocked userId=" + userId); final UserState uss = mStartedUsers.get(userId); if (uss == null) { // User is not started, nothing to do... but we do need to // callback if requested. if (callback != null) { mHandler.post(new Runnable() { @Override public void run() { try { callback.userStopped(userId); } catch (RemoteException e) { } } }); } return; } if (callback != null) { uss.mStopCallbacks.add(callback); } if (uss.state != UserState.STATE_STOPPING && uss.state != UserState.STATE_SHUTDOWN) { uss.setState(UserState.STATE_STOPPING); getUserManagerInternal().setUserState(userId, uss.state); updateStartedUserArrayLocked(); long ident = Binder.clearCallingIdentity(); try { // We are going to broadcast ACTION_USER_STOPPING and then // once that is done send a final ACTION_SHUTDOWN and then // stop the user. final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING); stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true); // This is the result receiver for the initial stopping broadcast. final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { mHandler.post(new Runnable() { @Override public void run() { finishUserStopping(userId, uss); } }); } }; // Clear broadcast queue for the user to avoid delivering stale broadcasts mService.clearBroadcastQueueForUserLocked(userId); // Kick things off. mService.broadcastIntentLocked(null, null, stoppingIntent, null, stoppingReceiver, 0, null, null, new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); } } } void finishUserStopping(final int userId, final UserState uss) { // On to the next. final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN); // This is the result receiver for the final shutdown broadcast. final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { mHandler.post(new Runnable() { @Override public void run() { finishUserStopped(uss); } }); } }; synchronized (mService) { if (uss.state != UserState.STATE_STOPPING) { // Whoops, we are being started back up. Abort, abort! return; } uss.setState(UserState.STATE_SHUTDOWN); } getUserManagerInternal().setUserState(userId, uss.state); mService.mBatteryStatsService.noteEvent( BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH, Integer.toString(userId), userId); mService.mSystemServiceManager.stopUser(userId); synchronized (mService) { mService.broadcastIntentLocked(null, null, shutdownIntent, null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); } } void finishUserStopped(UserState uss) { final int userId = uss.mHandle.getIdentifier(); boolean stopped; ArrayList<IStopUserCallback> callbacks; synchronized (mService) { callbacks = new ArrayList<>(uss.mStopCallbacks); if (mStartedUsers.get(userId) != uss) { stopped = false; } else if (uss.state != UserState.STATE_SHUTDOWN) { stopped = false; } else { stopped = true; // User can no longer run. mStartedUsers.remove(userId); getUserManagerInternal().removeUserState(userId); mUserLru.remove(Integer.valueOf(userId)); updateStartedUserArrayLocked(); mService.onUserStoppedLocked(userId); // Clean up all state and processes associated with the user. // Kill all the processes for the user. forceStopUserLocked(userId, "finish user"); } } for (int i = 0; i < callbacks.size(); i++) { try { if (stopped) callbacks.get(i).userStopped(userId); else callbacks.get(i).userStopAborted(userId); } catch (RemoteException e) { } } if (stopped) { mService.mSystemServiceManager.cleanupUser(userId); synchronized (mService) { mService.mStackSupervisor.removeUserLocked(userId); } // Remove the user if it is ephemeral. if (getUserInfo(userId).isEphemeral()) { mUserManager.removeUser(userId); } } } /** * Determines the list of users that should be stopped together with the specified * {@code userId}. The returned list includes {@code userId}. */ private @NonNull int[] getUsersToStopLocked(int userId) { int startedUsersSize = mStartedUsers.size(); IntArray userIds = new IntArray(); userIds.add(userId); synchronized (mUserProfileGroupIdsSelfLocked) { int userGroupId = mUserProfileGroupIdsSelfLocked.get(userId, UserInfo.NO_PROFILE_GROUP_ID); for (int i = 0; i < startedUsersSize; i++) { UserState uss = mStartedUsers.valueAt(i); int startedUserId = uss.mHandle.getIdentifier(); // Skip unrelated users (profileGroupId mismatch) int startedUserGroupId = mUserProfileGroupIdsSelfLocked.get(startedUserId, UserInfo.NO_PROFILE_GROUP_ID); boolean sameGroup = (userGroupId != UserInfo.NO_PROFILE_GROUP_ID) && (userGroupId == startedUserGroupId); // userId has already been added boolean sameUserId = startedUserId == userId; if (!sameGroup || sameUserId) { continue; } userIds.add(startedUserId); } } return userIds.toArray(); } private void forceStopUserLocked(int userId, String reason) { mService.forceStopPackageLocked(null, -1, false, false, true, false, false, userId, reason); Intent intent = new Intent(Intent.ACTION_USER_STOPPED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL); } /** * Stops the guest or ephemeral user if it has gone to the background. */ private void stopGuestOrEphemeralUserIfBackground() { synchronized (mService) { final int num = mUserLru.size(); for (int i = 0; i < num; i++) { Integer oldUserId = mUserLru.get(i); UserState oldUss = mStartedUsers.get(oldUserId); if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId || oldUss.state == UserState.STATE_STOPPING || oldUss.state == UserState.STATE_SHUTDOWN) { continue; } UserInfo userInfo = getUserInfo(oldUserId); if (userInfo.isEphemeral()) { LocalServices.getService(UserManagerInternal.class) .onEphemeralUserStop(oldUserId); } if (userInfo.isGuest() || userInfo.isEphemeral()) { // This is a user to be stopped. stopUsersLocked(oldUserId, true, null); break; } } } } void startProfilesLocked() { if (DEBUG_MU) Slog.i(TAG, "startProfilesLocked"); List<UserInfo> profiles = getUserManager().getProfiles( mCurrentUserId, false /* enabledOnly */); List<UserInfo> profilesToStart = new ArrayList<>(profiles.size()); for (UserInfo user : profiles) { if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED && user.id != mCurrentUserId && !user.isQuietModeEnabled()) { profilesToStart.add(user); } } final int profilesToStartSize = profilesToStart.size(); int i = 0; for (; i < profilesToStartSize && i < (MAX_RUNNING_USERS - 1); ++i) { startUser(profilesToStart.get(i).id, /* foreground= */ false); } if (i < profilesToStartSize) { Slog.w(TAG, "More profiles than MAX_RUNNING_USERS"); } } private UserManagerService getUserManager() { UserManagerService userManager = mUserManager; if (userManager == null) { IBinder b = ServiceManager.getService(Context.USER_SERVICE); userManager = mUserManager = (UserManagerService) IUserManager.Stub.asInterface(b); } return userManager; } private IMountService getMountService() { return IMountService.Stub.asInterface(ServiceManager.getService("mount")); } /** * Start user, if its not already running. * <p>The user will be brought to the foreground, if {@code foreground} parameter is set. * When starting the user, multiple intents will be broadcast in the following order:</p> * <ul> * <li>{@link Intent#ACTION_USER_STARTED} - sent to registered receivers of the new user * <li>{@link Intent#ACTION_USER_BACKGROUND} - sent to registered receivers of the outgoing * user and all profiles of this user. Sent only if {@code foreground} parameter is true * <li>{@link Intent#ACTION_USER_FOREGROUND} - sent to registered receivers of the new * user and all profiles of this user. Sent only if {@code foreground} parameter is true * <li>{@link Intent#ACTION_USER_SWITCHED} - sent to registered receivers of the new user. * Sent only if {@code foreground} parameter is true * <li>{@link Intent#ACTION_USER_STARTING} - ordered broadcast sent to registered receivers * of the new fg user * <li>{@link Intent#ACTION_LOCKED_BOOT_COMPLETED} - ordered broadcast sent to receivers of * the new user * <li>{@link Intent#ACTION_USER_UNLOCKED} - sent to registered receivers of the new user * <li>{@link Intent#ACTION_PRE_BOOT_COMPLETED} - ordered broadcast sent to receivers of the * new user. Sent only when the user is booting after a system update. * <li>{@link Intent#ACTION_USER_INITIALIZE} - ordered broadcast sent to receivers of the * new user. Sent only the first time a user is starting. * <li>{@link Intent#ACTION_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new * user. Indicates that the user has finished booting. * </ul> * * @param userId ID of the user to start * @param foreground true if user should be brought to the foreground * @return true if the user has been successfully started */ boolean startUser(final int userId, final boolean foreground) { if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: switchUser() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + INTERACT_ACROSS_USERS_FULL; Slog.w(TAG, msg); throw new SecurityException(msg); } Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground); final long ident = Binder.clearCallingIdentity(); try { synchronized (mService) { final int oldUserId = mCurrentUserId; if (oldUserId == userId) { return true; } mService.mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE, "startUser", false); final UserInfo userInfo = getUserInfo(userId); if (userInfo == null) { Slog.w(TAG, "No user info for user #" + userId); return false; } if (foreground && userInfo.isManagedProfile()) { Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user"); return false; } if (foreground) { mService.mWindowManager.startFreezingScreen( R.anim.screen_user_exit, R.anim.screen_user_enter); } boolean needStart = false; // If the user we are switching to is not currently started, then // we need to start it now. if (mStartedUsers.get(userId) == null) { UserState userState = new UserState(UserHandle.of(userId)); mStartedUsers.put(userId, userState); getUserManagerInternal().setUserState(userId, userState.state); updateStartedUserArrayLocked(); needStart = true; } final UserState uss = mStartedUsers.get(userId); final Integer userIdInt = userId; mUserLru.remove(userIdInt); mUserLru.add(userIdInt); if (foreground) { mCurrentUserId = userId; mService.updateUserConfigurationLocked(); mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up updateCurrentProfileIdsLocked(); mService.mWindowManager.setCurrentUser(userId, mCurrentProfileIds); // Once the internal notion of the active user has switched, we lock the device // with the option to show the user switcher on the keyguard. mService.mWindowManager.lockNow(null); } else { final Integer currentUserIdInt = mCurrentUserId; updateCurrentProfileIdsLocked(); mService.mWindowManager.setCurrentProfileIds(mCurrentProfileIds); mUserLru.remove(currentUserIdInt); mUserLru.add(currentUserIdInt); } // Make sure user is in the started state. If it is currently // stopping, we need to knock that off. if (uss.state == UserState.STATE_STOPPING) { // If we are stopping, we haven't sent ACTION_SHUTDOWN, // so we can just fairly silently bring the user back from // the almost-dead. uss.setState(uss.lastState); getUserManagerInternal().setUserState(userId, uss.state); updateStartedUserArrayLocked(); needStart = true; } else if (uss.state == UserState.STATE_SHUTDOWN) { // This means ACTION_SHUTDOWN has been sent, so we will // need to treat this as a new boot of the user. uss.setState(UserState.STATE_BOOTING); getUserManagerInternal().setUserState(userId, uss.state); updateStartedUserArrayLocked(); needStart = true; } if (uss.state == UserState.STATE_BOOTING) { // Give user manager a chance to propagate user restrictions // to other services and prepare app storage getUserManager().onBeforeStartUser(userId); // Booting up a new user, need to tell system services about it. // Note that this is on the same handler as scheduling of broadcasts, // which is important because it needs to go first. mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0)); } if (foreground) { mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId, oldUserId)); mHandler.removeMessages(REPORT_USER_SWITCH_MSG); mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG); mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG, oldUserId, userId, uss)); mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG, oldUserId, userId, uss), USER_SWITCH_TIMEOUT); } if (needStart) { // Send USER_STARTED broadcast Intent intent = new Intent(Intent.ACTION_USER_STARTED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, userId); } if (foreground) { moveUserToForegroundLocked(uss, oldUserId, userId); } else { mService.mUserController.finishUserBoot(uss); } if (needStart) { Intent intent = new Intent(Intent.ACTION_USER_STARTING); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); mService.broadcastIntentLocked(null, null, intent, null, new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { } }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL); } } } finally { Binder.restoreCallingIdentity(ident); } return true; } /** * Start user, if its not already running, and bring it to foreground. */ boolean startUserInForeground(final int userId, Dialog dlg) { boolean result = startUser(userId, /* foreground */ true); dlg.dismiss(); return result; } boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) { if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: unlockUser() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + INTERACT_ACROSS_USERS_FULL; Slog.w(TAG, msg); throw new SecurityException(msg); } final long binderToken = Binder.clearCallingIdentity(); try { return unlockUserCleared(userId, token, secret, listener); } finally { Binder.restoreCallingIdentity(binderToken); } } /** * Attempt to unlock user without a credential token. This typically * succeeds when the device doesn't have credential-encrypted storage, or * when the the credential-encrypted storage isn't tied to a user-provided * PIN or pattern. */ boolean maybeUnlockUser(final int userId) { // Try unlocking storage using empty token return unlockUserCleared(userId, null, null, null); } private static void notifyFinished(int userId, IProgressListener listener) { if (listener == null) return; try { listener.onFinished(userId, null); } catch (RemoteException ignored) { } } boolean unlockUserCleared(final int userId, byte[] token, byte[] secret, IProgressListener listener) { UserState uss; synchronized (mService) { // TODO Move this block outside of synchronized if it causes lock contention if (!StorageManager.isUserKeyUnlocked(userId)) { final UserInfo userInfo = getUserInfo(userId); final IMountService mountService = getMountService(); try { // We always want to unlock user storage, even user is not started yet mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret); } catch (RemoteException | RuntimeException e) { Slog.w(TAG, "Failed to unlock: " + e.getMessage()); } } // Bail if user isn't actually running, otherwise register the given // listener to watch for unlock progress uss = mStartedUsers.get(userId); if (uss == null) { notifyFinished(userId, listener); return false; } else { uss.mUnlockProgress.addListener(listener); uss.tokenProvided = (token != null); } } finishUserUnlocking(uss); final ArraySet<Integer> childProfilesToUnlock = new ArraySet<>(); synchronized (mService) { // We just unlocked a user, so let's now attempt to unlock any // managed profiles under that user. for (int i = 0; i < mStartedUsers.size(); i++) { final int testUserId = mStartedUsers.keyAt(i); final UserInfo parent = getUserManager().getProfileParent(testUserId); if (parent != null && parent.id == userId && testUserId != userId) { Slog.d(TAG, "User " + testUserId + " (parent " + parent.id + "): attempting unlock because parent was just unlocked"); childProfilesToUnlock.add(testUserId); } } } final int size = childProfilesToUnlock.size(); for (int i = 0; i < size; i++) { maybeUnlockUser(childProfilesToUnlock.valueAt(i)); } return true; } void showUserSwitchDialog(Pair<UserInfo, UserInfo> fromToUserPair) { // The dialog will show and then initiate the user switch by calling startUserInForeground Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromToUserPair.first, fromToUserPair.second, true /* above system */); d.show(); } void dispatchForegroundProfileChanged(int userId) { final int observerCount = mUserSwitchObservers.beginBroadcast(); for (int i = 0; i < observerCount; i++) { try { mUserSwitchObservers.getBroadcastItem(i).onForegroundProfileSwitch(userId); } catch (RemoteException e) { // Ignore } } mUserSwitchObservers.finishBroadcast(); } /** Called on handler thread */ void dispatchUserSwitchComplete(int userId) { final int observerCount = mUserSwitchObservers.beginBroadcast(); for (int i = 0; i < observerCount; i++) { try { mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(userId); } catch (RemoteException e) { } } mUserSwitchObservers.finishBroadcast(); } private void stopBackgroundUsersIfEnforced(int oldUserId) { // Never stop system user if (oldUserId == UserHandle.USER_SYSTEM) { return; } // For now, only check for user restriction. Additional checks can be added here boolean disallowRunInBg = hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND, oldUserId); if (!disallowRunInBg) { return; } synchronized (mService) { if (DEBUG_MU) Slog.i(TAG, "stopBackgroundUsersIfEnforced stopping " + oldUserId + " and related users"); stopUsersLocked(oldUserId, false, null); } } void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) { synchronized (mService) { Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId + ". Observers that didn't send results: " + mCurWaitingUserSwitchCallbacks); sendContinueUserSwitchLocked(uss, oldUserId, newUserId); } } void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) { Slog.d(TAG, "Dispatch onUserSwitching oldUser #" + oldUserId + " newUser #" + newUserId); final int observerCount = mUserSwitchObservers.beginBroadcast(); if (observerCount > 0) { final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); synchronized (mService) { uss.switching = true; mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks; } final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount); for (int i = 0; i < observerCount; i++) { try { // Prepend with unique prefix to guarantee that keys are unique final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); synchronized (mService) { curWaitingUserSwitchCallbacks.add(name); } final IRemoteCallback callback = new IRemoteCallback.Stub() { @Override public void sendResult(Bundle data) throws RemoteException { synchronized (mService) { // Early return if this session is no longer valid if (curWaitingUserSwitchCallbacks != mCurWaitingUserSwitchCallbacks) { return; } curWaitingUserSwitchCallbacks.remove(name); // Continue switching if all callbacks have been notified if (waitingCallbacksCount.decrementAndGet() == 0) { sendContinueUserSwitchLocked(uss, oldUserId, newUserId); } } } }; mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback); } catch (RemoteException e) { } } } else { synchronized (mService) { sendContinueUserSwitchLocked(uss, oldUserId, newUserId); } } mUserSwitchObservers.finishBroadcast(); } void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) { mCurWaitingUserSwitchCallbacks = null; mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG); mHandler.sendMessage(mHandler.obtainMessage(ActivityManagerService.CONTINUE_USER_SWITCH_MSG, oldUserId, newUserId, uss)); } void continueUserSwitch(UserState uss, int oldUserId, int newUserId) { Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId); synchronized (mService) { mService.mWindowManager.stopFreezingScreen(); } uss.switching = false; mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG); mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0)); stopGuestOrEphemeralUserIfBackground(); stopBackgroundUsersIfEnforced(oldUserId); } void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) { boolean homeInFront = mService.mStackSupervisor.switchUserLocked(newUserId, uss); if (homeInFront) { mService.startHomeActivityLocked(newUserId, "moveUserToForeground"); } else { mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); } EventLogTags.writeAmSwitchUser(newUserId); sendUserSwitchBroadcastsLocked(oldUserId, newUserId); } void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) { long ident = Binder.clearCallingIdentity(); try { Intent intent; if (oldUserId >= 0) { // Send USER_BACKGROUND broadcast to all profiles of the outgoing user List<UserInfo> profiles = getUserManager().getProfiles(oldUserId, false); int count = profiles.size(); for (int i = 0; i < count; i++) { int profileUserId = profiles.get(i).id; intent = new Intent(Intent.ACTION_USER_BACKGROUND); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId); mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, profileUserId); } } if (newUserId >= 0) { // Send USER_FOREGROUND broadcast to all profiles of the incoming user List<UserInfo> profiles = getUserManager().getProfiles(newUserId, false); int count = profiles.size(); for (int i = 0; i < count; i++) { int profileUserId = profiles.get(i).id; intent = new Intent(Intent.ACTION_USER_FOREGROUND); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId); mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, profileUserId); } intent = new Intent(Intent.ACTION_USER_SWITCHED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId); mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, new String[] {android.Manifest.permission.MANAGE_USERS}, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL); } } finally { Binder.restoreCallingIdentity(ident); } } int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, int allowMode, String name, String callerPackage) { final int callingUserId = UserHandle.getUserId(callingUid); if (callingUserId == userId) { return userId; } // Note that we may be accessing mCurrentUserId outside of a lock... // shouldn't be a big deal, if this is being called outside // of a locked context there is intrinsically a race with // the value the caller will receive and someone else changing it. // We assume that USER_CURRENT_OR_SELF will use the current user; later // we will switch to the calling user if access to the current user fails. int targetUserId = unsafeConvertIncomingUserLocked(userId); if (callingUid != 0 && callingUid != SYSTEM_UID) { final boolean allow; if (mService.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid, callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { // If the caller has this permission, they always pass go. And collect $200. allow = true; } else if (allowMode == ALLOW_FULL_ONLY) { // We require full access, sucks to be you. allow = false; } else if (mService.checkComponentPermission(INTERACT_ACROSS_USERS, callingPid, callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { // If the caller does not have either permission, they are always doomed. allow = false; } else if (allowMode == ALLOW_NON_FULL) { // We are blanket allowing non-full access, you lucky caller! allow = true; } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) { // We may or may not allow this depending on whether the two users are // in the same profile. allow = isSameProfileGroup(callingUserId, targetUserId); } else { throw new IllegalArgumentException("Unknown mode: " + allowMode); } if (!allow) { if (userId == UserHandle.USER_CURRENT_OR_SELF) { // In this case, they would like to just execute as their // owner user instead of failing. targetUserId = callingUserId; } else { StringBuilder builder = new StringBuilder(128); builder.append("Permission Denial: "); builder.append(name); if (callerPackage != null) { builder.append(" from "); builder.append(callerPackage); } builder.append(" asks to run as user "); builder.append(userId); builder.append(" but is calling from user "); builder.append(UserHandle.getUserId(callingUid)); builder.append("; this requires "); builder.append(INTERACT_ACROSS_USERS_FULL); if (allowMode != ALLOW_FULL_ONLY) { builder.append(" or "); builder.append(INTERACT_ACROSS_USERS); } String msg = builder.toString(); Slog.w(TAG, msg); throw new SecurityException(msg); } } } if (!allowAll && targetUserId < 0) { throw new IllegalArgumentException( "Call does not support special user #" + targetUserId); } // Check shell permission if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) { if (hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId)) { throw new SecurityException("Shell does not have permission to access user " + targetUserId + "\n " + Debug.getCallers(3)); } } return targetUserId; } int unsafeConvertIncomingUserLocked(int userId) { return (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) ? getCurrentUserIdLocked(): userId; } void registerUserSwitchObserver(IUserSwitchObserver observer, String name) { Preconditions.checkNotNull(name, "Observer name cannot be null"); if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { final String msg = "Permission Denial: registerUserSwitchObserver() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + INTERACT_ACROSS_USERS_FULL; Slog.w(TAG, msg); throw new SecurityException(msg); } mUserSwitchObservers.register(observer, name); } void unregisterUserSwitchObserver(IUserSwitchObserver observer) { mUserSwitchObservers.unregister(observer); } UserState getStartedUserStateLocked(int userId) { return mStartedUsers.get(userId); } boolean hasStartedUserState(int userId) { return mStartedUsers.get(userId) != null; } private void updateStartedUserArrayLocked() { int num = 0; for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); // This list does not include stopping users. if (uss.state != UserState.STATE_STOPPING && uss.state != UserState.STATE_SHUTDOWN) { num++; } } mStartedUserArray = new int[num]; num = 0; for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); if (uss.state != UserState.STATE_STOPPING && uss.state != UserState.STATE_SHUTDOWN) { mStartedUserArray[num++] = mStartedUsers.keyAt(i); } } } void sendBootCompletedLocked(IIntentReceiver resultTo) { for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); finishUserBoot(uss, resultTo); } } void onSystemReady() { updateCurrentProfileIdsLocked(); } /** * Refreshes the list of users related to the current user when either a * user switch happens or when a new related user is started in the * background. */ private void updateCurrentProfileIdsLocked() { final List<UserInfo> profiles = getUserManager().getProfiles(mCurrentUserId, false /* enabledOnly */); int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null for (int i = 0; i < currentProfileIds.length; i++) { currentProfileIds[i] = profiles.get(i).id; } mCurrentProfileIds = currentProfileIds; synchronized (mUserProfileGroupIdsSelfLocked) { mUserProfileGroupIdsSelfLocked.clear(); final List<UserInfo> users = getUserManager().getUsers(false); for (int i = 0; i < users.size(); i++) { UserInfo user = users.get(i); if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) { mUserProfileGroupIdsSelfLocked.put(user.id, user.profileGroupId); } } } } int[] getStartedUserArrayLocked() { return mStartedUserArray; } boolean isUserStoppingOrShuttingDownLocked(int userId) { UserState state = getStartedUserStateLocked(userId); if (state == null) { return false; } return state.state == UserState.STATE_STOPPING || state.state == UserState.STATE_SHUTDOWN; } boolean isUserRunningLocked(int userId, int flags) { UserState state = getStartedUserStateLocked(userId); if (state == null) { return false; } if ((flags & ActivityManager.FLAG_OR_STOPPED) != 0) { return true; } if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0) { switch (state.state) { case UserState.STATE_BOOTING: case UserState.STATE_RUNNING_LOCKED: return true; default: return false; } } if ((flags & ActivityManager.FLAG_AND_UNLOCKING_OR_UNLOCKED) != 0) { switch (state.state) { case UserState.STATE_RUNNING_UNLOCKING: case UserState.STATE_RUNNING_UNLOCKED: return true; default: return false; } } if ((flags & ActivityManager.FLAG_AND_UNLOCKED) != 0) { switch (state.state) { case UserState.STATE_RUNNING_UNLOCKED: return true; default: return false; } } // One way or another, we're running! return true; } UserInfo getCurrentUser() { if ((mService.checkCallingPermission(INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) && ( mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED)) { String msg = "Permission Denial: getCurrentUser() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + INTERACT_ACROSS_USERS; Slog.w(TAG, msg); throw new SecurityException(msg); } synchronized (mService) { return getCurrentUserLocked(); } } UserInfo getCurrentUserLocked() { int userId = mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId; return getUserInfo(userId); } int getCurrentOrTargetUserIdLocked() { return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId; } int getCurrentUserIdLocked() { return mCurrentUserId; } private boolean isCurrentUserLocked(int userId) { return userId == getCurrentOrTargetUserIdLocked(); } int setTargetUserIdLocked(int targetUserId) { return mTargetUserId = targetUserId; } int[] getUsers() { UserManagerService ums = getUserManager(); return ums != null ? ums.getUserIds() : new int[] { 0 }; } UserInfo getUserInfo(int userId) { return getUserManager().getUserInfo(userId); } int[] getUserIds() { return getUserManager().getUserIds(); } boolean exists(int userId) { return getUserManager().exists(userId); } boolean hasUserRestriction(String restriction, int userId) { return getUserManager().hasUserRestriction(restriction, userId); } Set<Integer> getProfileIds(int userId) { Set<Integer> userIds = new HashSet<>(); final List<UserInfo> profiles = getUserManager().getProfiles(userId, false /* enabledOnly */); for (UserInfo user : profiles) { userIds.add(user.id); } return userIds; } boolean isSameProfileGroup(int callingUserId, int targetUserId) { if (callingUserId == targetUserId) { return true; } synchronized (mUserProfileGroupIdsSelfLocked) { int callingProfile = mUserProfileGroupIdsSelfLocked.get(callingUserId, UserInfo.NO_PROFILE_GROUP_ID); int targetProfile = mUserProfileGroupIdsSelfLocked.get(targetUserId, UserInfo.NO_PROFILE_GROUP_ID); return callingProfile != UserInfo.NO_PROFILE_GROUP_ID && callingProfile == targetProfile; } } boolean isCurrentProfileLocked(int userId) { return ArrayUtils.contains(mCurrentProfileIds, userId); } int[] getCurrentProfileIdsLocked() { return mCurrentProfileIds; } /** * Returns whether the given user requires credential entry at this time. This is used to * intercept activity launches for work apps when the Work Challenge is present. */ boolean shouldConfirmCredentials(int userId) { synchronized (mService) { if (mStartedUsers.get(userId) == null) { return false; } } if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) { return false; } final KeyguardManager km = (KeyguardManager) mService.mContext .getSystemService(KEYGUARD_SERVICE); return km.isDeviceLocked(userId) && km.isDeviceSecure(userId); } boolean isLockScreenDisabled(@UserIdInt int userId) { return mLockPatternUtils.isLockScreenDisabled(userId); } private UserManagerInternal getUserManagerInternal() { if (mUserManagerInternal == null) { mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); } return mUserManagerInternal; } void dump(PrintWriter pw, boolean dumpAll) { pw.println(" mStartedUsers:"); for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); pw.print(" User #"); pw.print(uss.mHandle.getIdentifier()); pw.print(": "); uss.dump("", pw); } pw.print(" mStartedUserArray: ["); for (int i = 0; i < mStartedUserArray.length; i++) { if (i > 0) pw.print(", "); pw.print(mStartedUserArray[i]); } pw.println("]"); pw.print(" mUserLru: ["); for (int i = 0; i < mUserLru.size(); i++) { if (i > 0) pw.print(", "); pw.print(mUserLru.get(i)); } pw.println("]"); if (dumpAll) { pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray)); } synchronized (mUserProfileGroupIdsSelfLocked) { if (mUserProfileGroupIdsSelfLocked.size() > 0) { pw.println(" mUserProfileGroupIds:"); for (int i=0; i<mUserProfileGroupIdsSelfLocked.size(); i++) { pw.print(" User #"); pw.print(mUserProfileGroupIdsSelfLocked.keyAt(i)); pw.print(" -> profile #"); pw.println(mUserProfileGroupIdsSelfLocked.valueAt(i)); } } } } }