diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 53f7b295f2ad..25c54fa522d9 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -89,22 +89,25 @@ public class DevicePolicyManager { private final Context mContext; private final IDevicePolicyManager mService; - private boolean mParentInstance; + private final boolean mParentInstance; private static final String REMOTE_EXCEPTION_MESSAGE = "Failed to talk with device policy manager service"; private DevicePolicyManager(Context context, boolean parentInstance) { - this(context, IDevicePolicyManager.Stub.asInterface( - ServiceManager.getService(Context.DEVICE_POLICY_SERVICE))); - mParentInstance = parentInstance; + this(context, + IDevicePolicyManager.Stub.asInterface( + ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)), + parentInstance); } /** @hide */ @VisibleForTesting - protected DevicePolicyManager(Context context, IDevicePolicyManager service) { + protected DevicePolicyManager( + Context context, IDevicePolicyManager service, boolean parentInstance) { mContext = context; mService = service; + mParentInstance = parentInstance; } /** @hide */ @@ -1146,7 +1149,7 @@ public class DevicePolicyManager { public void setPasswordMinimumLength(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumLength(admin, length); + mService.setPasswordMinimumLength(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1167,7 +1170,7 @@ public class DevicePolicyManager { public int getPasswordMinimumLength(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumLength(admin, userHandle); + return mService.getPasswordMinimumLength(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1200,7 +1203,7 @@ public class DevicePolicyManager { public void setPasswordMinimumUpperCase(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumUpperCase(admin, length); + mService.setPasswordMinimumUpperCase(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1228,7 +1231,7 @@ public class DevicePolicyManager { public int getPasswordMinimumUpperCase(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumUpperCase(admin, userHandle); + return mService.getPasswordMinimumUpperCase(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1261,7 +1264,7 @@ public class DevicePolicyManager { public void setPasswordMinimumLowerCase(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumLowerCase(admin, length); + mService.setPasswordMinimumLowerCase(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1289,7 +1292,7 @@ public class DevicePolicyManager { public int getPasswordMinimumLowerCase(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumLowerCase(admin, userHandle); + return mService.getPasswordMinimumLowerCase(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1321,7 +1324,7 @@ public class DevicePolicyManager { public void setPasswordMinimumLetters(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumLetters(admin, length); + mService.setPasswordMinimumLetters(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1347,7 +1350,7 @@ public class DevicePolicyManager { public int getPasswordMinimumLetters(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumLetters(admin, userHandle); + return mService.getPasswordMinimumLetters(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1379,7 +1382,7 @@ public class DevicePolicyManager { public void setPasswordMinimumNumeric(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumNumeric(admin, length); + mService.setPasswordMinimumNumeric(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1406,7 +1409,7 @@ public class DevicePolicyManager { public int getPasswordMinimumNumeric(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumNumeric(admin, userHandle); + return mService.getPasswordMinimumNumeric(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1438,7 +1441,7 @@ public class DevicePolicyManager { public void setPasswordMinimumSymbols(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumSymbols(admin, length); + mService.setPasswordMinimumSymbols(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1464,7 +1467,7 @@ public class DevicePolicyManager { public int getPasswordMinimumSymbols(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumSymbols(admin, userHandle); + return mService.getPasswordMinimumSymbols(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1496,7 +1499,7 @@ public class DevicePolicyManager { public void setPasswordMinimumNonLetter(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumNonLetter(admin, length); + mService.setPasswordMinimumNonLetter(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1523,7 +1526,7 @@ public class DevicePolicyManager { public int getPasswordMinimumNonLetter(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumNonLetter(admin, userHandle); + return mService.getPasswordMinimumNonLetter(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1556,7 +1559,7 @@ public class DevicePolicyManager { public void setPasswordHistoryLength(@NonNull ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordHistoryLength(admin, length); + mService.setPasswordHistoryLength(admin, length, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1588,7 +1591,7 @@ public class DevicePolicyManager { public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) { if (mService != null) { try { - mService.setPasswordExpirationTimeout(admin, timeout); + mService.setPasswordExpirationTimeout(admin, timeout, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1607,7 +1610,7 @@ public class DevicePolicyManager { public long getPasswordExpirationTimeout(@Nullable ComponentName admin) { if (mService != null) { try { - return mService.getPasswordExpirationTimeout(admin, myUserId()); + return mService.getPasswordExpirationTimeout(admin, myUserId(), mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1628,7 +1631,7 @@ public class DevicePolicyManager { public long getPasswordExpiration(@Nullable ComponentName admin) { if (mService != null) { try { - return mService.getPasswordExpiration(admin, myUserId()); + return mService.getPasswordExpiration(admin, myUserId(), mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1651,7 +1654,7 @@ public class DevicePolicyManager { public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordHistoryLength(admin, userHandle); + return mService.getPasswordHistoryLength(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1703,7 +1706,7 @@ public class DevicePolicyManager { public int getCurrentFailedPasswordAttempts() { if (mService != null) { try { - return mService.getCurrentFailedPasswordAttempts(myUserId()); + return mService.getCurrentFailedPasswordAttempts(myUserId(), mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1750,7 +1753,7 @@ public class DevicePolicyManager { public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) { if (mService != null) { try { - mService.setMaximumFailedPasswordsForWipe(admin, num); + mService.setMaximumFailedPasswordsForWipe(admin, num, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1772,7 +1775,8 @@ public class DevicePolicyManager { public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getMaximumFailedPasswordsForWipe(admin, userHandle); + return mService.getMaximumFailedPasswordsForWipe( + admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1790,7 +1794,8 @@ public class DevicePolicyManager { public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) { if (mService != null) { try { - return mService.getProfileWithMinimumFailedPasswordsForWipe(userHandle); + return mService.getProfileWithMinimumFailedPasswordsForWipe( + userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1882,7 +1887,7 @@ public class DevicePolicyManager { public void setMaximumTimeToLock(@NonNull ComponentName admin, long timeMs) { if (mService != null) { try { - mService.setMaximumTimeToLock(admin, timeMs); + mService.setMaximumTimeToLock(admin, timeMs, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1905,7 +1910,7 @@ public class DevicePolicyManager { public long getMaximumTimeToLock(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getMaximumTimeToLock(admin, userHandle); + return mService.getMaximumTimeToLock(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1924,7 +1929,7 @@ public class DevicePolicyManager { public void lockNow() { if (mService != null) { try { - mService.lockNow(); + mService.lockNow(mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -2721,7 +2726,7 @@ public class DevicePolicyManager { public void setKeyguardDisabledFeatures(@NonNull ComponentName admin, int which) { if (mService != null) { try { - mService.setKeyguardDisabledFeatures(admin, which); + mService.setKeyguardDisabledFeatures(admin, which, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -2731,8 +2736,8 @@ public class DevicePolicyManager { /** * Determine whether or not features have been disabled in keyguard either by the calling * admin, if specified, or all admins. - * @param admin The name of the admin component to check, or {@code null} to check whether any admins - * have disabled features in keyguard. + * @param admin The name of the admin component to check, or {@code null} to check whether any + * admins have disabled features in keyguard. * @return bitfield of flags. See {@link #setKeyguardDisabledFeatures(ComponentName, int)} * for a list. */ @@ -2744,7 +2749,7 @@ public class DevicePolicyManager { public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getKeyguardDisabledFeatures(admin, userHandle); + return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -4667,7 +4672,8 @@ public class DevicePolicyManager { * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String) * @see #getCrossProfileWidgetProviders(android.content.ComponentName) */ - public boolean removeCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) { + public boolean removeCrossProfileWidgetProvider( + @NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.removeCrossProfileWidgetProvider(admin, packageName); @@ -5126,7 +5132,8 @@ public class DevicePolicyManager { } /** - * Obtains a {@link DevicePolicyManager} whose calls act on the parent profile. + * Called by the profile owner of a managed profile to obtain a {@link DevicePolicyManager} + * whose calls act on the parent profile. * *

Note only some methods will work on the parent Manager. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 57865f4c4d6c..2b378a4fbaff 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -38,48 +38,48 @@ interface IDevicePolicyManager { void setPasswordQuality(in ComponentName who, int quality, boolean parent); int getPasswordQuality(in ComponentName who, int userHandle, boolean parent); - void setPasswordMinimumLength(in ComponentName who, int length); - int getPasswordMinimumLength(in ComponentName who, int userHandle); + void setPasswordMinimumLength(in ComponentName who, int length, boolean parent); + int getPasswordMinimumLength(in ComponentName who, int userHandle, boolean parent); - void setPasswordMinimumUpperCase(in ComponentName who, int length); - int getPasswordMinimumUpperCase(in ComponentName who, int userHandle); + void setPasswordMinimumUpperCase(in ComponentName who, int length, boolean parent); + int getPasswordMinimumUpperCase(in ComponentName who, int userHandle, boolean parent); - void setPasswordMinimumLowerCase(in ComponentName who, int length); - int getPasswordMinimumLowerCase(in ComponentName who, int userHandle); + void setPasswordMinimumLowerCase(in ComponentName who, int length, boolean parent); + int getPasswordMinimumLowerCase(in ComponentName who, int userHandle, boolean parent); - void setPasswordMinimumLetters(in ComponentName who, int length); - int getPasswordMinimumLetters(in ComponentName who, int userHandle); + void setPasswordMinimumLetters(in ComponentName who, int length, boolean parent); + int getPasswordMinimumLetters(in ComponentName who, int userHandle, boolean parent); - void setPasswordMinimumNumeric(in ComponentName who, int length); - int getPasswordMinimumNumeric(in ComponentName who, int userHandle); + void setPasswordMinimumNumeric(in ComponentName who, int length, boolean parent); + int getPasswordMinimumNumeric(in ComponentName who, int userHandle, boolean parent); - void setPasswordMinimumSymbols(in ComponentName who, int length); - int getPasswordMinimumSymbols(in ComponentName who, int userHandle); + void setPasswordMinimumSymbols(in ComponentName who, int length, boolean parent); + int getPasswordMinimumSymbols(in ComponentName who, int userHandle, boolean parent); - void setPasswordMinimumNonLetter(in ComponentName who, int length); - int getPasswordMinimumNonLetter(in ComponentName who, int userHandle); + void setPasswordMinimumNonLetter(in ComponentName who, int length, boolean parent); + int getPasswordMinimumNonLetter(in ComponentName who, int userHandle, boolean parent); - void setPasswordHistoryLength(in ComponentName who, int length); - int getPasswordHistoryLength(in ComponentName who, int userHandle); + void setPasswordHistoryLength(in ComponentName who, int length, boolean parent); + int getPasswordHistoryLength(in ComponentName who, int userHandle, boolean parent); - void setPasswordExpirationTimeout(in ComponentName who, long expiration); - long getPasswordExpirationTimeout(in ComponentName who, int userHandle); + void setPasswordExpirationTimeout(in ComponentName who, long expiration, boolean parent); + long getPasswordExpirationTimeout(in ComponentName who, int userHandle, boolean parent); - long getPasswordExpiration(in ComponentName who, int userHandle); + long getPasswordExpiration(in ComponentName who, int userHandle, boolean parent); boolean isActivePasswordSufficient(int userHandle, boolean parent); - int getCurrentFailedPasswordAttempts(int userHandle); - int getProfileWithMinimumFailedPasswordsForWipe(int userHandle); + int getCurrentFailedPasswordAttempts(int userHandle, boolean parent); + int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent); - void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num); - int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle); + void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, boolean parent); + int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle, boolean parent); boolean resetPassword(String password, int flags); - void setMaximumTimeToLock(in ComponentName who, long timeMs); - long getMaximumTimeToLock(in ComponentName who, int userHandle); + void setMaximumTimeToLock(in ComponentName who, long timeMs, boolean parent); + long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent); - void lockNow(); + void lockNow(boolean parent); void wipeData(int flags); @@ -99,8 +99,8 @@ interface IDevicePolicyManager { void setScreenCaptureDisabled(in ComponentName who, boolean disabled); boolean getScreenCaptureDisabled(in ComponentName who, int userHandle); - void setKeyguardDisabledFeatures(in ComponentName who, int which); - int getKeyguardDisabledFeatures(in ComponentName who, int userHandle); + void setKeyguardDisabledFeatures(in ComponentName who, int which, boolean parent); + int getKeyguardDisabledFeatures(in ComponentName who, int userHandle, boolean parent); void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle); boolean isAdminActive(in ComponentName policyReceiver, int userHandle); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 7232562e9669..74d46592a70c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -132,7 +132,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; -import com.android.server.pm.UserManagerService; import com.android.server.pm.UserRestrictionsUtils; import org.xmlpull.v1.XmlPullParser; @@ -244,16 +243,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON); } - // Keyguard features that when set of a profile will affect the profiles - // parent user. + /** Keyguard features that when set on a profile will affect the profiles parent user. */ private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER = + // STOPSHIP If the work challenge supports fingerprint, move DISABLE_FINGERPRINT + // to PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE? DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; - // Keyguard features that are allowed to be set on a managed profile + /** Keyguard features that when set on a profile affect the profile content or challenge only */ + private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE = + DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; + + /** Keyguard features that are allowed to be set on a managed profile */ private static final int PROFILE_KEYGUARD_FEATURES = - PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER - | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; + PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE; final Context mContext; final Injector mInjector; @@ -596,12 +599,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } ActiveAdmin getParentActiveAdmin() { - if (parentAdmin == null && !isParent) { + Preconditions.checkState(!isParent); + + if (parentAdmin == null) { parentAdmin = new ActiveAdmin(info, /* parent */ true); } return parentAdmin; } + boolean hasParentActiveAdmin() { + return parentAdmin != null; + } + int getUid() { return info.getActivityInfo().applicationInfo.uid; } public UserHandle getUserHandle() { @@ -933,6 +942,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.w(LOG_TAG, "Missing text when loading long support message"); } } else if (TAG_PARENT_ADMIN.equals(tag)) { + Preconditions.checkState(!isParent); + parentAdmin = new ActiveAdmin(info, /* parent */ true); parentAdmin.readFromXml(parser); } else if (TAG_ORGANIZATION_COLOR.equals(tag)) { @@ -1146,6 +1157,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } pw.print(prefix); pw.println("userRestrictions:"); UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", userRestrictions); + pw.print(prefix); pw.print("isParent="); + pw.println(isParent); + if (parentAdmin != null) { + pw.print(prefix); pw.println("parentAdmin:"); + parentAdmin.dump(prefix + " ", pw); + } } } @@ -1405,7 +1422,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager()); mLocalService = new LocalService(); - mLockPatternUtils = new LockPatternUtils(mContext); + mLockPatternUtils = injector.newLockPatternUtils(); mHasFeature = mContext.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); @@ -1662,8 +1679,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration * reminders. Clears alarm if no expirations are configured. */ - protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) { - final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle); + private void setExpirationAlarmCheckLocked(Context context, int userHandle) { + final long expiration = getPasswordExpirationLocked(null, userHandle, /* parent */ false); final long now = System.currentTimeMillis(); final long timeToExpire = expiration - now; final long alarmTime; @@ -1689,7 +1706,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD, new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT, - new UserHandle(policy.mUserHandle)); + UserHandle.of(userHandle)); am.cancel(pi); if (alarmTime != 0) { am.set(AlarmManager.RTC, alarmTime, pi); @@ -1709,6 +1726,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } + ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle, boolean parent) { + if (parent) { + enforceManagedProfile(userHandle, "call APIs on the parent profile"); + } + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + if (admin != null && parent) { + admin = admin.getParentActiveAdmin(); + } + return admin; + } + ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { final int callingUid = mInjector.binderGetCallingUid(); @@ -1739,6 +1767,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy, boolean parent) + throws SecurityException { + if (parent) { + enforceManagedProfile(mInjector.userHandleGetCallingUserId(), + "call APIs on the parent profile"); + } + ActiveAdmin admin = getActiveAdminForCallerLocked(who, reqPolicy); + return parent ? admin.getParentActiveAdmin() : admin; + } /** * Find the admin for the component and userId bit of the uid, then check * the admin's uid matches the uid. @@ -1858,6 +1895,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Sends a broadcast to each profile that share the password unlock with the given user id. + */ + private void sendAdminCommandForLockscreenPoliciesLocked( + String action, int reqPolicy, int userHandle) { + if (isSeparateProfileChallengeEnabled(userHandle)) { + sendAdminCommandLocked(action, reqPolicy, userHandle); + } else { + sendAdminCommandToSelfAndProfilesLocked(action, reqPolicy, userHandle); + } + } + void removeActiveAdminLocked(final ComponentName adminReceiver, final int userHandle) { final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin != null) { @@ -1881,7 +1930,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { resetGlobalProxyLocked(getUserData(userHandle)); } saveSettingsLocked(userHandle); - updateMaximumTimeToLockLocked(policy); + updateMaximumTimeToLockLocked(userHandle); policy.mRemovingAdmins.remove(adminReceiver); } // The removed admin might have disabled camera, so update user @@ -2198,12 +2247,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // never normally happen. final long identity = mInjector.binderClearCallingIdentity(); try { - LockPatternUtils utils = mInjector.newLockPatternUtils(); - if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) { + 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(utils.getActivePasswordQuality(userHandle))); + + Integer.toHexString(actualPasswordQuality)); policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; policy.mActivePasswordLength = 0; policy.mActivePasswordUpperCase = 0; @@ -2218,7 +2267,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } validatePasswordOwnerLocked(policy); - updateMaximumTimeToLockLocked(policy); + updateMaximumTimeToLockLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); if (policy.mStatusBarDisabled) { setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle); @@ -2382,25 +2431,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { final long now = System.currentTimeMillis(); - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo ui : profiles) { - int profileUserHandle = ui.id; - final DevicePolicyData policy = getUserData(profileUserHandle); - final int count = policy.mAdminList.size(); - if (count > 0) { - for (int i = 0; i < count; i++) { - final ActiveAdmin admin = policy.mAdminList.get(i); - if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) - && admin.passwordExpirationTimeout > 0L - && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS - && admin.passwordExpirationDate > 0L) { - sendAdminCommandLocked(admin, - DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); - } - } + // Return the strictest policy across all participating admins. + List admins = getActiveAdminsForLockscreenPoliciesLocked( + userHandle, /* parent */ false); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) + && admin.passwordExpirationTimeout > 0L + && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS + && admin.passwordExpirationDate > 0L) { + sendAdminCommandLocked(admin, + DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); } } - setExpirationAlarmCheckLocked(mContext, getUserData(userHandle)); + setExpirationAlarmCheckLocked(mContext, userHandle); } } @@ -2669,7 +2714,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isSeparateProfileChallengeAllowed(int userHandle) { ComponentName profileOwner = getProfileOwner(userHandle); - return !isAdminApiLevelMOrBelow(profileOwner, userHandle); + return profileOwner != null && !isAdminApiLevelMOrBelow(profileOwner, userHandle); } @Override @@ -2678,18 +2723,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); validateQualityConstant(quality); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); - if (parent) { - ap = ap.getParentActiveAdmin(); - } + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.passwordQuality != quality) { ap.passwordQuality = quality; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @@ -2704,46 +2745,55 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); - if (parent && admin != null) { - admin = admin.getParentActiveAdmin(); - } + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.passwordQuality : mode; } - if (isSeparateProfileChallengeEnabled(userHandle) && !parent) { - // If a Work Challenge is in use, only return its restrictions. - DevicePolicyData policy = getUserDataUnchecked(userHandle); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (mode < admin.passwordQuality) { - mode = admin.passwordQuality; - } + // Return the strictest policy across all participating admins. + List admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (mode < admin.passwordQuality) { + mode = admin.passwordQuality; } - } else { - // Return strictest policy for this user and profiles that are visible from this - // user that do not use a separate work challenge. - // TODO: When there are separate parent restrictions the profile should just - // obey its own. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - // Only aggregate data for the parent profile plus the non-work challenge - // enabled profiles. - if (!(userInfo.isManagedProfile() - && isSeparateProfileChallengeEnabled(userInfo.id))) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (mode < admin.passwordQuality) { - mode = admin.passwordQuality; - } + } + return mode; + } + } + + private List getActiveAdminsForLockscreenPoliciesLocked( + int userHandle, boolean parent) { + 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 admins = new ArrayList(); + for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { + DevicePolicyData policy = getUserData(userInfo.id); + if (!isManagedProfile(userInfo.id)) { + admins.addAll(policy.mAdminList); + } else { + // For managed profiles, we always include the policies set on the parent + // profile. Additionally, we include the ones set on the managed profile + // if no separate challenge is in place. + boolean hasSeparateChallenge = isSeparateProfileChallengeEnabled(userInfo.id); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.hasParentActiveAdmin()) { + admins.add(admin.getParentActiveAdmin()); + } + if (!hasSeparateChallenge) { + admins.add(admin); } } } } - return mode; + return admins; } } @@ -2757,24 +2807,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setPasswordMinimumLength(ComponentName who, int length) { + public void setPasswordMinimumLength(ComponentName who, int length, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.minimumPasswordLength != length) { ap.minimumPasswordLength = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordMinimumLength(ComponentName who, int userHandle) { + public int getPasswordMinimumLength(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -2783,20 +2832,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.minimumPasswordLength : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i=0; i admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (length < admin.minimumPasswordLength) { + length = admin.minimumPasswordLength; } } return length; @@ -2804,24 +2851,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setPasswordHistoryLength(ComponentName who, int length) { + public void setPasswordHistoryLength(ComponentName who, int length, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.passwordHistoryLength != length) { ap.passwordHistoryLength = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordHistoryLength(ComponentName who, int userHandle) { + public int getPasswordHistoryLength(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -2830,37 +2876,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.passwordHistoryLength : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.passwordHistoryLength) { - length = admin.passwordHistoryLength; - } + // Return the strictest policy across all participating admins. + List admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (length < admin.passwordHistoryLength) { + length = admin.passwordHistoryLength; } } + return length; } } @Override - public void setPasswordExpirationTimeout(ComponentName who, long timeout) { + public void setPasswordExpirationTimeout(ComponentName who, long timeout, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms"); - final int userHandle = UserHandle.getCallingUserId(); + final int userHandle = mInjector.userHandleGetCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD, parent); // Calling this API automatically bumps the expiration date final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L; ap.passwordExpirationDate = expiration; @@ -2871,8 +2916,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .format(new Date(expiration))); } saveSettingsLocked(userHandle); - // in case this is the first one - setExpirationAlarmCheckLocked(mContext, getUserData(userHandle)); + + // in case this is the first one, set the alarm on the appropriate user. + int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle; + setExpirationAlarmCheckLocked(mContext, affectedUserHandle); } } @@ -2881,7 +2928,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Returns 0 if not configured. */ @Override - public long getPasswordExpirationTimeout(ComponentName who, int userHandle) { + public long getPasswordExpirationTimeout(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0L; } @@ -2890,20 +2937,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long timeout = 0L; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.passwordExpirationTimeout : timeout; } - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (timeout == 0L || (admin.passwordExpirationTimeout != 0L - && timeout > admin.passwordExpirationTimeout)) { - timeout = admin.passwordExpirationTimeout; - } + // Return the strictest policy across all participating admins. + List admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (timeout == 0L || (admin.passwordExpirationTimeout != 0L + && timeout > admin.passwordExpirationTimeout)) { + timeout = admin.passwordExpirationTimeout; } } return timeout; @@ -2984,59 +3030,56 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Return a single admin's expiration date/time, or the min (soonest) for all admins. * Returns 0 if not configured. */ - private long getPasswordExpirationLocked(ComponentName who, int userHandle) { + private long getPasswordExpirationLocked(ComponentName who, int userHandle, boolean parent) { long timeout = 0L; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.passwordExpirationDate : timeout; } - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (timeout == 0L || (admin.passwordExpirationDate != 0 - && timeout > admin.passwordExpirationDate)) { - timeout = admin.passwordExpirationDate; - } + // Return the strictest policy across all participating admins. + List admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (timeout == 0L || (admin.passwordExpirationDate != 0 + && timeout > admin.passwordExpirationDate)) { + timeout = admin.passwordExpirationDate; } } return timeout; } @Override - public long getPasswordExpiration(ComponentName who, int userHandle) { + public long getPasswordExpiration(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0L; } enforceFullCrossUsersPermission(userHandle); synchronized (this) { - return getPasswordExpirationLocked(who, userHandle); + return getPasswordExpirationLocked(who, userHandle, parent); } } @Override - public void setPasswordMinimumUpperCase(ComponentName who, int length) { + public void setPasswordMinimumUpperCase(ComponentName who, int length, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.minimumPasswordUpperCase != length) { ap.minimumPasswordUpperCase = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) { + public int getPasswordMinimumUpperCase(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -3045,20 +3088,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.minimumPasswordUpperCase : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i=0; i admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (length < admin.minimumPasswordUpperCase) { + length = admin.minimumPasswordUpperCase; } } return length; @@ -3066,21 +3107,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setPasswordMinimumLowerCase(ComponentName who, int length) { + public void setPasswordMinimumLowerCase(ComponentName who, int length, boolean parent) { Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.minimumPasswordLowerCase != length) { ap.minimumPasswordLowerCase = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) { + public int getPasswordMinimumLowerCase(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -3089,20 +3129,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.minimumPasswordLowerCase : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i=0; i admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (length < admin.minimumPasswordLowerCase) { + length = admin.minimumPasswordLowerCase; } } return length; @@ -3110,24 +3148,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setPasswordMinimumLetters(ComponentName who, int length) { + public void setPasswordMinimumLetters(ComponentName who, int length, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.minimumPasswordLetters != length) { ap.minimumPasswordLetters = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordMinimumLetters(ComponentName who, int userHandle) { + public int getPasswordMinimumLetters(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -3136,23 +3173,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.minimumPasswordLetters : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i=0; i admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) { + continue; + } + if (length < admin.minimumPasswordLetters) { + length = admin.minimumPasswordLetters; } } return length; @@ -3160,24 +3195,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setPasswordMinimumNumeric(ComponentName who, int length) { + public void setPasswordMinimumNumeric(ComponentName who, int length, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.minimumPasswordNumeric != length) { ap.minimumPasswordNumeric = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordMinimumNumeric(ComponentName who, int userHandle) { + public int getPasswordMinimumNumeric(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -3186,23 +3220,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.minimumPasswordNumeric : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) { - continue; - } - if (length < admin.minimumPasswordNumeric) { - length = admin.minimumPasswordNumeric; - } + // Return the strictest policy across all participating admins. + List admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) { + continue; + } + if (length < admin.minimumPasswordNumeric) { + length = admin.minimumPasswordNumeric; } } return length; @@ -3210,24 +3242,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setPasswordMinimumSymbols(ComponentName who, int length) { + public void setPasswordMinimumSymbols(ComponentName who, int length, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.minimumPasswordSymbols != length) { ap.minimumPasswordSymbols = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordMinimumSymbols(ComponentName who, int userHandle) { + public int getPasswordMinimumSymbols(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -3236,23 +3267,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.minimumPasswordSymbols : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i=0; i admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) { + continue; + } + if (length < admin.minimumPasswordSymbols) { + length = admin.minimumPasswordSymbols; } } return length; @@ -3260,24 +3289,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setPasswordMinimumNonLetter(ComponentName who, int length) { + public void setPasswordMinimumNonLetter(ComponentName who, int length, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); if (ap.minimumPasswordNonLetter != length) { ap.minimumPasswordNonLetter = length; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) { + public int getPasswordMinimumNonLetter(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -3286,23 +3314,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.minimumPasswordNonLetter : length; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i=0; i admins = + getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) { + continue; + } + if (length < admin.minimumPasswordNonLetter) { + length = admin.minimumPasswordNonLetter; } } return length; @@ -3317,119 +3343,129 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceFullCrossUsersPermission(userHandle); synchronized (this) { - int id = getCredentialOwner(userHandle); - DevicePolicyData policy = getUserDataUnchecked(id); - // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - ActiveAdmin admin = - getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); - ComponentName adminComponentName = admin.info.getComponent(); - // TODO: Include the Admin sdk level check in LockPatternUtils check. - ComponentName who = !isAdminApiLevelMOrBelow(adminComponentName, userHandle) - && isSeparateProfileChallengeEnabled(userHandle) - ? adminComponentName : null; - if (policy.mActivePasswordQuality < getPasswordQuality(who, userHandle, parent) - || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) { + getActiveAdminForCallerLocked( + null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); + + DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent)); + if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent) + || policy.mActivePasswordLength < getPasswordMinimumLength( + null, userHandle, parent)) { return false; } if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { return true; } - return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle) - && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle) - && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle) - && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle) - && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle) - && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle); + return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase( + null, userHandle, parent) + && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase( + null, userHandle, parent) + && policy.mActivePasswordLetters >= getPasswordMinimumLetters( + null, userHandle, parent) + && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric( + null, userHandle, parent) + && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols( + null, userHandle, parent) + && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter( + null, userHandle, parent); } } @Override - public int getCurrentFailedPasswordAttempts(int userHandle) { + public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) { synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null, - DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); + getActiveAdminForCallerLocked( + null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent); - int credentialOwnerId = getCredentialOwner(userHandle); - DevicePolicyData policy = getUserDataUnchecked(credentialOwnerId); + DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent)); return policy.mFailedPasswordAttempts; } } @Override - public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) { + public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_WIPE_DATA); - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); + getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_WIPE_DATA, parent); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent); if (ap.maximumFailedPasswordsForWipe != num) { ap.maximumFailedPasswordsForWipe = num; - saveSettingsLocked(userHandle); + saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } } } @Override - public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) { + public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } enforceFullCrossUsersPermission(userHandle); synchronized (this) { - ActiveAdmin admin = (who != null) ? getActiveAdminUncheckedLocked(who, userHandle) - : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle); + ActiveAdmin admin = (who != null) + ? getActiveAdminUncheckedLocked(who, userHandle, parent) + : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle, parent); return admin != null ? admin.maximumFailedPasswordsForWipe : 0; } } @Override - public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) { + public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent) { if (!mHasFeature) { return UserHandle.USER_NULL; } enforceFullCrossUsersPermission(userHandle); synchronized (this) { - ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle); + ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked( + userHandle, parent); return admin != null ? admin.getUserHandle().getIdentifier() : UserHandle.USER_NULL; } } /** - * Returns the admin with the strictest policy on maximum failed passwords for this user and all - * profiles that are visible from this user. If the policy for the primary and any other profile - * are equal, it returns the admin for the primary profile. - * Returns {@code null} if none of them have that policy set. + * Returns the admin with the strictest policy on maximum failed passwords for: + *

+ *

If the policy for the primary and any other profile are equal, it returns the admin for + * the primary profile. + * Returns {@code null} if no participating admin has that policy set. */ - private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(int userHandle) { + private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked( + int userHandle, boolean parent) { int count = 0; ActiveAdmin strictestAdmin = null; - for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - for (ActiveAdmin admin : policy.mAdminList) { - if (admin.maximumFailedPasswordsForWipe == - ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { - continue; // No max number of failed passwords policy set for this profile. - } - // We always favor the primary profile if several profiles have the same value set. - if (count == 0 || - count > admin.maximumFailedPasswordsForWipe || - (userInfo.isPrimary() && count >= admin.maximumFailedPasswordsForWipe)) { - count = admin.maximumFailedPasswordsForWipe; - strictestAdmin = admin; - } + // Return the strictest policy across all participating admins. + List admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (admin.maximumFailedPasswordsForWipe == + ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { + continue; // No max number of failed passwords policy set for this profile. + } + + // We always favor the primary profile if several profiles have the same value set. + int userId = admin.getUserHandle().getIdentifier(); + if (count == 0 || + count > admin.maximumFailedPasswordsForWipe || + (count == admin.maximumFailedPasswordsForWipe && + mUserManager.getUserInfo(userId).isPrimary())) { + count = admin.maximumFailedPasswordsForWipe; + strictestAdmin = admin; } } return strictestAdmin; @@ -3443,14 +3479,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int callingUid = mInjector.binderGetCallingUid(); final int userHandle = mInjector.userHandleGetCallingUserId(); - long ident = mInjector.binderClearCallingIdentity(); - try { - if (getCredentialOwner(userHandle) != userHandle) { - throw new SecurityException("You can not change password for this profile because" + if (getCredentialOwner(userHandle, /* parent */ false) != userHandle) { + throw new SecurityException("You can not change password for this profile because" + " it shares the password with the owner profile"); - } - } finally { - mInjector.binderRestoreCallingIdentity(ident); } String password = passwordOrNull != null ? passwordOrNull : ""; @@ -3494,7 +3525,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - quality = getPasswordQuality(null, userHandle, false); + quality = getPasswordQuality(null, userHandle, /* parent */ false); if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; } @@ -3510,7 +3541,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } quality = Math.max(realQuality, quality); } - int length = getPasswordMinimumLength(null, userHandle); + int length = getPasswordMinimumLength(null, userHandle, /* parent */ false); if (password.length() < length) { Slog.w(LOG_TAG, "resetPassword: password length " + password.length() + " does not meet required length " + length); @@ -3539,40 +3570,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { nonletter++; } } - int neededLetters = getPasswordMinimumLetters(null, userHandle); + int neededLetters = getPasswordMinimumLetters(null, userHandle, /* parent */ false); if(letters < neededLetters) { Slog.w(LOG_TAG, "resetPassword: number of letters " + letters + " does not meet required number of letters " + neededLetters); return false; } - int neededNumbers = getPasswordMinimumNumeric(null, userHandle); + int neededNumbers = getPasswordMinimumNumeric(null, userHandle, /* parent */ false); if (numbers < neededNumbers) { Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers + " does not meet required number of numerical digits " + neededNumbers); return false; } - int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle); + int neededLowerCase = getPasswordMinimumLowerCase( + null, userHandle, /* parent */ false); if (lowercase < neededLowerCase) { Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase + " does not meet required number of lowercase letters " + neededLowerCase); return false; } - int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle); + int neededUpperCase = getPasswordMinimumUpperCase( + null, userHandle, /* parent */ false); if (uppercase < neededUpperCase) { Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase + " does not meet required number of uppercase letters " + neededUpperCase); return false; } - int neededSymbols = getPasswordMinimumSymbols(null, userHandle); + int neededSymbols = getPasswordMinimumSymbols(null, userHandle, /* parent */ false); if (symbols < neededSymbols) { Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols + " does not meet required number of special symbols " + neededSymbols); return false; } - int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle); + int neededNonLetter = getPasswordMinimumNonLetter( + null, userHandle, /* parent */ false); if (nonletter < neededNonLetter) { Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter + " does not meet required number of non-letter characters " @@ -3597,17 +3631,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Don't do this with the lock held, because it is going to call // back in to the service. - ident = mInjector.binderClearCallingIdentity(); + final long ident = mInjector.binderClearCallingIdentity(); try { - LockPatternUtils utils = mInjector.newLockPatternUtils(); if (!TextUtils.isEmpty(password)) { - utils.saveLockPassword(password, null, quality, userHandle); + mLockPatternUtils.saveLockPassword(password, null, quality, userHandle); } else { - utils.clearLock(userHandle); + mLockPatternUtils.clearLock(userHandle); } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { - utils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, + mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL); } synchronized (this) { @@ -3627,7 +3660,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean isLockScreenSecureUnchecked(int userId) { long ident = mInjector.binderClearCallingIdentity(); try { - return mInjector.newLockPatternUtils().isSecure(userId); + return mLockPatternUtils.isSecure(userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -3654,50 +3687,69 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setMaximumTimeToLock(ComponentName who, long timeMs) { + public void setMaximumTimeToLock(ComponentName who, long timeMs, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); + final int userHandle = mInjector.userHandleGetCallingUserId(); synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_FORCE_LOCK); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent); if (ap.maximumTimeToUnlock != timeMs) { ap.maximumTimeToUnlock = timeMs; saveSettingsLocked(userHandle); - updateMaximumTimeToLockLocked(getUserData(userHandle)); + updateMaximumTimeToLockLocked(userHandle); } } } - void updateMaximumTimeToLockLocked(DevicePolicyData policy) { - long timeMs = getMaximumTimeToLock(null, policy.mUserHandle); + void updateMaximumTimeToLockLocked(int userHandle) { + // Calculate the min timeout for all profiles - including the ones with a separate + // challenge. Ideally if the timeout only affected the profile challenge we'd lock that + // challenge only and keep the screen on. However there is no easy way of doing that at the + // moment so we set the screen off timeout regardless of whether it affects the parent user + // or the profile challenge only. + long timeMs = Integer.MAX_VALUE; + List profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserDataUnchecked(userInfo.id); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.maximumTimeToUnlock > 0 + && timeMs > admin.maximumTimeToUnlock) { + timeMs = admin.maximumTimeToUnlock; + } + } + } + + // We only store the last maximum time to lock on the parent profile. So if calling from a + // managed profile, retrieve the policy for the parent. + DevicePolicyData policy = getUserDataUnchecked(getProfileParentId(userHandle)); if (policy.mLastMaximumTimeToLock == timeMs) { return; } + policy.mLastMaximumTimeToLock = timeMs; - long ident = mInjector.binderClearCallingIdentity(); + final long ident = mInjector.binderClearCallingIdentity(); try { - if (timeMs <= 0) { - timeMs = Integer.MAX_VALUE; - } else { + if (policy.mLastMaximumTimeToLock != Integer.MAX_VALUE) { // Make sure KEEP_SCREEN_ON is disabled, since that // would allow bypassing of the maximum time to lock. mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); } - policy.mLastMaximumTimeToLock = timeMs; // TODO It can overflow. Cap it. mInjector.getPowerManagerInternal() - .setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs); + .setMaximumScreenOffTimeoutFromDeviceAdmin((int)policy.mLastMaximumTimeToLock); } finally { mInjector.binderRestoreCallingIdentity(ident); } } @Override - public long getMaximumTimeToLock(ComponentName who, int userHandle) { + public long getMaximumTimeToLock(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } @@ -3706,23 +3758,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long time = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return admin != null ? admin.maximumTimeToUnlock : time; } - // Return strictest policy for this user and profiles that are visible from this user. - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i=0; i admin.maximumTimeToUnlock) { - time = admin.maximumTimeToUnlock; - } + // Return the strictest policy across all participating admins. + List admins = getActiveAdminsForLockscreenPoliciesLocked( + userHandle, parent); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (time == 0) { + time = admin.maximumTimeToUnlock; + } else if (admin.maximumTimeToUnlock != 0 + && time > admin.maximumTimeToUnlock) { + time = admin.maximumTimeToUnlock; } } return time; @@ -3730,32 +3780,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void lockNow() { + public void lockNow(boolean parent) { if (!mHasFeature) { return; } synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null, - DeviceAdminInfo.USES_POLICY_FORCE_LOCK); - lockNowUnchecked(); - } - } + getActiveAdminForCallerLocked( + null, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent); - private void lockNowUnchecked() { - long ident = mInjector.binderClearCallingIdentity(); - try { - // Power off the display - mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(), - PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0); - // Ensure the device is locked - new LockPatternUtils(mContext).requireStrongAuth( - STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL); - mInjector.getIWindowManager().lockNow(null); - } catch (RemoteException e) { - } finally { - mInjector.binderRestoreCallingIdentity(ident); + int userToLock = mInjector.userHandleGetCallingUserId(); + + // Unless this is a managed profile with work challenge enabled, lock all users. + if (parent || !isSeparateProfileChallengeEnabled(userToLock)) { + userToLock = UserHandle.USER_ALL; + } + final long ident = mInjector.binderClearCallingIdentity(); + try { + mLockPatternUtils.requireStrongAuth( + STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, userToLock); + if (userToLock == UserHandle.USER_ALL) { + // Power off the display + mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0); + mInjector.getIWindowManager().lockNow(null); + } + } catch (RemoteException e) { + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } } } @@ -4168,7 +4222,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceFullCrossUsersPermission(userHandle); - // Managed Profile password can only be changed when per user encryption is present. + + // Managed Profile password can only be changed when it has a separate challenge. if (!isSeparateProfileChallengeEnabled(userHandle)) { enforceNotManagedProfile(userHandle, "set the active password"); } @@ -4193,18 +4248,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mFailedPasswordAttempts = 0; saveSettingsLocked(userHandle); updatePasswordExpirationsLocked(userHandle); - setExpirationAlarmCheckLocked(mContext, policy); + setExpirationAlarmCheckLocked(mContext, userHandle); // Send a broadcast to each profile using this password as its primary unlock. - if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) { - sendAdminCommandLocked( - DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); - } else { - sendAdminCommandToSelfAndProfilesLocked( - DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); - } + sendAdminCommandForLockscreenPoliciesLocked( + DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); } } finally { mInjector.binderRestoreCallingIdentity(ident); @@ -4215,33 +4264,35 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Called any time the device password is updated. Resets all password expiration clocks. */ private void updatePasswordExpirationsLocked(int userHandle) { - List profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - int profileId = userInfo.id; - DevicePolicyData policy = getUserDataUnchecked(profileId); - final int N = policy.mAdminList.size(); - if (N > 0) { - for (int i=0; i 0L ? (timeout + System.currentTimeMillis()) : 0L; - admin.passwordExpirationDate = expiration; - } - } - } - saveSettingsLocked(profileId); + ArraySet affectedUserIds = new ArraySet(); + List admins = getActiveAdminsForLockscreenPoliciesLocked( + userHandle, /* parent */ false); + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) { + affectedUserIds.add(admin.getUserHandle().getIdentifier()); + long timeout = admin.passwordExpirationTimeout; + long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L; + admin.passwordExpirationDate = expiration; } + } + for (int affectedUserId : affectedUserIds) { + saveSettingsLocked(affectedUserId); + } } @Override public void reportFailedPasswordAttempt(int userHandle) { enforceFullCrossUsersPermission(userHandle); - enforceNotManagedProfile(userHandle, "report failed password attempt"); + if (!isSeparateProfileChallengeEnabled(userHandle)) { + enforceNotManagedProfile(userHandle, + "report failed password attempt if separate profile challenge is not in place"); + } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - long ident = mInjector.binderClearCallingIdentity(); + final long ident = mInjector.binderClearCallingIdentity(); try { boolean wipeData = false; int identifier = 0; @@ -4250,8 +4301,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mFailedPasswordAttempts++; saveSettingsLocked(userHandle); if (mHasFeature) { - ActiveAdmin strictestAdmin = - getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle); + ActiveAdmin strictestAdmin = getAdminWithMinimumFailedPasswordsForWipeLocked( + userHandle, /* parent */ false); int max = strictestAdmin != null ? strictestAdmin.maximumFailedPasswordsForWipe : 0; if (max > 0 && policy.mFailedPasswordAttempts >= max) { @@ -4261,7 +4312,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { wipeData = true; identifier = strictestAdmin.getUserHandle().getIdentifier(); } - sendAdminCommandToSelfAndProfilesLocked( + + sendAdminCommandForLockscreenPoliciesLocked( DeviceAdminReceiver.ACTION_PASSWORD_FAILED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } @@ -4291,7 +4343,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mPasswordOwner = -1; saveSettingsLocked(userHandle); if (mHasFeature) { - sendAdminCommandToSelfAndProfilesLocked( + sendAdminCommandForLockscreenPoliciesLocked( DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } @@ -4951,22 +5003,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - /** - * Selectively disable keyguard features. - */ @Override - public void setKeyguardDisabledFeatures(ComponentName who, int which) { + public void setKeyguardDisabledFeatures(ComponentName who, int which, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = UserHandle.getCallingUserId(); + final int userHandle = mInjector.userHandleGetCallingUserId(); if (isManagedProfile(userHandle)) { - which = which & PROFILE_KEYGUARD_FEATURES; + if (parent) { + which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; + } else if (isSeparateProfileChallengeEnabled(userHandle)){ + which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE; + } else { + which = which & PROFILE_KEYGUARD_FEATURES; + } } synchronized (this) { - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES); + ActiveAdmin ap = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES, parent); if (ap.disabledKeyguardFeatures != which) { ap.disabledKeyguardFeatures = which; saveSettingsLocked(userHandle); @@ -4979,50 +5034,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * or the aggregate of all active admins if who is null. */ @Override - public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) { + public int getKeyguardDisabledFeatures(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return 0; } enforceFullCrossUsersPermission(userHandle); - long ident = mInjector.binderClearCallingIdentity(); + final long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return (admin != null) ? admin.disabledKeyguardFeatures : 0; } - UserInfo user = mUserManager.getUserInfo(userHandle); - final List profiles; - if (user.isManagedProfile()) { + final List admins; + if (!parent && isManagedProfile(userHandle)) { // If we are being asked about a managed profile, just return keyguard features // disabled by admins in the profile. - profiles = Collections.singletonList(user); + admins = getUserDataUnchecked(userHandle).mAdminList; } else { - // Otherwise return those set by admins in the user - // and its profiles. - profiles = mUserManager.getProfiles(userHandle); + // Otherwise return those set by admins in the user and its profiles. + admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent); } - // Determine which keyguard features are disabled by any active admin. - int which = 0; - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserData(userInfo.id); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (userInfo.id == userHandle || !userInfo.isManagedProfile()) { - // If we are being asked explictly about this user - // return all disabled features even if its a managed profile. - which |= admin.disabledKeyguardFeatures; - } else if (!isSeparateProfileChallengeEnabled( - userInfo.id)) { - // Otherwise a managed profile is only allowed to disable - // some features on the parent user, and we only aggregate them if - // it doesn't have its own challenge. - which |= (admin.disabledKeyguardFeatures - & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER); - } + int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; + final int N = admins.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = admins.get(i); + int userId = admin.getUserHandle().getIdentifier(); + if (userId == userHandle || !isManagedProfile(userHandle)) { + // If we are being asked explicitly about this user + // return all disabled features even if its a managed profile. + which |= admin.disabledKeyguardFeatures; + } else { + // Otherwise a managed profile is only allowed to disable + // some features on the parent user. + which |= (admin.disabledKeyguardFeatures + & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER); } } return which; @@ -5283,7 +5331,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); long token = mInjector.binderClearCallingIdentity(); try { - new LockPatternUtils(mContext).setDeviceOwnerInfo(info); + mLockPatternUtils.setDeviceOwnerInfo(info); } finally { mInjector.binderRestoreCallingIdentity(token); } @@ -5293,7 +5341,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public String getDeviceOwnerLockScreenInfo() { - return new LockPatternUtils(mContext).getDeviceOwnerInfo(); + return mLockPatternUtils.getDeviceOwnerInfo(); } private void clearUserPoliciesLocked(UserHandle userHandle) { @@ -5570,15 +5618,37 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void enforceNotManagedProfile(int userHandle, String message) { - if(isManagedProfile(userHandle)) { - throw new SecurityException("You can not " + message + " for a managed profile. "); + private void enforceManagedProfile(int userHandle, String message) { + if(!isManagedProfile(userHandle)) { + throw new SecurityException("You can not " + message + " outside a managed profile."); } } - private int getCredentialOwner(int userHandle) { - long ident = mInjector.binderClearCallingIdentity(); + private void enforceNotManagedProfile(int userHandle, String message) { + if(isManagedProfile(userHandle)) { + throw new SecurityException("You can not " + message + " for a managed profile."); + } + } + + private int getProfileParentId(int userHandle) { + final long ident = mInjector.binderClearCallingIdentity(); try { + UserInfo parentUser = mUserManager.getProfileParent(userHandle); + return parentUser != null ? parentUser.id : userHandle; + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } + } + + private int getCredentialOwner(int userHandle, boolean parent) { + final long ident = mInjector.binderClearCallingIdentity(); + try { + if (parent) { + UserInfo parentProfile = mUserManager.getProfileParent(userHandle); + if (parentProfile != null) { + userHandle = parentProfile.id; + } + } return mUserManager.getCredentialOwnerProfile(userHandle); } finally { mInjector.binderRestoreCallingIdentity(ident); @@ -6515,15 +6585,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + userId); } - UserManager um = UserManager.get(mContext); - UserInfo primaryUser = um.getProfileParent(userId); - - // Call did not come from a managed profile - if (primaryUser == null) { - primaryUser = um.getUserInfo(userId); - } - - if (!isSystemApp(mIPackageManager, packageName, primaryUser.id)) { + int parentUserId = getProfileParentId(userId); + if (!isSystemApp(mIPackageManager, packageName, parentUserId)) { throw new IllegalArgumentException("Only system apps can be enabled this way."); } @@ -6551,19 +6614,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = mInjector.binderClearCallingIdentity(); try { - UserManager um = UserManager.get(mContext); - UserInfo primaryUser = um.getProfileParent(userId); - - // Call did not come from a managed profile. - if (primaryUser == null) { - primaryUser = um.getUserInfo(userId); - } - + int parentUserId = getProfileParentId(userId); List activitiesToEnable = mIPackageManager.queryIntentActivities( intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, // no flags - primaryUser.id); + parentUserId); if (VERBOSE_LOG) { Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable); @@ -6573,7 +6629,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (ResolveInfo info : activitiesToEnable) { if (info.activityInfo != null) { String packageName = info.activityInfo.packageName; - if (isSystemApp(mIPackageManager, packageName, primaryUser.id)) { + if (isSystemApp(mIPackageManager, packageName, parentUserId)) { numberOfAppsInstalled++; mIPackageManager.installExistingPackageAsUser(packageName, userId); } else { @@ -6977,7 +7033,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (Settings.Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) { // ignore if it contradicts an existing policy - long timeMs = getMaximumTimeToLock(who, UserHandle.getCallingUserId()); + long timeMs = getMaximumTimeToLock( + who, mInjector.userHandleGetCallingUserId(), /* parent */ false); if (timeMs > 0 && timeMs < Integer.MAX_VALUE) { return; } @@ -7000,7 +7057,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - if (isDeviceOwner(who, mInjector.userHandleGetCallingUserId())) { + if (isDeviceOwner(who, callingUserId)) { if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting)) { throw new SecurityException(String.format( "Permission denial: Device owners cannot update %1$s", setting)); @@ -7073,15 +7130,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); } final int userId = UserHandle.getCallingUserId(); - LockPatternUtils utils = new LockPatternUtils(mContext); long ident = mInjector.binderClearCallingIdentity(); try { // disallow disabling the keyguard if a password is currently set - if (disabled && utils.isSecure(userId)) { + if (disabled && mLockPatternUtils.isSecure(userId)) { return false; } - utils.setLockScreenDisabled(disabled, userId); + mLockPatternUtils.setLockScreenDisabled(disabled, userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -7214,7 +7270,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isActiveAdminWithPolicy(int uid, int reqPolicy) { - final int userId = UserHandle.getUserId(uid); synchronized(DevicePolicyManagerService.this) { return getActiveAdminWithPolicyForUidLocked(null, reqPolicy, uid) != null; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java index b80f3bf8d58d..3da61d69c742 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java @@ -26,7 +26,7 @@ public class DevicePolicyManagerTestable extends DevicePolicyManager { public DevicePolicyManagerTestable(DpmMockContext context, DevicePolicyManagerServiceTestable dpms) { - super(context, dpms); + super(context, dpms, /* parentInstance = */ false); this.dpms = dpms; }