diff options
4 files changed, 238 insertions, 75 deletions
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 62ee408cffbf..fa6b1189f1da 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 ef04f641b0ee..ca0af2cf07af 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 025e97318ba9..87ab87df0b0c 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; @@ -1885,6 +1886,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()) { checkCreateUsersPermission("query isRestricted for user " + userId); @@ -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<StatsEvent> data) { - if (atomTag != FrameworkStatsLog.USER_INFO) { - Slogf.e(LOG_TAG, "Unexpected atom tag: %d", atomTag); - return android.app.StatsManager.PULL_SKIP; - } - final List<UserInfo> 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; + if (atomTag == FrameworkStatsLog.USER_INFO) { + final List<UserInfo> 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.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 34b40c716b4f..b1ad8ec1cb66 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[] {"<tag", "<![CDATA["}; private File restrictionsFile; private int tempUserId = UserHandle.USER_NULL; + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + private UserManagerService mUserManagerService; + + @Before + public void setup() throws Exception { + // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup + // TODO: Remove once UMS supports proper dependency injection + if (Looper.myLooper() == null) { + Looper.prepare(); + } + // Disable binder caches in this process. + PropertyInvalidatedCache.disableForTestMode(); + + LocalServices.removeServiceForTest(UserManagerInternal.class); + mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext()); - @Override - protected void setUp() throws Exception { - super.setUp(); restrictionsFile = new File(mContext.getCacheDir(), "restrictions.xml"); restrictionsFile.delete(); } - @Override - protected void tearDown() throws Exception { + @After + public void teardown() throws Exception { restrictionsFile.delete(); if (tempUserId != UserHandle.USER_NULL) { UserManager.get(mContext).removeUser(tempUserId); } - super.tearDown(); } + @Test public void testWriteReadApplicationRestrictions() throws IOException { AtomicFile atomicFile = new AtomicFile(restrictionsFile); Bundle bundle = createBundle(); UserManagerService.writeApplicationRestrictionsLAr(bundle, atomicFile); - assertTrue(atomicFile.getBaseFile().exists()); + assertThat(atomicFile.getBaseFile().exists()).isTrue(); String s = FileUtils.readTextFile(restrictionsFile, 10000, ""); System.out.println("restrictionsFile: " + s); bundle = UserManagerService.readApplicationRestrictionsLAr(atomicFile); @@ -70,22 +96,22 @@ public class UserManagerServiceTest extends AndroidTestCase { assertBundle(bundle); } + @Test public void testAddUserWithAccount() { UserManager um = UserManager.get(mContext); UserInfo user = um.createUser("Test User", 0); - assertNotNull(user); + assertThat(user).isNotNull(); tempUserId = user.id; String accountName = "Test Account"; um.setUserAccount(tempUserId, accountName); - assertEquals(accountName, um.getUserAccount(tempUserId)); + assertThat(um.getUserAccount(tempUserId)).isEqualTo(accountName); } + @Test public void testUserSystemPackageWhitelist() throws Exception { String cmd = "cmd user report-system-user-package-whitelist-problems --critical-only"; final String result = runShellCommand(cmd); - if (!TextUtils.isEmpty(result)) { - fail("Command '" + cmd + " reported errors:\n" + result); - } + assertThat(result).isEmpty(); } private Bundle createBundle() { @@ -114,26 +140,141 @@ public class UserManagerServiceTest extends AndroidTestCase { } private void assertBundle(Bundle bundle) { - assertFalse(bundle.getBoolean("boolean_0")); - assertTrue(bundle.getBoolean("boolean_1")); - assertEquals(100, bundle.getInt("integer")); - assertEquals("", bundle.getString("empty")); - assertEquals("text", bundle.getString("string")); - assertEquals(Arrays.asList(STRING_ARRAY), Arrays.asList(bundle.getStringArray("string[]"))); + assertThat(bundle.getBoolean("boolean_0")).isFalse(); + assertThat(bundle.getBoolean("boolean_1")).isTrue(); + assertThat(bundle.getInt("integer")).isEqualTo(100); + assertThat(bundle.getString("empty")).isEqualTo(""); + assertThat(bundle.getString("string")).isEqualTo("text"); + assertThat(Arrays.asList(bundle.getStringArray("string[]"))) + .isEqualTo(Arrays.asList(STRING_ARRAY)); Parcelable[] bundle_array = bundle.getParcelableArray("bundle_array"); - assertEquals(2, bundle_array.length); + assertThat(bundle_array.length).isEqualTo(2); Bundle bundle1 = (Bundle) bundle_array[0]; - assertEquals("bundle_array_string", bundle1.getString("bundle_array_string")); - assertNotNull(bundle1.getBundle("bundle_array_bundle")); + assertThat(bundle1.getString("bundle_array_string")) + .isEqualTo("bundle_array_string"); + assertThat(bundle1.getBundle("bundle_array_bundle")).isNotNull(); Bundle bundle2 = (Bundle) bundle_array[1]; - assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2")); + assertThat(bundle2.getString("bundle_array_string2")) + .isEqualTo("bundle_array_string2"); Bundle childBundle = bundle.getBundle("bundle"); - assertEquals("bundle_string", childBundle.getString("bundle_string")); - assertEquals(1, childBundle.getInt("bundle_int")); + assertThat(childBundle.getString("bundle_string")) + .isEqualTo("bundle_string"); + assertThat(childBundle.getInt("bundle_int")).isEqualTo(1); + } + + @Test + public void assertHasUserRestriction() throws Exception { + int userId = ActivityManager.getCurrentUser(); + + mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, true, userId); + assertThat(mUserManagerService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)).isTrue(); + + mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId); + assertThat(mUserManagerService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)).isFalse(); + } + + @Test + public void assertIsUserSwitcherEnabledOnMultiUserSettings() throws Exception { + int userId = ActivityManager.getCurrentUser(); + resetUserSwitcherEnabled(); + + setUserSwitch(false); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse(); + + setUserSwitch(true); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue(); + } + + @Test + public void assertIsUserSwitcherEnabledOnMaxSupportedUsers() throws Exception { + int userId = ActivityManager.getCurrentUser(); + setMaxSupportedUsers(1); + + assertThat(UserManager.supportsMultipleUsers()).isFalse(); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse(); + + setMaxSupportedUsers(8); + + assertThat(UserManager.supportsMultipleUsers()).isTrue(); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue(); + } + + + @Test + public void assertIsUserSwitcherEnabledOnShowMultiuserUI() throws Exception { + int userId = ActivityManager.getCurrentUser(); + setShowMultiuserUI(false); + + assertThat(UserManager.supportsMultipleUsers()).isFalse(); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse(); + + setShowMultiuserUI(true); + + assertThat(UserManager.supportsMultipleUsers()).isTrue(); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue(); + } + + @Test + public void assertIsUserSwitcherEnabledOnUserRestrictions() throws Exception { + int userId = ActivityManager.getCurrentUser(); + resetUserSwitcherEnabled(); + + mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, true, userId); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse(); + + mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue(); + } + + @Test + public void assertIsUserSwitcherEnabledOnDemoMode() throws Exception { + int userId = ActivityManager.getCurrentUser(); + resetUserSwitcherEnabled(); + + setDeviceDemoMode(true); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse(); + + setDeviceDemoMode(false); + assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue(); + } + + private void resetUserSwitcherEnabled() throws Exception { + int userId = ActivityManager.getCurrentUser(); + setUserSwitch(true); + setShowMultiuserUI(true); + setDeviceDemoMode(false); + setMaxSupportedUsers(8); + mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId); + } + + private void setUserSwitch(boolean enabled) { + android.provider.Settings.Global.putInt(mContext.getContentResolver(), + android.provider.Settings.Global.USER_SWITCHER_ENABLED, enabled ? 1 : 0); } + private void setDeviceDemoMode(boolean enabled) { + android.provider.Settings.Global.putInt(mContext.getContentResolver(), + android.provider.Settings.Global.DEVICE_DEMO_MODE, enabled ? 1 : 0); + } + + private static String runShellCommand(String cmd) throws Exception { return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) .executeShellCommand(cmd); } + + private static String setSystemProperty(String name, String value) throws Exception { + final String oldValue = runShellCommand("getprop " + name); + assertThat(runShellCommand("setprop " + name + " " + value)) + .isEqualTo(""); + return oldValue; + } + + private static void setMaxSupportedUsers(int max) throws Exception { + setSystemProperty("fw.max_users", String.valueOf(max)); + } + + public static void setShowMultiuserUI(boolean show) throws Exception { + setSystemProperty("fw.show_multiuserui", String.valueOf(show)); + } } |