diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 62ee408cffbfc..fa6b1189f1da4 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -76,6 +76,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 ef04f641b0eee..ca0af2cf07afc 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -5246,23 +5246,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 025e97318ba90..87ab87df0b0c1 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; @@ -1884,6 +1885,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()) { @@ -2277,7 +2291,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. @@ -4804,41 +4817,59 @@ 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) { - 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(); - 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; + 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; + 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.USER_INFO, - user.id, - userTypeStandard, - userTypeCustom, - user.flags, - user.creationTime, - user.lastLoggedInTime, - isUserRunningUnlocked - )); + 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; } 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[] {"