diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index e5de3e157c88c..e1d15defad381 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -74,6 +74,7 @@ interface IUserManager { String getUserAccount(int userId); void setUserAccount(int userId, String accountName); long getUserCreationTime(int userId); + boolean isUserSwitcherEnabled(int mUserId); boolean isRestricted(int userId); boolean canHaveRestrictedProfile(int userId); int getUserSerialNumber(int userId); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index b2f7c60fe3b66..5487a12038334 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -5132,23 +5132,13 @@ public class UserManager { }) @UserHandleAware public boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable) { - if (!supportsMultipleUsers()) { - return false; - } - if (hasUserRestrictionForUser(DISALLOW_USER_SWITCH, mUserId)) { - return false; - } - // If Demo Mode is on, don't show user switcher - if (isDeviceInDemoMode(mContext)) { - return false; - } - // Check the Settings.Global.USER_SWITCHER_ENABLED that the user can toggle on/off. - final boolean userSwitcherSettingOn = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.USER_SWITCHER_ENABLED, - Resources.getSystem().getBoolean(R.bool.config_showUserSwitcherByDefault) ? 1 : 0) - != 0; - if (!userSwitcherSettingOn) { - return false; + + try { + if (!mService.isUserSwitcherEnabled(mUserId)) { + return false; + } + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); } // The feature is enabled. But is it worth showing? diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 701ac73c55d18..00fb0651adc4e 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -18,6 +18,7 @@ package com.android.server.pm; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.os.UserManager.DISALLOW_USER_SWITCH; import android.Manifest; import android.accounts.Account; @@ -1759,6 +1760,19 @@ public class UserManagerService extends IUserManager.Stub { } } + @Override + public boolean isUserSwitcherEnabled(@UserIdInt int mUserId) { + boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.USER_SWITCHER_ENABLED, + Resources.getSystem().getBoolean(com.android.internal + .R.bool.config_showUserSwitcherByDefault) ? 1 : 0) != 0; + + return UserManager.supportsMultipleUsers() + && !hasUserRestriction(DISALLOW_USER_SWITCH, mUserId) + && !UserManager.isDeviceInDemoMode(mContext) + && multiUserSettingOn; + } + @Override public boolean isRestricted(@UserIdInt int userId) { if (userId != UserHandle.getCallingUserId()) { @@ -2049,7 +2063,6 @@ public class UserManagerService extends IUserManager.Stub { originatingUserId, local); localChanged = updateLocalRestrictionsForTargetUsersLR(originatingUserId, local, updatedLocalTargetUserIds); - if (isDeviceOwner) { // Remember the global restriction owner userId to be able to make a distinction // in getUserRestrictionSource on who set local policies. @@ -4432,45 +4445,60 @@ public class UserManagerService extends IUserManager.Stub { null, // use default PullAtomMetadata values BackgroundThread.getExecutor(), this::onPullAtom); + statsManager.setPullAtomCallback( + FrameworkStatsLog.MULTI_USER_INFO, + null, // use default PullAtomMetadata values + BackgroundThread.getExecutor(), + this::onPullAtom); } /** Writes a UserInfo pulled atom for each user on the device. */ private int onPullAtom(int atomTag, List data) { - if (atomTag != FrameworkStatsLog.USER_INFO) { + if (atomTag == FrameworkStatsLog.USER_INFO) { + final List users = getUsersInternal(true, true, true); + final int size = users.size(); + if (size > 1) { + for (int idx = 0; idx < size; idx++) { + final UserInfo user = users.get(idx); + final int userTypeStandard = UserManager.getUserTypeForStatsd(user.userType); + final String userTypeCustom = (userTypeStandard == FrameworkStatsLog + .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN) + ? + user.userType : null; + + boolean isUserRunningUnlocked; + synchronized (mUserStates) { + isUserRunningUnlocked = + mUserStates.get(user.id, -1) == UserState.STATE_RUNNING_UNLOCKED; + } + + data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.USER_INFO, + user.id, + userTypeStandard, + userTypeCustom, + user.flags, + user.creationTime, + user.lastLoggedInTime, + isUserRunningUnlocked + )); + } + } + } else if (atomTag == FrameworkStatsLog.MULTI_USER_INFO) { + if (UserManager.getMaxSupportedUsers() > 1) { + int deviceOwnerUserId = UserHandle.USER_NULL; + + synchronized (mRestrictionsLock) { + deviceOwnerUserId = mDeviceOwnerUserId; + } + + data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.MULTI_USER_INFO, + UserManager.getMaxSupportedUsers(), + isUserSwitcherEnabled(deviceOwnerUserId))); + } + } else { Slogf.e(LOG_TAG, "Unexpected atom tag: %d", atomTag); return android.app.StatsManager.PULL_SKIP; } - final List users = getUsersInternal(true, true, true); - final int size = users.size(); - for (int idx = 0; idx < size; idx++) { - final UserInfo user = users.get(idx); - if (user.id == UserHandle.USER_SYSTEM) { - // Skip user 0. It's not interesting. We already know it exists, is running, and (if - // we know the device configuration) its userType. - continue; - } - - final int userTypeStandard = UserManager.getUserTypeForStatsd(user.userType); - final String userTypeCustom = (userTypeStandard == - FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN) ? - user.userType : null; - - boolean isUserRunningUnlocked; - synchronized (mUserStates) { - isUserRunningUnlocked = - mUserStates.get(user.id, -1) == UserState.STATE_RUNNING_UNLOCKED; - } - - data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.USER_INFO, - user.id, - userTypeStandard, - userTypeCustom, - user.flags, - user.creationTime, - user.lastLoggedInTime, - isUserRunningUnlocked - )); - } return android.app.StatsManager.PULL_SUCCESS; } diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java index 34b40c716b4fb..b1ad8ec1cb66d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -16,53 +16,79 @@ package com.android.server.pm; +import static android.os.UserManager.DISALLOW_USER_SWITCH; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.ActivityManager; +import android.app.PropertyInvalidatedCache; +import android.content.Context; import android.content.pm.UserInfo; import android.os.Bundle; import android.os.FileUtils; +import android.os.Looper; import android.os.Parcelable; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Postsubmit; import android.support.test.uiautomator.UiDevice; -import android.test.AndroidTestCase; -import android.text.TextUtils; import android.util.AtomicFile; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.LocalServices; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; import java.io.IOException; import java.util.Arrays; +/** Test {@link UserManagerService} functionality. */ @Postsubmit -@SmallTest -public class UserManagerServiceTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class UserManagerServiceTest { private static String[] STRING_ARRAY = new String[] {"