summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/hiddenapi-greylist-max-o.txt3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java15
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/com/android/internal/widget/LockSettingsInternal.java16
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java83
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java84
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java49
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java4
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)