diff options
10 files changed, 143 insertions, 121 deletions
diff --git a/config/hiddenapi-greylist-max-o.txt b/config/hiddenapi-greylist-max-o.txt index d9c1cd0313fc..15026b0d1fd7 100644 --- a/config/hiddenapi-greylist-max-o.txt +++ b/config/hiddenapi-greylist-max-o.txt @@ -3040,7 +3040,6 @@ Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->retrievePreRebootSecurityLo Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->retrieveSecurityLogs(Landroid/content/ComponentName;)Landroid/content/pm/ParceledListSlice; Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setAccountManagementDisabled(Landroid/content/ComponentName;Ljava/lang/String;Z)V Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setActiveAdmin(Landroid/content/ComponentName;ZI)V -Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setActivePasswordState(Landroid/app/admin/PasswordMetrics;I)V Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setAffiliationIds(Landroid/content/ComponentName;Ljava/util/List;)V Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setAlwaysOnVpnPackage(Landroid/content/ComponentName;Ljava/lang/String;Z)Z Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setApplicationHidden(Landroid/content/ComponentName;Ljava/lang/String;Ljava/lang/String;Z)Z @@ -3305,7 +3304,6 @@ Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_retrievePreRebootSecu Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_retrieveSecurityLogs:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setAccountManagementDisabled:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setActiveAdmin:I -Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setActivePasswordState:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setAffiliationIds:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setAlwaysOnVpnPackage:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setApplicationHidden:I @@ -3569,7 +3567,6 @@ Landroid/app/admin/IDevicePolicyManager;->retrievePreRebootSecurityLogs(Landroid Landroid/app/admin/IDevicePolicyManager;->retrieveSecurityLogs(Landroid/content/ComponentName;)Landroid/content/pm/ParceledListSlice; Landroid/app/admin/IDevicePolicyManager;->setAccountManagementDisabled(Landroid/content/ComponentName;Ljava/lang/String;Z)V Landroid/app/admin/IDevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V -Landroid/app/admin/IDevicePolicyManager;->setActivePasswordState(Landroid/app/admin/PasswordMetrics;I)V Landroid/app/admin/IDevicePolicyManager;->setAffiliationIds(Landroid/content/ComponentName;Ljava/util/List;)V Landroid/app/admin/IDevicePolicyManager;->setAlwaysOnVpnPackage(Landroid/content/ComponentName;Ljava/lang/String;Z)Z Landroid/app/admin/IDevicePolicyManager;->setApplicationHidden(Landroid/content/ComponentName;Ljava/lang/String;Ljava/lang/String;Z)Z diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ff5a043b9336..a136bbda2a3e 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -5764,21 +5764,6 @@ public class DevicePolicyManager { /** * @hide */ - @UnsupportedAppUsage - @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) - public void setActivePasswordState(PasswordMetrics metrics, int userHandle) { - if (mService != null) { - try { - mService.setActivePasswordState(metrics, userHandle); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } - - /** - * @hide - */ @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) public void reportPasswordChanged(@UserIdInt int userId) { if (mService != null) { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 5cdef6d39dc6..0da5b7a1cf62 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -131,7 +131,6 @@ interface IDevicePolicyManager { void forceRemoveActiveAdmin(in ComponentName policyReceiver, int userHandle); boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy, int userHandle); - void setActivePasswordState(in PasswordMetrics metrics, int userHandle); void reportPasswordChanged(int userId); void reportFailedPasswordAttempt(int userHandle); void reportSuccessfulPasswordAttempt(int userHandle); diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java index d459bfbbcdc4..aab2f4b288b2 100644 --- a/core/java/com/android/internal/widget/LockSettingsInternal.java +++ b/core/java/com/android/internal/widget/LockSettingsInternal.java @@ -16,6 +16,8 @@ package com.android.internal.widget; +import android.annotation.Nullable; +import android.app.admin.PasswordMetrics; /** * LockSettingsService local system service interface. @@ -61,4 +63,18 @@ public abstract class LockSettingsInternal { long tokenHandle, byte[] token, int requestedQuality, int userId); public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId); + + /** + * Returns PasswordMetrics object corresponding to the given user's lockscreen password. + * If the user has a password but its metrics isn't known yet (for example if the device + * has not been unlocked since boot), this method will return {@code null}. + * If the user has no password, a default PasswordMetrics (PASSWORD_QUALITY_UNSPECIFIED) + * will be returned. + * + * Calling this method on a managed profile user with unified challenge is undefined. + * + * @param userHandle the user for whom to provide metrics. + * @return the user password metrics. + */ + public abstract @Nullable PasswordMetrics getUserPasswordMetrics(int userHandle); } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index f38f2f9a0de5..ccc0d4b8334c 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -217,6 +217,11 @@ public class LockSettingsService extends ILockSettings.Stub { private final RecoverableKeyStoreManager mRecoverableKeyStoreManager; private boolean mFirstCallToVold; + // Current password metric for all users on the device. Updated when user unlocks + // the device or changes password. Removed when user is stopped. + @GuardedBy("this") + final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>(); + protected IGateKeeperService mGateKeeperService; protected IAuthSecret mAuthSecretService; @@ -424,6 +429,13 @@ public class LockSettingsService extends ILockSettings.Stub { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } + /** + * Return the {@link DevicePolicyManager} object. + * + * Since LockSettingsService is considered a lower-level component than DevicePolicyManager, + * do NOT hold any lock in this class while calling into DevicePolicyManager to prevent + * the risk of deadlock. + */ public DevicePolicyManager getDevicePolicyManager() { return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); } @@ -593,6 +605,9 @@ public class LockSettingsService extends ILockSettings.Stub { // the device. int strongAuthRequired = LockPatternUtils.StrongAuthTracker.getDefaultFlags(mContext); requireStrongAuth(strongAuthRequired, userId); + synchronized (this) { + mUserPasswordMetrics.remove(userId); + } } public void onStartUser(final int userId) { @@ -1501,7 +1516,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); synchronizeUnifiedWorkChallengeForProfiles(userId, null); - notifyActivePasswordMetricsAvailable(CREDENTIAL_TYPE_NONE, null, userId); + setUserPasswordMetrics(CREDENTIAL_TYPE_NONE, null, userId); sendCredentialsOnChangeIfRequired( credentialType, credential, userId, isLockTiedToParent); return; @@ -1946,7 +1961,7 @@ public class LockSettingsService extends ILockSettings.Stub { Log.w(TAG, "progressCallback throws exception", e); } } - notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); + setUserPasswordMetrics(storedHash.type, credential, userId); unlockKeystore(credential, userId); Slog.i(TAG, "Unlocking user " + userId + " with token length " @@ -1988,32 +2003,40 @@ public class LockSettingsService extends ILockSettings.Stub { } /** - * Call this method to notify DPMS regarding the latest password metric. This should be called - * when the user is authenticating or when a new password is being set. + * Keep track of the given user's latest password metric. This should be called + * when the user is authenticating or when a new password is being set. In comparison, + * {@link #notifyPasswordChanged} only needs to be called when the user changes the password. */ - private void notifyActivePasswordMetricsAvailable( - @CredentialType int credentialType, byte[] password, @UserIdInt int userId) { - final PasswordMetrics metrics = - PasswordMetrics.computeForCredential(credentialType, password); + private void setUserPasswordMetrics(@CredentialType int credentialType, byte[] password, + @UserIdInt int userHandle) { + synchronized (this) { + mUserPasswordMetrics.put(userHandle, + PasswordMetrics.computeForCredential(credentialType, password)); + } + } - // Asynchronous to avoid dead lock - mHandler.post(() -> { - final DevicePolicyManager dpm = (DevicePolicyManager) - mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - dpm.setActivePasswordState(metrics, userId); - }); + @VisibleForTesting + PasswordMetrics getUserPasswordMetrics(int userHandle) { + if (!isUserSecure(userHandle)) { + // for users without password, mUserPasswordMetrics might not be initialized + // since the user never unlock the device manually. In this case, always + // return a default metrics object. This is to distinguish this case from + // the case where during boot user password is unknown yet (returning null here) + return new PasswordMetrics(); + } + synchronized (this) { + return mUserPasswordMetrics.get(userHandle); + } } /** - * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before + * Call after {@link #setUserPasswordMetrics} so metrics are updated before * reporting the password changed. */ private void notifyPasswordChanged(@UserIdInt int userId) { // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering mHandler.post(() -> { - DevicePolicyManager dpm = (DevicePolicyManager) - mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - dpm.reportPasswordChanged(userId); + mInjector.getDevicePolicyManager().reportPasswordChanged(userId); LocalServices.getService(WindowManagerInternal.class).reportPasswordChanged(userId); }); } @@ -2582,7 +2605,7 @@ public class LockSettingsService extends ILockSettings.Stub { } if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId); + setUserPasswordMetrics(credentialType, userCredential, userId); unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId); // Do resetLockout / revokeChallenge when all profiles are unlocked @@ -2676,7 +2699,7 @@ public class LockSettingsService extends ILockSettings.Stub { setSyntheticPasswordHandleLocked(newHandle, userId); synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); - notifyActivePasswordMetricsAvailable(credentialType, credential, userId); + setUserPasswordMetrics(credentialType, credential, userId); if (profilePasswords != null) { for (Map.Entry<Integer, byte[]> entry : profilePasswords.entrySet()) { @@ -2982,6 +3005,8 @@ public class LockSettingsService extends ILockSettings.Stub { pw.println("hasPassword: " + havePassword(userId)); pw.println("hasPattern: " + havePattern(userId)); // print raw credential type instead? pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabled(userId)); + pw.println(String.format("metrics: %s", + getUserPasswordMetrics(userId) != null ? "known" : "unknown")); pw.decreaseIndent(); } pw.println(); @@ -3158,5 +3183,23 @@ public class LockSettingsService extends ILockSettings.Stub { public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) { return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId); } + + @Override + public PasswordMetrics getUserPasswordMetrics(int userHandle) { + long identity = Binder.clearCallingIdentity(); + try { + if (isManagedProfileWithUnifiedLock(userHandle)) { + // A managed profile with unified challenge is supposed to be protected by the + // parent lockscreen, so asking for its password metrics is not really useful, + // as this method would just return the metrics of the random profile password + Slog.w(TAG, "Querying password metrics for unified challenge profile: " + + userHandle); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + return LockSettingsService.this.getUserPasswordMetrics(userHandle); + } + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f933b09b0c15..478bc88fe815 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -248,6 +248,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.StatLogger; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockSettingsInternal; import com.android.server.LocalServices; import com.android.server.LockGuard; import com.android.server.SystemServerInitThreadPool; @@ -500,6 +501,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final UsageStatsManagerInternal mUsageStatsManagerInternal; final TelephonyManager mTelephonyManager; private final LockPatternUtils mLockPatternUtils; + private final LockSettingsInternal mLockSettingsInternal; private final DeviceAdminServiceController mDeviceAdminServiceController; private final OverlayPackagesProvider mOverlayPackagesProvider; @@ -739,7 +741,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final SparseArray<DevicePolicyData> mUserData = new SparseArray<>(); @GuardedBy("getLockObject()") - final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>(); final Handler mHandler; final Handler mBackgroundHandler; @@ -1994,6 +1995,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE)); } + LockSettingsInternal getLockSettingsInternal() { + return LocalServices.getService(LockSettingsInternal.class); + } + boolean isBuildDebuggable() { return Build.IS_DEBUGGABLE; } @@ -2233,7 +2238,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mLocalService = new LocalService(); mLockPatternUtils = injector.newLockPatternUtils(); - + mLockSettingsInternal = injector.getLockSettingsInternal(); // TODO: why does SecurityLogMonitor need to be created even when mHasFeature == false? mSecurityLogMonitor = new SecurityLogMonitor(this); @@ -2309,17 +2314,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } /** - * Provides PasswordMetrics object corresponding to the given user. - * @param userHandle the user for whom to provide metrics. - * @return the user password metrics, or {@code null} if none have been associated with - * the user yet (for example, if the device has booted but not been unlocked). - */ - @GuardedBy("getLockObject()") - PasswordMetrics getUserPasswordMetricsLocked(int userHandle) { - return mUserPasswordMetrics.get(userHandle); - } - - /** * Creates and loads the policy data from xml for data that is shared between * various profiles of a user. In contrast to {@link #getUserData(int)} * it allows access to data of users other than the calling user. @@ -2353,9 +2347,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (policy != null) { mUserData.remove(userHandle); } - if (mUserPasswordMetrics.get(userHandle) != null) { - mUserPasswordMetrics.remove(userHandle); - } File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML); @@ -4183,15 +4174,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void updatePasswordValidityCheckpointLocked(int userHandle, boolean parent) { final int credentialOwner = getCredentialOwner(userHandle, parent); DevicePolicyData policy = getUserData(credentialOwner); - PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner); - if (metrics == null) { - metrics = new PasswordMetrics(); + PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner); + // Update the checkpoint only if the user's password metrics is known + if (metrics != null) { + final boolean newCheckpoint = isPasswordSufficientForUserWithoutCheckpointLocked( + metrics, userHandle, parent); + if (newCheckpoint != policy.mPasswordValidAtLastCheckpoint) { + policy.mPasswordValidAtLastCheckpoint = newCheckpoint; + saveSettingsLocked(credentialOwner); + } } - policy.mPasswordValidAtLastCheckpoint = - isPasswordSufficientForUserWithoutCheckpointLocked( - metrics, userHandle, parent); - - saveSettingsLocked(credentialOwner); } /** @@ -4766,7 +4758,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); int credentialOwner = getCredentialOwner(userHandle, parent); DevicePolicyData policy = getUserDataUnchecked(credentialOwner); - PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner); + PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner); return isActivePasswordSufficientForUserLocked( policy.mPasswordValidAtLastCheckpoint, metrics, userHandle, parent); } @@ -4796,15 +4788,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { enforceUserUnlocked(targetUser, false); int credentialOwner = getCredentialOwner(userHandle, false); DevicePolicyData policy = getUserDataUnchecked(credentialOwner); - PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner); + PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner); return isActivePasswordSufficientForUserLocked( policy.mPasswordValidAtLastCheckpoint, metrics, targetUser, false); } } private boolean isActivePasswordSufficientForUserLocked( - boolean passwordValidAtLastCheckpoint, PasswordMetrics metrics, int userHandle, - boolean parent) { + boolean passwordValidAtLastCheckpoint, @Nullable PasswordMetrics metrics, + int userHandle, boolean parent) { if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && (metrics == null)) { // Before user enters their password for the first time after a reboot, return the // value of this flag, which tells us whether the password was valid the last time @@ -4815,9 +4807,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } if (metrics == null) { - // This could happen if the user never had a password set, for example, so - // setActivePasswordState has never been called for it. - metrics = new PasswordMetrics(); + // Called on a FBE device when the user password exists but its metrics is unknown. + // This shouldn't happen since we enforce the user to be unlocked (which would result + // in the metrics known to the framework on a FBE device) at all call sites. + throw new IllegalStateException("isActivePasswordSufficient called on FBE-locked user"); } return isPasswordSufficientForUserWithoutCheckpointLocked(metrics, userHandle, parent); @@ -4829,7 +4822,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * {@code userId} (or its parent, if {@code parent} is set to {@code true}). */ private boolean isPasswordSufficientForUserWithoutCheckpointLocked( - PasswordMetrics metrics, @UserIdInt int userId, boolean parent) { + @NonNull PasswordMetrics metrics, @UserIdInt int userId, boolean parent) { final int requiredQuality = getPasswordQuality(null, userId, parent); if (requiredQuality >= PASSWORD_QUALITY_NUMERIC @@ -4867,7 +4860,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false); - PasswordMetrics metrics = getUserPasswordMetricsLocked(targetUserId); + PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(targetUserId); return metrics == null ? PASSWORD_COMPLEXITY_NONE : metrics.determineComplexity(); } } @@ -6707,31 +6700,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - /** - * Notify DPMS regarding the metric of the current password. This happens when the user changes - * the password, but also when the user just unlocks the keyguard. In comparison, - * reportPasswordChanged() is only called when the user changes the password. - */ - @Override - public void setActivePasswordState(PasswordMetrics metrics, int userHandle) { - if (!mLockPatternUtils.hasSecureLockScreen()) { - return; - } - enforceFullCrossUsersPermission(userHandle); - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.BIND_DEVICE_ADMIN, null); - - // If the managed profile doesn't have a separate password, set the metrics to default - if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) { - metrics = new PasswordMetrics(); - } - - validateQualityConstant(metrics.quality); - synchronized (getLockObject()) { - mUserPasswordMetrics.put(userHandle, metrics); - } - } - @Override public void reportPasswordChanged(@UserIdInt int userId) { if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index ce83df702b2a..64ea59d2fa2d 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -48,6 +48,7 @@ import androidx.annotation.NonNull; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockSettingsInternal; import com.android.server.net.NetworkPolicyManagerInternal; import java.io.File; @@ -210,6 +211,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override + LockSettingsInternal getLockSettingsInternal() { + return services.lockSettingsInternal; + } + + @Override IAudioService getIAudioService() { return services.iaudioService; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 9ae9824da3e2..d6cb9826d514 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -40,6 +40,7 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; @@ -764,7 +765,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } /** - * Test for: @{link DevicePolicyManager#setActivePasswordState} + * Test for: @{link DevicePolicyManager#reportPasswordChanged} * * Validates that when the password for a user changes, the notification broadcast intent * {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is sent to managed profile owners, in @@ -806,7 +807,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } /** - * Test for: @{link DevicePolicyManager#setActivePasswordState} + * Test for: @{link DevicePolicyManager#reportPasswordChanged} * * Validates that when the password for a managed profile changes, the notification broadcast * intent {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is only sent to the profile, not @@ -4258,6 +4259,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; mContext.packageName = admin1.getPackageName(); setupDeviceOwner(); + final int userHandle = UserHandle.getUserId(mContext.binder.callingUid); + // When there is no lockscreen, user password metrics is always empty. + when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle)) + .thenReturn(new PasswordMetrics()); // If no password requirements are set, isActivePasswordSufficient should succeed. assertTrue(dpm.isActivePasswordSufficient()); @@ -4266,14 +4271,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); reset(mContext.spiedContext); - final int userHandle = UserHandle.getUserId(mContext.binder.callingUid); - PasswordMetrics passwordMetricsNoSymbols = new PasswordMetrics( - DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9, - 8, 2, - 6, 1, - 0, 1); // This should be ignored, as there is no lock screen. - dpm.setActivePasswordState(passwordMetricsNoSymbols, userHandle); dpm.reportPasswordChanged(userHandle); // No broadcast should be sent. @@ -4290,19 +4288,24 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int userHandle = UserHandle.getUserId(mContext.binder.callingUid); final long ident = mContext.binder.clearCallingIdentity(); - dpm.setActivePasswordState(passwordMetrics, userHandle); + when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle)) + .thenReturn(passwordMetrics); dpm.reportPasswordChanged(userHandle); // Drain ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED broadcasts as part of // reportPasswordChanged() - // This broadcast should be sent 4 times: + // This broadcast should be sent 2-4 times: // * Twice from calls to DevicePolicyManagerService.updatePasswordExpirationsLocked, // once for each affected user, in DevicePolicyManagerService.reportPasswordChanged. - // * Twice from calls to DevicePolicyManagerService.saveSettingsLocked + // * Optionally, at most twice from calls to DevicePolicyManagerService.saveSettingsLocked // in DevicePolicyManagerService.reportPasswordChanged, once with the userId // the password change is relevant to and another with the credential owner of said - // userId. - verify(mContext.spiedContext, times(4)).sendBroadcastAsUser( + // userId, if the password checkpoint value changes. + verify(mContext.spiedContext, atMost(4)).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(userHandle)); + verify(mContext.spiedContext, atLeast(2)).sendBroadcastAsUser( MockUtils.checkIntentAction( DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), MockUtils.checkUserHandle(userHandle)); @@ -5224,9 +5227,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY); when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(DpmMockContext.CALLER_USER_HANDLE); - dpms.mUserPasswordMetrics.put( - DpmMockContext.CALLER_USER_HANDLE, - PasswordMetrics.computeForPassword("asdf".getBytes())); + when(getServices().lockSettingsInternal + .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(PasswordMetrics.computeForPassword("asdf".getBytes())); assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity()); } @@ -5241,12 +5244,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(parentUser.id); - dpms.mUserPasswordMetrics.put( - DpmMockContext.CALLER_USER_HANDLE, - PasswordMetrics.computeForPassword("asdf".getBytes())); - dpms.mUserPasswordMetrics.put( - parentUser.id, - PasswordMetrics.computeForPassword("parentUser".getBytes())); + when(getServices().lockSettingsInternal + .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(PasswordMetrics.computeForPassword("asdf".getBytes())); + when(getServices().lockSettingsInternal + .getUserPasswordMetrics(parentUser.id)) + .thenReturn(PasswordMetrics.computeForPassword("parentUser".getBytes())); assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity()); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index f6f365ec1494..b0d0303a82d9 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -64,6 +64,7 @@ import android.view.IWindowManager; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockSettingsInternal; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -102,6 +103,7 @@ public class MockSystemServices { public final IBackupManager ibackupManager; public final IAudioService iaudioService; public final LockPatternUtils lockPatternUtils; + public final LockSettingsInternal lockSettingsInternal; public final StorageManagerForMock storageManager; public final WifiManager wifiManager; public final SettingsForMock settings; @@ -143,6 +145,7 @@ public class MockSystemServices { ibackupManager = mock(IBackupManager.class); iaudioService = mock(IAudioService.class); lockPatternUtils = mock(LockPatternUtils.class); + lockSettingsInternal = mock(LockSettingsInternal.class); storageManager = mock(StorageManagerForMock.class); wifiManager = mock(WifiManager.class); settings = mock(SettingsForMock.class); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 1cd590c39f49..341b8f036263 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -341,6 +341,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { final byte[] pattern = "123654".getBytes(); final byte[] token = "some-high-entropy-secure-token".getBytes(); initializeCredentialUnderSP(password, PRIMARY_USER_ID); + reset(mDevicePolicyManager); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID)); @@ -360,7 +361,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { flushHandlerTasks(); final PasswordMetrics metric = PasswordMetrics.computeForCredential( LockPatternUtils.CREDENTIAL_TYPE_PATTERN, pattern); - verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID); + assertEquals(metric, mService.getUserPasswordMetrics(PRIMARY_USER_ID)); + verify(mDevicePolicyManager).reportPasswordChanged(PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) |