diff options
4 files changed, 98 insertions, 13 deletions
diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java index fbb8ddfecad2..4d9970c2c144 100644 --- a/core/java/android/app/admin/DevicePolicyCache.java +++ b/core/java/android/app/admin/DevicePolicyCache.java @@ -44,6 +44,12 @@ public abstract class DevicePolicyCache { public abstract boolean getScreenCaptureDisabled(@UserIdInt int userHandle); /** + * Caches {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} of the + * given user with {@code null} passed in as argument. + */ + public abstract int getPasswordQuality(@UserIdInt int userHandle); + + /** * Empty implementation. */ private static class EmptyDevicePolicyCache extends DevicePolicyCache { @@ -53,5 +59,10 @@ public abstract class DevicePolicyCache { public boolean getScreenCaptureDisabled(int userHandle) { return false; } + + @Override + public int getPasswordQuality(int userHandle) { + return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + } } } diff --git a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java index c9173a6430cc..250785138355 100644 --- a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java +++ b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.os.Handler; @@ -125,9 +126,7 @@ class KeyguardDisableHandler { return new KeyguardDisableHandler(new Injector() { @Override public boolean dpmRequiresPassword(int userId) { - DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( - Context.DEVICE_POLICY_SERVICE); - return dpm == null || dpm.getPasswordQuality(null, userId) + return DevicePolicyCache.getInstance().getPasswordQuality(userId) != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java index 37b5ad1eb610..c50a5ffd4175 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java @@ -15,11 +15,16 @@ */ package com.android.server.devicepolicy; +import android.annotation.UserIdInt; import android.app.admin.DevicePolicyCache; +import android.app.admin.DevicePolicyManager; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; +import java.io.PrintWriter; + /** * Implementation of {@link DevicePolicyCache}, to which {@link DevicePolicyManagerService} pushes * policies. @@ -36,9 +41,13 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { @GuardedBy("mLock") private final SparseBooleanArray mScreenCaptureDisabled = new SparseBooleanArray(); + @GuardedBy("mLock") + private final SparseIntArray mPasswordQuality = new SparseIntArray(); + public void onUserRemoved(int userHandle) { synchronized (mLock) { mScreenCaptureDisabled.delete(userHandle); + mPasswordQuality.delete(userHandle); } } @@ -54,4 +63,26 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { mScreenCaptureDisabled.put(userHandle, disabled); } } + + @Override + public int getPasswordQuality(@UserIdInt int userHandle) { + synchronized (mLock) { + return mPasswordQuality.get(userHandle, + DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); + } + } + + /** Updat the password quality cache for the given user */ + public void setPasswordQuality(int userHandle, int quality) { + synchronized (mLock) { + mPasswordQuality.put(userHandle, quality); + } + } + + /** Dump content */ + public void dump(String prefix, PrintWriter pw) { + pw.println("Device policy cache"); + pw.println(prefix + "Screen capture disabled: " + mScreenCaptureDisabled.toString()); + pw.println(prefix + "Password quality: " + mPasswordQuality.toString()); + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e1aeb33445ed..ac7c16e315d0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2333,8 +2333,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); return; } + updatePasswordQualityCacheForUserGroup(userHandle); mPolicyCache.onUserRemoved(userHandle); - mOwners.removeProfileOwner(userHandle); mOwners.writeProfileOwner(userHandle); @@ -3650,6 +3650,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { updateScreenCaptureDisabled(userId, getScreenCaptureDisabled(null, userId)); pushUserRestrictions(userId); + // When system user is started (device boot), load cache for all users. + // This is to mitigate the potential race between loading the cache and keyguard + // reading the value during user switch, due to onStartUser() being asynchronous. + updatePasswordQualityCacheForUserGroup( + userId == UserHandle.USER_SYSTEM ? UserHandle.USER_ALL : userId); startOwnerService(userId, "start-user"); } @@ -4135,13 +4140,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { ActiveAdmin ap = getActiveAdminForCallerLocked( who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); - final PasswordMetrics metrics = ap.minimumPasswordMetrics; - if (metrics.quality != quality) { - metrics.quality = quality; - updatePasswordValidityCheckpointLocked(userId, parent); - saveSettingsLocked(userId); + final long ident = mInjector.binderClearCallingIdentity(); + try { + final PasswordMetrics metrics = ap.minimumPasswordMetrics; + if (metrics.quality != quality) { + metrics.quality = quality; + updatePasswordValidityCheckpointLocked(userId, parent); + updatePasswordQualityCacheForUserGroup(userId); + saveSettingsLocked(userId); + } + maybeLogPasswordComplexitySet(who, userId, parent, metrics); + } finally { + mInjector.binderRestoreCallingIdentity(ident); } - maybeLogPasswordComplexitySet(who, userId, parent, metrics); } DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_PASSWORD_QUALITY) @@ -4173,6 +4184,32 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { saveSettingsLocked(credentialOwner); } + /** + * Update password quality values in policy cache for all users in the same user group as + * the given user. The cached password quality for user X is the aggregated quality among all + * admins who have influence of user X's screenlock, i.e. it's equivalent to the return value of + * getPasswordQuality(null, user X, false). + * + * Caches for all users in the same user group often need to be updated alltogether because a + * user's admin policy can affect another's aggregated password quality in some situation. + * For example a managed profile's policy will affect the parent user if the profile has unified + * challenge. A profile can also explicitly set a parent password quality which will affect the + * aggregated password quality of the parent user. + */ + private void updatePasswordQualityCacheForUserGroup(@UserIdInt int userId) { + final List<UserInfo> users; + if (userId == UserHandle.USER_ALL) { + users = mUserManager.getUsers(); + } else { + users = mUserManager.getProfiles(userId); + } + for (UserInfo userInfo : users) { + final int currentUserId = userInfo.id; + mPolicyCache.setPasswordQuality(currentUserId, + getPasswordQuality(null, currentUserId, false)); + } + } + @Override public int getPasswordQuality(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { @@ -8849,6 +8886,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mStatLogger.dump(pw, " "); pw.println(); pw.println(" Encryption Status: " + getEncryptionStatusName(getEncryptionStatus())); + pw.println(); + mPolicyCache.dump(" ", pw); } } @@ -11319,8 +11358,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void reportSeparateProfileChallengeChanged(@UserIdInt int userId) { - synchronized (getLockObject()) { - updateMaximumTimeToLockLocked(userId); + final long ident = mInjector.binderClearCallingIdentity(); + try { + synchronized (getLockObject()) { + updateMaximumTimeToLockLocked(userId); + updatePasswordQualityCacheForUserGroup(userId); + } + } finally { + mInjector.binderRestoreCallingIdentity(ident); } DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SEPARATE_PROFILE_CHALLENGE_CHANGED) @@ -11336,7 +11381,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public CharSequence getPrintingDisabledReasonForUser(@UserIdInt int userId) { synchronized (getLockObject()) { - DevicePolicyData policy = getUserData(userId); if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING, UserHandle.of(userId))) { Log.e(LOG_TAG, "printing is enabled"); |