diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index fb9adb730314b..41e2dc0de4d65 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3665,6 +3665,28 @@ public class DevicePolicyManager { return false; } + /** + * Returns whether the given user's credential will be sufficient for all password policy + * requirement, once the user's profile has switched to unified challenge. + * + *
This is different from {@link #isActivePasswordSufficient()} since once the profile
+ * switches to unified challenge, policies set explicitly on the profile will start to affect
+ * the parent user.
+ * @param userHandle the user whose password requirement will be checked
+ * @param profileUser the profile user whose lockscreen challenge will be unified.
+ * @hide
+ */
+ public boolean isPasswordSufficientAfterProfileUnification(int userHandle, int profileUser) {
+ if (mService != null) {
+ try {
+ return mService.isPasswordSufficientAfterProfileUnification(userHandle,
+ profileUser);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
/**
* Retrieve the number of times the user has failed at entering a password since that last
* successful password entry.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 591a3f68eed04..d10153c117235 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -85,6 +85,7 @@ interface IDevicePolicyManager {
boolean isActivePasswordSufficient(int userHandle, boolean parent);
boolean isProfileActivePasswordSufficientForParent(int userHandle);
+ boolean isPasswordSufficientAfterProfileUnification(int userHandle, int profileUser);
int getPasswordComplexity(boolean parent);
boolean isUsingUnifiedPassword(in ComponentName admin);
int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 86ebb47400c79..39e1f0dc2d2c5 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -350,7 +350,7 @@ public final class PasswordMetrics implements Parcelable {
*
* TODO: move to PasswordPolicy
*/
- private void maxWith(PasswordMetrics other) {
+ public void maxWith(PasswordMetrics other) {
credType = Math.max(credType, other.credType);
if (credType != CREDENTIAL_TYPE_PASSWORD) {
return;
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index fa2ec55bd81a2..a77e34b4af1e0 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -147,6 +147,28 @@ public class RestrictedLockUtils {
public EnforcedAdmin() {
}
+ /**
+ * Combines two {@link EnforcedAdmin} into one: if one of them is null, then just return
+ * the other. If both of them are the same, then return that. Otherwise return the symbolic
+ * {@link #MULTIPLE_ENFORCED_ADMIN}
+ */
+ public static EnforcedAdmin combine(EnforcedAdmin admin1, EnforcedAdmin admin2) {
+ if (admin1 == null) {
+ return admin2;
+ }
+ if (admin2 == null) {
+ return admin1;
+ }
+ if (admin1.equals(admin2)) {
+ return admin1;
+ }
+ if (!admin1.enforcedRestriction.equals(admin2.enforcedRestriction)) {
+ throw new IllegalArgumentException(
+ "Admins with different restriction cannot be combined");
+ }
+ return MULTIPLE_ENFORCED_ADMIN;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9297a43b04aa3..7972f247b46dd 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -366,10 +366,15 @@ public class LockSettingsService extends ILockSettings.Stub {
if (mStorage.hasChildProfileLock(managedUserId)) {
return;
}
- // Do not tie it to parent when parent does not have a screen lock
+ // If parent does not have a screen lock, simply clear credential from the managed profile,
+ // to maintain the invariant that unified profile should always have the same secure state
+ // as its parent.
final int parentId = mUserManager.getProfileParent(managedUserId).id;
- if (!isUserSecure(parentId)) {
- if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
+ if (!isUserSecure(parentId) && !managedUserPassword.isNone()) {
+ if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock but profile has one");
+
+ setLockCredentialInternal(LockscreenCredential.createNone(), managedUserPassword,
+ managedUserId, /* isLockTiedToParent= */ true);
return;
}
// Do not tie when the parent has no SID (but does have a screen lock).
@@ -3161,6 +3166,21 @@ public class LockSettingsService extends ILockSettings.Stub {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
}
+ private static String credentialTypeToString(int credentialType) {
+ switch (credentialType) {
+ case CREDENTIAL_TYPE_NONE:
+ return "None";
+ case CREDENTIAL_TYPE_PATTERN:
+ return "Pattern";
+ case CREDENTIAL_TYPE_PIN:
+ return "Pin";
+ case CREDENTIAL_TYPE_PASSWORD:
+ return "Password";
+ default:
+ return "Unknown " + credentialType;
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, printWriter)) return;
@@ -3192,7 +3212,8 @@ public class LockSettingsService extends ILockSettings.Stub {
// It's OK to dump the password type since anyone with physical access can just
// observe it from the keyguard directly.
pw.println("Quality: " + getKeyguardStoredQuality(userId));
- pw.println("CredentialType: " + getCredentialTypeInternal(userId));
+ pw.println("CredentialType: " + credentialTypeToString(
+ getCredentialTypeInternal(userId)));
pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabledInternal(userId));
pw.println(String.format("Metrics: %s",
getUserPasswordMetrics(userId) != null ? "known" : "unknown"));
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1da0740024560..2c0d4c0c92087 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4733,33 +4733,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!parent && isSeparateProfileChallengeEnabled(userHandle)) {
// If this user has a separate challenge, only return its restrictions.
return getUserDataUnchecked(userHandle).mAdminList;
- } else {
- // Return all admins for this user and the profiles that are visible from this
- // user that do not use a separate work challenge.
- ArrayList Should not be called on a profile user.
+ */
+ @GuardedBy("getLockObject()")
+ private List