Loading core/java/android/os/PersistableBundle.java +37 −0 Original line number Diff line number Diff line Loading @@ -294,6 +294,43 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa XmlUtils.writeMapXml(mMap, out, this); } /** * Checks whether all keys and values are within the given character limit. * Note: Maximum character limit of String that can be saved to XML as part of bundle is 65535. * Otherwise IOException is thrown. * @param limit length of String keys and values in the PersistableBundle, including nested * PersistableBundles to check against. * * @hide */ public boolean isBundleContentsWithinLengthLimit(int limit) { unparcel(); if (mMap == null) { return true; } for (int i = 0; i < mMap.size(); i++) { if (mMap.keyAt(i) != null && mMap.keyAt(i).length() > limit) { return false; } final Object value = mMap.valueAt(i); if (value instanceof String && ((String) value).length() > limit) { return false; } else if (value instanceof String[]) { String[] stringArray = (String[]) value; for (int j = 0; j < stringArray.length; j++) { if (stringArray[j] != null && stringArray[j].length() > limit) { return false; } } } else if (value instanceof PersistableBundle && !((PersistableBundle) value).isBundleContentsWithinLengthLimit(limit)) { return false; } } return true; } /** @hide */ static class MyReadMapCallback implements XmlUtils.ReadMapCallback { @Override Loading core/java/android/os/UserManager.java +19 −4 Original line number Diff line number Diff line Loading @@ -100,6 +100,21 @@ public class UserManager { /** The userType of UserHandle.myUserId(); empty string if not a profile; null until cached. */ private String mProfileTypeOfProcessUser = null; /** Maximum length of username. * @hide */ public static final int MAX_USER_NAME_LENGTH = 100; /** Maximum length of user property String value. * @hide */ public static final int MAX_ACCOUNT_STRING_LENGTH = 500; /** Maximum length of account options String values. * @hide */ public static final int MAX_ACCOUNT_OPTIONS_LENGTH = 1000; /** * User type representing a {@link UserHandle#USER_SYSTEM system} user that is a human user. * This type of user cannot be created; it can only pre-exist on first boot. Loading Loading @@ -3630,15 +3645,15 @@ public class UserManager { * time, the preferred user name and account information are used by the setup process for that * user. * * @param userName Optional name to assign to the user. * @param userName Optional name to assign to the user. Character limit is 100. * @param accountName Optional account name that will be used by the setup wizard to initialize * the user. * the user. Character limit is 500. * @param accountType Optional account type for the account to be created. This is required * if the account name is specified. * if the account name is specified. Character limit is 500. * @param accountOptions Optional bundle of data to be passed in during account creation in the * new user via {@link AccountManager#addAccount(String, String, String[], * Bundle, android.app.Activity, android.accounts.AccountManagerCallback, * Handler)}. * Handler)}. Character limit is 1000. * @return An Intent that can be launched from an Activity. * @see #USER_CREATION_FAILED_NOT_PERMITTED * @see #USER_CREATION_FAILED_NO_MORE_USERS Loading core/java/com/android/internal/app/ConfirmUserCreationActivity.java +12 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,14 @@ public class ConfirmUserCreationActivity extends AlertActivity if (cantCreateUser) { setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED); return null; } else if (!(isUserPropertyWithinLimit(mUserName, UserManager.MAX_USER_NAME_LENGTH) && isUserPropertyWithinLimit(mAccountName, UserManager.MAX_ACCOUNT_STRING_LENGTH) && isUserPropertyWithinLimit(mAccountType, UserManager.MAX_ACCOUNT_STRING_LENGTH)) || (mAccountOptions != null && !mAccountOptions.isBundleContentsWithinLengthLimit( UserManager.MAX_ACCOUNT_OPTIONS_LENGTH))) { setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED); Log.i(TAG, "User properties must not exceed their character limits"); return null; } else if (cantCreateAnyMoreUsers) { setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS); return null; Loading Loading @@ -141,4 +149,8 @@ public class ConfirmUserCreationActivity extends AlertActivity } finish(); } private boolean isUserPropertyWithinLimit(String property, int limit) { return property == null || property.length() <= limit; } } core/java/com/android/internal/widget/LockPatternUtils.java +2 −2 Original line number Diff line number Diff line Loading @@ -1367,8 +1367,8 @@ public class LockPatternUtils { } public boolean isUserInLockdown(int userId) { return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; return (getStrongAuthForUser(userId) & StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0; } private static class WrappedCallback extends ICheckCredentialProgressCallback.Stub { Loading core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java +34 −5 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -70,12 +72,15 @@ import java.util.List; @SmallTest public class LockPatternUtilsTest { private ILockSettings mLockSettings; private static final int USER_ID = 1; private static final int DEMO_USER_ID = 5; private LockPatternUtils mLockPatternUtils; private void configureTest(boolean isSecure, boolean isDemoUser, int deviceDemoMode) throws Exception { mLockSettings = Mockito.mock(ILockSettings.class); final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); final MockContentResolver cr = new MockContentResolver(context); Loading @@ -83,15 +88,14 @@ public class LockPatternUtilsTest { when(context.getContentResolver()).thenReturn(cr); Settings.Global.putInt(cr, Settings.Global.DEVICE_DEMO_MODE, deviceDemoMode); final ILockSettings ils = Mockito.mock(ILockSettings.class); when(ils.getCredentialType(DEMO_USER_ID)).thenReturn( when(mLockSettings.getCredentialType(DEMO_USER_ID)).thenReturn( isSecure ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD : LockPatternUtils.CREDENTIAL_TYPE_NONE); when(ils.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED, DEMO_USER_ID)) .thenReturn((long) PASSWORD_QUALITY_MANAGED); when(mLockSettings.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED, DEMO_USER_ID)).thenReturn((long) PASSWORD_QUALITY_MANAGED); // TODO(b/63758238): stop spying the class under test mLockPatternUtils = spy(new LockPatternUtils(context)); when(mLockPatternUtils.getLockSettings()).thenReturn(ils); when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings); doReturn(true).when(mLockPatternUtils).hasSecureLockScreen(); final UserInfo userInfo = Mockito.mock(UserInfo.class); Loading @@ -101,6 +105,31 @@ public class LockPatternUtilsTest { when(context.getSystemService(Context.USER_SERVICE)).thenReturn(um); } @Test public void isUserInLockDown() throws Exception { configureTest(true, false, 2); // GIVEN strong auth not required when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(STRONG_AUTH_NOT_REQUIRED); // THEN user isn't in lockdown assertFalse(mLockPatternUtils.isUserInLockdown(USER_ID)); // GIVEN lockdown when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); // THEN user is in lockdown assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID)); // GIVEN lockdown and lockout when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN | STRONG_AUTH_REQUIRED_AFTER_LOCKOUT); // THEN user is in lockdown assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID)); } @Test public void isLockScreenDisabled_isDemoUser_true() throws Exception { configureTest(false, true, 2); Loading Loading
core/java/android/os/PersistableBundle.java +37 −0 Original line number Diff line number Diff line Loading @@ -294,6 +294,43 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa XmlUtils.writeMapXml(mMap, out, this); } /** * Checks whether all keys and values are within the given character limit. * Note: Maximum character limit of String that can be saved to XML as part of bundle is 65535. * Otherwise IOException is thrown. * @param limit length of String keys and values in the PersistableBundle, including nested * PersistableBundles to check against. * * @hide */ public boolean isBundleContentsWithinLengthLimit(int limit) { unparcel(); if (mMap == null) { return true; } for (int i = 0; i < mMap.size(); i++) { if (mMap.keyAt(i) != null && mMap.keyAt(i).length() > limit) { return false; } final Object value = mMap.valueAt(i); if (value instanceof String && ((String) value).length() > limit) { return false; } else if (value instanceof String[]) { String[] stringArray = (String[]) value; for (int j = 0; j < stringArray.length; j++) { if (stringArray[j] != null && stringArray[j].length() > limit) { return false; } } } else if (value instanceof PersistableBundle && !((PersistableBundle) value).isBundleContentsWithinLengthLimit(limit)) { return false; } } return true; } /** @hide */ static class MyReadMapCallback implements XmlUtils.ReadMapCallback { @Override Loading
core/java/android/os/UserManager.java +19 −4 Original line number Diff line number Diff line Loading @@ -100,6 +100,21 @@ public class UserManager { /** The userType of UserHandle.myUserId(); empty string if not a profile; null until cached. */ private String mProfileTypeOfProcessUser = null; /** Maximum length of username. * @hide */ public static final int MAX_USER_NAME_LENGTH = 100; /** Maximum length of user property String value. * @hide */ public static final int MAX_ACCOUNT_STRING_LENGTH = 500; /** Maximum length of account options String values. * @hide */ public static final int MAX_ACCOUNT_OPTIONS_LENGTH = 1000; /** * User type representing a {@link UserHandle#USER_SYSTEM system} user that is a human user. * This type of user cannot be created; it can only pre-exist on first boot. Loading Loading @@ -3630,15 +3645,15 @@ public class UserManager { * time, the preferred user name and account information are used by the setup process for that * user. * * @param userName Optional name to assign to the user. * @param userName Optional name to assign to the user. Character limit is 100. * @param accountName Optional account name that will be used by the setup wizard to initialize * the user. * the user. Character limit is 500. * @param accountType Optional account type for the account to be created. This is required * if the account name is specified. * if the account name is specified. Character limit is 500. * @param accountOptions Optional bundle of data to be passed in during account creation in the * new user via {@link AccountManager#addAccount(String, String, String[], * Bundle, android.app.Activity, android.accounts.AccountManagerCallback, * Handler)}. * Handler)}. Character limit is 1000. * @return An Intent that can be launched from an Activity. * @see #USER_CREATION_FAILED_NOT_PERMITTED * @see #USER_CREATION_FAILED_NO_MORE_USERS Loading
core/java/com/android/internal/app/ConfirmUserCreationActivity.java +12 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,14 @@ public class ConfirmUserCreationActivity extends AlertActivity if (cantCreateUser) { setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED); return null; } else if (!(isUserPropertyWithinLimit(mUserName, UserManager.MAX_USER_NAME_LENGTH) && isUserPropertyWithinLimit(mAccountName, UserManager.MAX_ACCOUNT_STRING_LENGTH) && isUserPropertyWithinLimit(mAccountType, UserManager.MAX_ACCOUNT_STRING_LENGTH)) || (mAccountOptions != null && !mAccountOptions.isBundleContentsWithinLengthLimit( UserManager.MAX_ACCOUNT_OPTIONS_LENGTH))) { setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED); Log.i(TAG, "User properties must not exceed their character limits"); return null; } else if (cantCreateAnyMoreUsers) { setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS); return null; Loading Loading @@ -141,4 +149,8 @@ public class ConfirmUserCreationActivity extends AlertActivity } finish(); } private boolean isUserPropertyWithinLimit(String property, int limit) { return property == null || property.length() <= limit; } }
core/java/com/android/internal/widget/LockPatternUtils.java +2 −2 Original line number Diff line number Diff line Loading @@ -1367,8 +1367,8 @@ public class LockPatternUtils { } public boolean isUserInLockdown(int userId) { return getStrongAuthForUser(userId) == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; return (getStrongAuthForUser(userId) & StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0; } private static class WrappedCallback extends ICheckCredentialProgressCallback.Stub { Loading
core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java +34 −5 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -70,12 +72,15 @@ import java.util.List; @SmallTest public class LockPatternUtilsTest { private ILockSettings mLockSettings; private static final int USER_ID = 1; private static final int DEMO_USER_ID = 5; private LockPatternUtils mLockPatternUtils; private void configureTest(boolean isSecure, boolean isDemoUser, int deviceDemoMode) throws Exception { mLockSettings = Mockito.mock(ILockSettings.class); final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); final MockContentResolver cr = new MockContentResolver(context); Loading @@ -83,15 +88,14 @@ public class LockPatternUtilsTest { when(context.getContentResolver()).thenReturn(cr); Settings.Global.putInt(cr, Settings.Global.DEVICE_DEMO_MODE, deviceDemoMode); final ILockSettings ils = Mockito.mock(ILockSettings.class); when(ils.getCredentialType(DEMO_USER_ID)).thenReturn( when(mLockSettings.getCredentialType(DEMO_USER_ID)).thenReturn( isSecure ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD : LockPatternUtils.CREDENTIAL_TYPE_NONE); when(ils.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED, DEMO_USER_ID)) .thenReturn((long) PASSWORD_QUALITY_MANAGED); when(mLockSettings.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED, DEMO_USER_ID)).thenReturn((long) PASSWORD_QUALITY_MANAGED); // TODO(b/63758238): stop spying the class under test mLockPatternUtils = spy(new LockPatternUtils(context)); when(mLockPatternUtils.getLockSettings()).thenReturn(ils); when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings); doReturn(true).when(mLockPatternUtils).hasSecureLockScreen(); final UserInfo userInfo = Mockito.mock(UserInfo.class); Loading @@ -101,6 +105,31 @@ public class LockPatternUtilsTest { when(context.getSystemService(Context.USER_SERVICE)).thenReturn(um); } @Test public void isUserInLockDown() throws Exception { configureTest(true, false, 2); // GIVEN strong auth not required when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn(STRONG_AUTH_NOT_REQUIRED); // THEN user isn't in lockdown assertFalse(mLockPatternUtils.isUserInLockdown(USER_ID)); // GIVEN lockdown when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); // THEN user is in lockdown assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID)); // GIVEN lockdown and lockout when(mLockSettings.getStrongAuthForUser(USER_ID)).thenReturn( STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN | STRONG_AUTH_REQUIRED_AFTER_LOCKOUT); // THEN user is in lockdown assertTrue(mLockPatternUtils.isUserInLockdown(USER_ID)); } @Test public void isLockScreenDisabled_isDemoUser_true() throws Exception { configureTest(false, true, 2); Loading