Merge "Add Android Multiuser Atom which will contain number of supported users." into tm-qpr-dev
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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<StatsEvent> data) {
|
||||
if (atomTag != FrameworkStatsLog.USER_INFO) {
|
||||
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.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<UserInfo> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user