Loading core/java/android/app/admin/DevicePolicyManager.java +16 −1 Original line number Diff line number Diff line Loading @@ -1981,7 +1981,8 @@ public class DevicePolicyManager { * Determine whether the current password the user has set is sufficient to meet the policy * requirements (e.g. quality, minimum length) that have been requested by the admins of this * user and its participating profiles. Restrictions on profiles that have a separate challenge * are not taken into account. * are not taken into account. If the user has a password, it must have been entered in order to * perform this check. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has Loading @@ -1994,6 +1995,7 @@ public class DevicePolicyManager { * @return Returns true if the password meets the current requirements, else false. * @throws SecurityException if the calling application does not own an active administrator * that uses {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} * @throws IllegalStateException if the user has a password but has not entered it yet. */ public boolean isActivePasswordSufficient() { if (mService != null) { Loading Loading @@ -3425,6 +3427,19 @@ public class DevicePolicyManager { } } /** * @hide */ public void reportPasswordChanged(int userId) { if (mService != null) { try { mService.reportPasswordChanged(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * @hide */ Loading core/java/android/app/admin/IDevicePolicyManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ interface IDevicePolicyManager { void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase, int numbers, int symbols, int nonletter, int userHandle); void reportPasswordChanged(int userId); void reportFailedPasswordAttempt(int userHandle); void reportSuccessfulPasswordAttempt(int userHandle); void reportFailedFingerprintAttempt(int userHandle); Loading core/java/com/android/internal/widget/LockPatternUtils.java +3 −42 Original line number Diff line number Diff line Loading @@ -565,9 +565,6 @@ public class LockPatternUtils { setCredentialRequiredToDecrypt(false); } getDevicePolicyManager().setActivePasswordState( DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle); onAfterChangingPassword(userHandle); } Loading Loading @@ -614,6 +611,7 @@ public class LockPatternUtils { + MIN_LOCK_PATTERN_SIZE + " dots long."); } setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId); DevicePolicyManager dpm = getDevicePolicyManager(); Loading @@ -630,9 +628,6 @@ public class LockPatternUtils { setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId); setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern.size(), 0, 0, 0, 0, 0, 0, userId); onAfterChangingPassword(userId); } catch (RemoteException re) { Log.e(TAG, "Couldn't save lock pattern " + re); Loading Loading @@ -835,9 +830,9 @@ public class LockPatternUtils { + "of length " + MIN_LOCK_PASSWORD_SIZE); } final int computedQuality = computePasswordQuality(password); setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); getLockSettings().setLockPassword(password, savedPassword, userHandle); getLockSettings().setSeparateProfileChallengeEnabled(userHandle, true, null); int computedQuality = computePasswordQuality(password); // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM Loading @@ -855,40 +850,6 @@ public class LockPatternUtils { } } setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { int letters = 0; int uppercase = 0; int lowercase = 0; int numbers = 0; int symbols = 0; int nonletter = 0; for (int i = 0; i < password.length(); i++) { char c = password.charAt(i); if (c >= 'A' && c <= 'Z') { letters++; uppercase++; } else if (c >= 'a' && c <= 'z') { letters++; lowercase++; } else if (c >= '0' && c <= '9') { numbers++; nonletter++; } else { symbols++; nonletter++; } } dpm.setActivePasswordState(Math.max(quality, computedQuality), password.length(), letters, uppercase, lowercase, numbers, symbols, nonletter, userHandle); } else { // The password is not anything. dpm.setActivePasswordState( DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle); } // Add the password to the password history. We assume all // password hashes have the same length for simplicity of implementation. String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); Loading services/core/java/com/android/server/LockSettingsService.java +60 −0 Original line number Diff line number Diff line Loading @@ -899,6 +899,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPatternInternal(pattern, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); notifyPasswordChanged(userId); } } Loading @@ -913,6 +914,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); notifyActivePasswordMetricsAvailable(null, userId); return; } Loading Loading @@ -962,6 +964,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPasswordInternal(password, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); notifyPasswordChanged(userId); } } Loading @@ -975,6 +978,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); notifyActivePasswordMetricsAvailable(null, userId); return; } Loading Loading @@ -1365,6 +1369,7 @@ public class LockSettingsService extends ILockSettings.Stub { // migrate credential to GateKeeper credentialUtil.setCredential(credential, null, userId); if (!hasChallenge) { notifyActivePasswordMetricsAvailable(credential, userId); return VerifyCredentialResponse.OK; } // Fall through to get the auth token. Technically this should never happen, Loading Loading @@ -1398,6 +1403,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { // credential has matched notifyActivePasswordMetricsAvailable(credential, userId); unlockKeystore(credential, userId); Slog.i(TAG, "Unlocking user " + userId + Loading @@ -1421,6 +1427,60 @@ public class LockSettingsService extends ILockSettings.Stub { return response; } private void notifyActivePasswordMetricsAvailable(final String password, int userId) { final int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId); // Asynchronous to avoid dead lock mHandler.post(new Runnable() { @Override public void run() { int length = 0; int letters = 0; int uppercase = 0; int lowercase = 0; int numbers = 0; int symbols = 0; int nonletter = 0; if (password != null) { length = password.length(); for (int i = 0; i < length; i++) { char c = password.charAt(i); if (c >= 'A' && c <= 'Z') { letters++; uppercase++; } else if (c >= 'a' && c <= 'z') { letters++; lowercase++; } else if (c >= '0' && c <= '9') { numbers++; nonletter++; } else { symbols++; nonletter++; } } } DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); dpm.setActivePasswordState(quality, length, letters, uppercase, lowercase, numbers, symbols, nonletter, userId); } }); } /** * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before * reporting the password changed. */ private void notifyPasswordChanged(int userId) { // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering mHandler.post(() -> { DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); dpm.reportPasswordChanged(userId); }); } @Override public boolean checkVoldPassword(int userId) throws RemoteException { if (!mFirstCallToVold) { Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +86 −61 Original line number Diff line number Diff line Loading @@ -2218,10 +2218,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, "failed-password-attempts"); } if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 // Don't save metrics for FBE devices if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) { || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0)) { out.startTag(null, "active-password"); out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality)); out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength)); Loading Loading @@ -2314,6 +2317,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { JournaledFile journal = makeJournaledFile(userHandle); FileInputStream stream = null; File file = journal.chooseForRead(); boolean needsRewrite = false; try { stream = new FileInputStream(file); XmlPullParser parser = Xml.newPullParser(); Loading Loading @@ -2390,7 +2394,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("password-owner".equals(tag)) { policy.mPasswordOwner = Integer.parseInt( parser.getAttributeValue(null, "value")); } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); } else if (TAG_STATUS_BAR.equals(tag)) { policy.mStatusBarDisabled = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_DISABLED)); } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) { policy.doNotAskCredentialsOnBoot = true; } else if (TAG_AFFILIATION_ID.equals(tag)) { policy.mAffiliationIds.add(parser.getAttributeValue(null, "id")); } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { String pending = parser.getAttributeValue(null, ATTR_VALUE); policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { policy.mInitBundle = PersistableBundle.restoreFromXml(parser); } else if ("active-password".equals(tag)) { if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) { // Remove this from FBE devices needsRewrite = true; } else { policy.mActivePasswordQuality = Integer.parseInt( parser.getAttributeValue(null, "quality")); policy.mActivePasswordLength = Integer.parseInt( Loading @@ -2407,22 +2431,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { parser.getAttributeValue(null, "symbols")); policy.mActivePasswordNonLetter = Integer.parseInt( parser.getAttributeValue(null, "nonletter")); } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); } else if (TAG_STATUS_BAR.equals(tag)) { policy.mStatusBarDisabled = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_DISABLED)); } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) { policy.doNotAskCredentialsOnBoot = true; } else if (TAG_AFFILIATION_ID.equals(tag)) { policy.mAffiliationIds.add(parser.getAttributeValue(null, "id")); } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { String pending = parser.getAttributeValue(null, ATTR_VALUE); policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { policy.mInitBundle = PersistableBundle.restoreFromXml(parser); } } else { Slog.w(LOG_TAG, "Unknown tag: " + tag); XmlUtils.skipCurrentTag(parser); Loading @@ -2442,34 +2451,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Ignore } // Might need to upgrade the file by rewriting it if (needsRewrite) { saveSettingsLocked(userHandle); } // Generate a list of admins from the admin map policy.mAdminList.addAll(policy.mAdminMap.values()); // Validate that what we stored for the password quality matches // sufficiently what is currently set. Note that this is only // a sanity check in case the two get out of sync; this should // never normally happen. final long identity = mInjector.binderClearCallingIdentity(); try { int actualPasswordQuality = mLockPatternUtils.getActivePasswordQuality(userHandle); if (actualPasswordQuality < policy.mActivePasswordQuality) { Slog.w(LOG_TAG, "Active password quality 0x" + Integer.toHexString(policy.mActivePasswordQuality) + " does not match actual quality 0x" + Integer.toHexString(actualPasswordQuality)); policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; policy.mActivePasswordLength = 0; policy.mActivePasswordUpperCase = 0; policy.mActivePasswordLowerCase = 0; policy.mActivePasswordLetters = 0; policy.mActivePasswordNumeric = 0; policy.mActivePasswordSymbols = 0; policy.mActivePasswordNonLetter = 0; } } finally { mInjector.binderRestoreCallingIdentity(identity); } validatePasswordOwnerLocked(policy); updateMaximumTimeToLockLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); Loading Loading @@ -3663,6 +3652,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean isActivePasswordSufficientForUserLocked( DevicePolicyData policy, int userHandle, boolean parent) { enforceUserUnlocked(userHandle, parent); if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent) || policy.mActivePasswordLength < getPasswordMinimumLength( null, userHandle, parent)) { Loading Loading @@ -4673,20 +4664,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceFullCrossUsersPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); // Managed Profile password can only be changed when it has a separate challenge. if (!isSeparateProfileChallengeEnabled(userHandle)) { enforceNotManagedProfile(userHandle, "set the active password"); // If the managed profile doesn't have a separate password, set the metrics to default if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) { quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; length = 0; letters = 0; uppercase = 0; lowercase = 0; numbers = 0; symbols = 0; nonletter = 0; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); validateQualityConstant(quality); DevicePolicyData policy = getUserData(userHandle); long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { policy.mActivePasswordQuality = quality; policy.mActivePasswordLength = length; Loading @@ -4696,17 +4690,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mActivePasswordNumeric = numbers; policy.mActivePasswordSymbols = symbols; policy.mActivePasswordNonLetter = nonletter; } } @Override public void reportPasswordChanged(int userId) { if (!mHasFeature) { return; } enforceFullCrossUsersPermission(userId); // Managed Profile password can only be changed when it has a separate challenge. if (!isSeparateProfileChallengeEnabled(userId)) { enforceNotManagedProfile(userId, "set the active password"); } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); DevicePolicyData policy = getUserData(userId); long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { policy.mFailedPasswordAttempts = 0; saveSettingsLocked(userHandle); updatePasswordExpirationsLocked(userHandle); setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false); saveSettingsLocked(userId); updatePasswordExpirationsLocked(userId); setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false); // Send a broadcast to each profile using this password as its primary unlock. sendAdminCommandForLockscreenPoliciesLocked( DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userId); } removeCaApprovalsIfNeeded(userHandle); removeCaApprovalsIfNeeded(userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } Loading Loading @@ -6278,6 +6295,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "User must be running and unlocked"); } private void enforceUserUnlocked(int userId, boolean parent) { if (parent) { enforceUserUnlocked(getProfileParentId(userId)); } else { enforceUserUnlocked(userId); } } private void enforceManageUsers() { final int callingUid = mInjector.binderGetCallingUid(); if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) { Loading Loading
core/java/android/app/admin/DevicePolicyManager.java +16 −1 Original line number Diff line number Diff line Loading @@ -1981,7 +1981,8 @@ public class DevicePolicyManager { * Determine whether the current password the user has set is sufficient to meet the policy * requirements (e.g. quality, minimum length) that have been requested by the admins of this * user and its participating profiles. Restrictions on profiles that have a separate challenge * are not taken into account. * are not taken into account. If the user has a password, it must have been entered in order to * perform this check. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has Loading @@ -1994,6 +1995,7 @@ public class DevicePolicyManager { * @return Returns true if the password meets the current requirements, else false. * @throws SecurityException if the calling application does not own an active administrator * that uses {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} * @throws IllegalStateException if the user has a password but has not entered it yet. */ public boolean isActivePasswordSufficient() { if (mService != null) { Loading Loading @@ -3425,6 +3427,19 @@ public class DevicePolicyManager { } } /** * @hide */ public void reportPasswordChanged(int userId) { if (mService != null) { try { mService.reportPasswordChanged(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * @hide */ Loading
core/java/android/app/admin/IDevicePolicyManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ interface IDevicePolicyManager { void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase, int numbers, int symbols, int nonletter, int userHandle); void reportPasswordChanged(int userId); void reportFailedPasswordAttempt(int userHandle); void reportSuccessfulPasswordAttempt(int userHandle); void reportFailedFingerprintAttempt(int userHandle); Loading
core/java/com/android/internal/widget/LockPatternUtils.java +3 −42 Original line number Diff line number Diff line Loading @@ -565,9 +565,6 @@ public class LockPatternUtils { setCredentialRequiredToDecrypt(false); } getDevicePolicyManager().setActivePasswordState( DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle); onAfterChangingPassword(userHandle); } Loading Loading @@ -614,6 +611,7 @@ public class LockPatternUtils { + MIN_LOCK_PATTERN_SIZE + " dots long."); } setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId); DevicePolicyManager dpm = getDevicePolicyManager(); Loading @@ -630,9 +628,6 @@ public class LockPatternUtils { setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId); setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern.size(), 0, 0, 0, 0, 0, 0, userId); onAfterChangingPassword(userId); } catch (RemoteException re) { Log.e(TAG, "Couldn't save lock pattern " + re); Loading Loading @@ -835,9 +830,9 @@ public class LockPatternUtils { + "of length " + MIN_LOCK_PASSWORD_SIZE); } final int computedQuality = computePasswordQuality(password); setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); getLockSettings().setLockPassword(password, savedPassword, userHandle); getLockSettings().setSeparateProfileChallengeEnabled(userHandle, true, null); int computedQuality = computePasswordQuality(password); // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM Loading @@ -855,40 +850,6 @@ public class LockPatternUtils { } } setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { int letters = 0; int uppercase = 0; int lowercase = 0; int numbers = 0; int symbols = 0; int nonletter = 0; for (int i = 0; i < password.length(); i++) { char c = password.charAt(i); if (c >= 'A' && c <= 'Z') { letters++; uppercase++; } else if (c >= 'a' && c <= 'z') { letters++; lowercase++; } else if (c >= '0' && c <= '9') { numbers++; nonletter++; } else { symbols++; nonletter++; } } dpm.setActivePasswordState(Math.max(quality, computedQuality), password.length(), letters, uppercase, lowercase, numbers, symbols, nonletter, userHandle); } else { // The password is not anything. dpm.setActivePasswordState( DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle); } // Add the password to the password history. We assume all // password hashes have the same length for simplicity of implementation. String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); Loading
services/core/java/com/android/server/LockSettingsService.java +60 −0 Original line number Diff line number Diff line Loading @@ -899,6 +899,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPatternInternal(pattern, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); notifyPasswordChanged(userId); } } Loading @@ -913,6 +914,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); notifyActivePasswordMetricsAvailable(null, userId); return; } Loading Loading @@ -962,6 +964,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPasswordInternal(password, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); notifyPasswordChanged(userId); } } Loading @@ -975,6 +978,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); notifyActivePasswordMetricsAvailable(null, userId); return; } Loading Loading @@ -1365,6 +1369,7 @@ public class LockSettingsService extends ILockSettings.Stub { // migrate credential to GateKeeper credentialUtil.setCredential(credential, null, userId); if (!hasChallenge) { notifyActivePasswordMetricsAvailable(credential, userId); return VerifyCredentialResponse.OK; } // Fall through to get the auth token. Technically this should never happen, Loading Loading @@ -1398,6 +1403,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { // credential has matched notifyActivePasswordMetricsAvailable(credential, userId); unlockKeystore(credential, userId); Slog.i(TAG, "Unlocking user " + userId + Loading @@ -1421,6 +1427,60 @@ public class LockSettingsService extends ILockSettings.Stub { return response; } private void notifyActivePasswordMetricsAvailable(final String password, int userId) { final int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId); // Asynchronous to avoid dead lock mHandler.post(new Runnable() { @Override public void run() { int length = 0; int letters = 0; int uppercase = 0; int lowercase = 0; int numbers = 0; int symbols = 0; int nonletter = 0; if (password != null) { length = password.length(); for (int i = 0; i < length; i++) { char c = password.charAt(i); if (c >= 'A' && c <= 'Z') { letters++; uppercase++; } else if (c >= 'a' && c <= 'z') { letters++; lowercase++; } else if (c >= '0' && c <= '9') { numbers++; nonletter++; } else { symbols++; nonletter++; } } } DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); dpm.setActivePasswordState(quality, length, letters, uppercase, lowercase, numbers, symbols, nonletter, userId); } }); } /** * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before * reporting the password changed. */ private void notifyPasswordChanged(int userId) { // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering mHandler.post(() -> { DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); dpm.reportPasswordChanged(userId); }); } @Override public boolean checkVoldPassword(int userId) throws RemoteException { if (!mFirstCallToVold) { Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +86 −61 Original line number Diff line number Diff line Loading @@ -2218,10 +2218,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, "failed-password-attempts"); } if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 // Don't save metrics for FBE devices if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) { || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0)) { out.startTag(null, "active-password"); out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality)); out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength)); Loading Loading @@ -2314,6 +2317,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { JournaledFile journal = makeJournaledFile(userHandle); FileInputStream stream = null; File file = journal.chooseForRead(); boolean needsRewrite = false; try { stream = new FileInputStream(file); XmlPullParser parser = Xml.newPullParser(); Loading Loading @@ -2390,7 +2394,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("password-owner".equals(tag)) { policy.mPasswordOwner = Integer.parseInt( parser.getAttributeValue(null, "value")); } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); } else if (TAG_STATUS_BAR.equals(tag)) { policy.mStatusBarDisabled = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_DISABLED)); } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) { policy.doNotAskCredentialsOnBoot = true; } else if (TAG_AFFILIATION_ID.equals(tag)) { policy.mAffiliationIds.add(parser.getAttributeValue(null, "id")); } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { String pending = parser.getAttributeValue(null, ATTR_VALUE); policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { policy.mInitBundle = PersistableBundle.restoreFromXml(parser); } else if ("active-password".equals(tag)) { if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) { // Remove this from FBE devices needsRewrite = true; } else { policy.mActivePasswordQuality = Integer.parseInt( parser.getAttributeValue(null, "quality")); policy.mActivePasswordLength = Integer.parseInt( Loading @@ -2407,22 +2431,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { parser.getAttributeValue(null, "symbols")); policy.mActivePasswordNonLetter = Integer.parseInt( parser.getAttributeValue(null, "nonletter")); } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); } else if (TAG_STATUS_BAR.equals(tag)) { policy.mStatusBarDisabled = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_DISABLED)); } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) { policy.doNotAskCredentialsOnBoot = true; } else if (TAG_AFFILIATION_ID.equals(tag)) { policy.mAffiliationIds.add(parser.getAttributeValue(null, "id")); } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { String pending = parser.getAttributeValue(null, ATTR_VALUE); policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { policy.mInitBundle = PersistableBundle.restoreFromXml(parser); } } else { Slog.w(LOG_TAG, "Unknown tag: " + tag); XmlUtils.skipCurrentTag(parser); Loading @@ -2442,34 +2451,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Ignore } // Might need to upgrade the file by rewriting it if (needsRewrite) { saveSettingsLocked(userHandle); } // Generate a list of admins from the admin map policy.mAdminList.addAll(policy.mAdminMap.values()); // Validate that what we stored for the password quality matches // sufficiently what is currently set. Note that this is only // a sanity check in case the two get out of sync; this should // never normally happen. final long identity = mInjector.binderClearCallingIdentity(); try { int actualPasswordQuality = mLockPatternUtils.getActivePasswordQuality(userHandle); if (actualPasswordQuality < policy.mActivePasswordQuality) { Slog.w(LOG_TAG, "Active password quality 0x" + Integer.toHexString(policy.mActivePasswordQuality) + " does not match actual quality 0x" + Integer.toHexString(actualPasswordQuality)); policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; policy.mActivePasswordLength = 0; policy.mActivePasswordUpperCase = 0; policy.mActivePasswordLowerCase = 0; policy.mActivePasswordLetters = 0; policy.mActivePasswordNumeric = 0; policy.mActivePasswordSymbols = 0; policy.mActivePasswordNonLetter = 0; } } finally { mInjector.binderRestoreCallingIdentity(identity); } validatePasswordOwnerLocked(policy); updateMaximumTimeToLockLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); Loading Loading @@ -3663,6 +3652,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean isActivePasswordSufficientForUserLocked( DevicePolicyData policy, int userHandle, boolean parent) { enforceUserUnlocked(userHandle, parent); if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent) || policy.mActivePasswordLength < getPasswordMinimumLength( null, userHandle, parent)) { Loading Loading @@ -4673,20 +4664,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceFullCrossUsersPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); // Managed Profile password can only be changed when it has a separate challenge. if (!isSeparateProfileChallengeEnabled(userHandle)) { enforceNotManagedProfile(userHandle, "set the active password"); // If the managed profile doesn't have a separate password, set the metrics to default if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) { quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; length = 0; letters = 0; uppercase = 0; lowercase = 0; numbers = 0; symbols = 0; nonletter = 0; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); validateQualityConstant(quality); DevicePolicyData policy = getUserData(userHandle); long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { policy.mActivePasswordQuality = quality; policy.mActivePasswordLength = length; Loading @@ -4696,17 +4690,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mActivePasswordNumeric = numbers; policy.mActivePasswordSymbols = symbols; policy.mActivePasswordNonLetter = nonletter; } } @Override public void reportPasswordChanged(int userId) { if (!mHasFeature) { return; } enforceFullCrossUsersPermission(userId); // Managed Profile password can only be changed when it has a separate challenge. if (!isSeparateProfileChallengeEnabled(userId)) { enforceNotManagedProfile(userId, "set the active password"); } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); DevicePolicyData policy = getUserData(userId); long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { policy.mFailedPasswordAttempts = 0; saveSettingsLocked(userHandle); updatePasswordExpirationsLocked(userHandle); setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false); saveSettingsLocked(userId); updatePasswordExpirationsLocked(userId); setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false); // Send a broadcast to each profile using this password as its primary unlock. sendAdminCommandForLockscreenPoliciesLocked( DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userId); } removeCaApprovalsIfNeeded(userHandle); removeCaApprovalsIfNeeded(userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } Loading Loading @@ -6278,6 +6295,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "User must be running and unlocked"); } private void enforceUserUnlocked(int userId, boolean parent) { if (parent) { enforceUserUnlocked(getProfileParentId(userId)); } else { enforceUserUnlocked(userId); } } private void enforceManageUsers() { final int callingUid = mInjector.binderGetCallingUid(); if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) { Loading