From 599dd7ce9adf8ca067cefb0b191a5ac20ec35a79 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Fri, 14 Sep 2012 23:20:08 -0700 Subject: [PATCH] DevicePolicyManager per user Bug: 7136483 Store device policy information for each user and apply them when user switches. Global proxy can only be controlled by owner. Camera restriction applies to all users, if any one has an admin that disables it. Storage encryption can only be controlled by owner, although other users can query the state. Wipe data will only remove the user if non-zero, wipe the device, if zero. Change-Id: I359be46c1bc3828fd13d4be3228f11495081c8f2 --- core/java/android/app/PendingIntent.java | 9 +- .../app/admin/DevicePolicyManager.java | 176 +++- .../app/admin/IDevicePolicyManager.aidl | 96 +- .../internal/widget/LockPatternUtils.java | 111 +- .../impl/keyguard/KeyguardHostView.java | 5 +- .../impl/keyguard/KeyguardSelectorView.java | 3 +- .../impl/keyguard/KeyguardViewMediator.java | 2 +- .../server/DevicePolicyManagerService.java | 970 +++++++++++------- .../server/pm/PackageManagerService.java | 4 +- .../server/wm/KeyguardDisableHandler.java | 14 +- 10 files changed, 865 insertions(+), 525 deletions(-) diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index e7cea570ae5de..8fb6948e332e7 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -413,6 +413,13 @@ public final class PendingIntent implements Parcelable { */ public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags) { + return getBroadcastAsUser(context, requestCode, intent, flags, + new UserHandle(UserHandle.myUserId())); + } + + /** @hide */ + public static PendingIntent getBroadcastAsUser(Context context, int requestCode, + Intent intent, int flags, UserHandle userHandle) { String packageName = context.getPackageName(); String resolvedType = intent != null ? intent.resolveTypeIfNeeded( context.getContentResolver()) : null; @@ -423,7 +430,7 @@ public final class PendingIntent implements Parcelable { ActivityManager.INTENT_SENDER_BROADCAST, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, - flags, null, UserHandle.myUserId()); + flags, null, userHandle.getIdentifier()); return target != null ? new PendingIntent(target) : null; } catch (RemoteException e) { } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 4c55bb3be9498..600d02a174b72 100755 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -29,6 +29,7 @@ import android.os.Handler; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.Log; import java.io.IOException; @@ -131,7 +132,7 @@ public class DevicePolicyManager { public boolean isAdminActive(ComponentName who) { if (mService != null) { try { - return mService.isAdminActive(who); + return mService.isAdminActive(who, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -147,7 +148,7 @@ public class DevicePolicyManager { public List getActiveAdmins() { if (mService != null) { try { - return mService.getActiveAdmins(); + return mService.getActiveAdmins(UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -156,12 +157,14 @@ public class DevicePolicyManager { } /** + * Used by package administration code to determine if a package can be stopped + * or uninstalled. * @hide */ public boolean packageHasActiveAdmins(String packageName) { if (mService != null) { try { - return mService.packageHasActiveAdmins(packageName); + return mService.packageHasActiveAdmins(packageName, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -178,7 +181,7 @@ public class DevicePolicyManager { public void removeActiveAdmin(ComponentName who) { if (mService != null) { try { - mService.removeActiveAdmin(who); + mService.removeActiveAdmin(who, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -197,7 +200,7 @@ public class DevicePolicyManager { public boolean hasGrantedPolicy(ComponentName admin, int usesPolicy) { if (mService != null) { try { - return mService.hasGrantedPolicy(admin, usesPolicy); + return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -289,7 +292,7 @@ public class DevicePolicyManager { public void setPasswordQuality(ComponentName admin, int quality) { if (mService != null) { try { - mService.setPasswordQuality(admin, quality); + mService.setPasswordQuality(admin, quality, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -303,9 +306,14 @@ public class DevicePolicyManager { * all admins. */ public int getPasswordQuality(ComponentName admin) { + return getPasswordQuality(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordQuality(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordQuality(admin); + return mService.getPasswordQuality(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -337,7 +345,7 @@ public class DevicePolicyManager { public void setPasswordMinimumLength(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumLength(admin, length); + mService.setPasswordMinimumLength(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -351,9 +359,14 @@ public class DevicePolicyManager { * all admins. */ public int getPasswordMinimumLength(ComponentName admin) { + return getPasswordMinimumLength(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordMinimumLength(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumLength(admin); + return mService.getPasswordMinimumLength(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -386,7 +399,7 @@ public class DevicePolicyManager { public void setPasswordMinimumUpperCase(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumUpperCase(admin, length); + mService.setPasswordMinimumUpperCase(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -406,9 +419,14 @@ public class DevicePolicyManager { * password. */ public int getPasswordMinimumUpperCase(ComponentName admin) { + return getPasswordMinimumUpperCase(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordMinimumUpperCase(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumUpperCase(admin); + return mService.getPasswordMinimumUpperCase(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -441,7 +459,7 @@ public class DevicePolicyManager { public void setPasswordMinimumLowerCase(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumLowerCase(admin, length); + mService.setPasswordMinimumLowerCase(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -461,9 +479,14 @@ public class DevicePolicyManager { * password. */ public int getPasswordMinimumLowerCase(ComponentName admin) { + return getPasswordMinimumLowerCase(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordMinimumLowerCase(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumLowerCase(admin); + return mService.getPasswordMinimumLowerCase(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -495,7 +518,7 @@ public class DevicePolicyManager { public void setPasswordMinimumLetters(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumLetters(admin, length); + mService.setPasswordMinimumLetters(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -514,9 +537,14 @@ public class DevicePolicyManager { * @return The minimum number of letters required in the password. */ public int getPasswordMinimumLetters(ComponentName admin) { + return getPasswordMinimumLetters(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordMinimumLetters(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumLetters(admin); + return mService.getPasswordMinimumLetters(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -548,7 +576,7 @@ public class DevicePolicyManager { public void setPasswordMinimumNumeric(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumNumeric(admin, length); + mService.setPasswordMinimumNumeric(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -567,9 +595,14 @@ public class DevicePolicyManager { * @return The minimum number of numerical digits required in the password. */ public int getPasswordMinimumNumeric(ComponentName admin) { + return getPasswordMinimumNumeric(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordMinimumNumeric(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumNumeric(admin); + return mService.getPasswordMinimumNumeric(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -601,7 +634,7 @@ public class DevicePolicyManager { public void setPasswordMinimumSymbols(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumSymbols(admin, length); + mService.setPasswordMinimumSymbols(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -620,9 +653,14 @@ public class DevicePolicyManager { * @return The minimum number of symbols required in the password. */ public int getPasswordMinimumSymbols(ComponentName admin) { + return getPasswordMinimumSymbols(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumSymbols(admin); + return mService.getPasswordMinimumSymbols(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -654,7 +692,7 @@ public class DevicePolicyManager { public void setPasswordMinimumNonLetter(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordMinimumNonLetter(admin, length); + mService.setPasswordMinimumNonLetter(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -673,9 +711,14 @@ public class DevicePolicyManager { * @return The minimum number of letters required in the password. */ public int getPasswordMinimumNonLetter(ComponentName admin) { + return getPasswordMinimumNonLetter(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordMinimumNonLetter(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordMinimumNonLetter(admin); + return mService.getPasswordMinimumNonLetter(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -708,7 +751,7 @@ public class DevicePolicyManager { public void setPasswordHistoryLength(ComponentName admin, int length) { if (mService != null) { try { - mService.setPasswordHistoryLength(admin, length); + mService.setPasswordHistoryLength(admin, length, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -737,7 +780,7 @@ public class DevicePolicyManager { public void setPasswordExpirationTimeout(ComponentName admin, long timeout) { if (mService != null) { try { - mService.setPasswordExpirationTimeout(admin, timeout); + mService.setPasswordExpirationTimeout(admin, timeout, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -756,7 +799,7 @@ public class DevicePolicyManager { public long getPasswordExpirationTimeout(ComponentName admin) { if (mService != null) { try { - return mService.getPasswordExpirationTimeout(admin); + return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -776,7 +819,7 @@ public class DevicePolicyManager { public long getPasswordExpiration(ComponentName admin) { if (mService != null) { try { - return mService.getPasswordExpiration(admin); + return mService.getPasswordExpiration(admin, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -792,9 +835,14 @@ public class DevicePolicyManager { * @return The length of the password history */ public int getPasswordHistoryLength(ComponentName admin) { + return getPasswordHistoryLength(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getPasswordHistoryLength(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordHistoryLength(admin); + return mService.getPasswordHistoryLength(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -828,7 +876,7 @@ public class DevicePolicyManager { public boolean isActivePasswordSufficient() { if (mService != null) { try { - return mService.isActivePasswordSufficient(); + return mService.isActivePasswordSufficient(UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -847,7 +895,7 @@ public class DevicePolicyManager { public int getCurrentFailedPasswordAttempts() { if (mService != null) { try { - return mService.getCurrentFailedPasswordAttempts(); + return mService.getCurrentFailedPasswordAttempts(UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -877,7 +925,7 @@ public class DevicePolicyManager { public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) { if (mService != null) { try { - mService.setMaximumFailedPasswordsForWipe(admin, num); + mService.setMaximumFailedPasswordsForWipe(admin, num, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -892,9 +940,14 @@ public class DevicePolicyManager { * all admins. */ public int getMaximumFailedPasswordsForWipe(ComponentName admin) { + return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getMaximumFailedPasswordsForWipe(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getMaximumFailedPasswordsForWipe(admin); + return mService.getMaximumFailedPasswordsForWipe(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -933,7 +986,7 @@ public class DevicePolicyManager { public boolean resetPassword(String password, int flags) { if (mService != null) { try { - return mService.resetPassword(password, flags); + return mService.resetPassword(password, flags, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -957,7 +1010,7 @@ public class DevicePolicyManager { public void setMaximumTimeToLock(ComponentName admin, long timeMs) { if (mService != null) { try { - mService.setMaximumTimeToLock(admin, timeMs); + mService.setMaximumTimeToLock(admin, timeMs, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -971,9 +1024,14 @@ public class DevicePolicyManager { * all admins. */ public long getMaximumTimeToLock(ComponentName admin) { + return getMaximumTimeToLock(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public long getMaximumTimeToLock(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getMaximumTimeToLock(admin); + return mService.getMaximumTimeToLock(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1021,7 +1079,7 @@ public class DevicePolicyManager { public void wipeData(int flags) { if (mService != null) { try { - mService.wipeData(flags); + mService.wipeData(flags, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1090,7 +1148,7 @@ public class DevicePolicyManager { } android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec); } - return mService.setGlobalProxy(admin, hostSpec, exclSpec); + return mService.setGlobalProxy(admin, hostSpec, exclSpec, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1107,7 +1165,7 @@ public class DevicePolicyManager { public ComponentName getGlobalProxyAdmin() { if (mService != null) { try { - return mService.getGlobalProxyAdmin(); + return mService.getGlobalProxyAdmin(UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1199,7 +1257,7 @@ public class DevicePolicyManager { public int setStorageEncryption(ComponentName admin, boolean encrypt) { if (mService != null) { try { - return mService.setStorageEncryption(admin, encrypt); + return mService.setStorageEncryption(admin, encrypt, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1219,7 +1277,7 @@ public class DevicePolicyManager { public boolean getStorageEncryption(ComponentName admin) { if (mService != null) { try { - return mService.getStorageEncryption(admin); + return mService.getStorageEncryption(admin, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1244,9 +1302,14 @@ public class DevicePolicyManager { * {@link #ENCRYPTION_STATUS_ACTIVATING}, or{@link #ENCRYPTION_STATUS_ACTIVE}. */ public int getStorageEncryptionStatus() { + return getStorageEncryptionStatus(UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getStorageEncryptionStatus(int userHandle) { if (mService != null) { try { - return mService.getStorageEncryptionStatus(); + return mService.getStorageEncryptionStatus(userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1269,7 +1332,7 @@ public class DevicePolicyManager { public void setCameraDisabled(ComponentName admin, boolean disabled) { if (mService != null) { try { - mService.setCameraDisabled(admin, disabled); + mService.setCameraDisabled(admin, disabled, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1283,9 +1346,14 @@ public class DevicePolicyManager { * have disabled the camera */ public boolean getCameraDisabled(ComponentName admin) { + return getCameraDisabled(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public boolean getCameraDisabled(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getCameraDisabled(admin); + return mService.getCameraDisabled(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1309,7 +1377,7 @@ public class DevicePolicyManager { public void setKeyguardWidgetsDisabled(ComponentName admin, int which) { if (mService != null) { try { - mService.setKeyguardWidgetsDisabled(admin, which); + mService.setKeyguardWidgetsDisabled(admin, which, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1323,9 +1391,14 @@ public class DevicePolicyManager { * have disabled widgets in keyguard. */ public int getKeyguardWidgetsDisabled(ComponentName admin) { + return getKeyguardWidgetsDisabled(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public int getKeyguardWidgetsDisabled(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getKeyguardWidgetsDisabled(admin); + return mService.getKeyguardWidgetsDisabled(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1339,7 +1412,7 @@ public class DevicePolicyManager { public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) { if (mService != null) { try { - mService.setActiveAdmin(policyReceiver, refreshing); + mService.setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1380,7 +1453,7 @@ public class DevicePolicyManager { public void getRemoveWarning(ComponentName admin, RemoteCallback result) { if (mService != null) { try { - mService.getRemoveWarning(admin, result); + mService.getRemoveWarning(admin, result, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1391,11 +1464,11 @@ public class DevicePolicyManager { * @hide */ public void setActivePasswordState(int quality, int length, int letters, int uppercase, - int lowercase, int numbers, int symbols, int nonletter) { + int lowercase, int numbers, int symbols, int nonletter, int userHandle) { if (mService != null) { try { mService.setActivePasswordState(quality, length, letters, uppercase, lowercase, - numbers, symbols, nonletter); + numbers, symbols, nonletter, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1405,10 +1478,10 @@ public class DevicePolicyManager { /** * @hide */ - public void reportFailedPasswordAttempt() { + public void reportFailedPasswordAttempt(int userHandle) { if (mService != null) { try { - mService.reportFailedPasswordAttempt(); + mService.reportFailedPasswordAttempt(userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1418,14 +1491,13 @@ public class DevicePolicyManager { /** * @hide */ - public void reportSuccessfulPasswordAttempt() { + public void reportSuccessfulPasswordAttempt(int userHandle) { if (mService != null) { try { - mService.reportSuccessfulPasswordAttempt(); + mService.reportSuccessfulPasswordAttempt(userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } } - } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 0b7ec1229e187..bdfb177acb533 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -25,76 +25,76 @@ import android.os.RemoteCallback; * {@hide} */ interface IDevicePolicyManager { - void setPasswordQuality(in ComponentName who, int quality); - int getPasswordQuality(in ComponentName who); + void setPasswordQuality(in ComponentName who, int quality, int userHandle); + int getPasswordQuality(in ComponentName who, int userHandle); - void setPasswordMinimumLength(in ComponentName who, int length); - int getPasswordMinimumLength(in ComponentName who); + void setPasswordMinimumLength(in ComponentName who, int length, int userHandle); + int getPasswordMinimumLength(in ComponentName who, int userHandle); - void setPasswordMinimumUpperCase(in ComponentName who, int length); - int getPasswordMinimumUpperCase(in ComponentName who); + void setPasswordMinimumUpperCase(in ComponentName who, int length, int userHandle); + int getPasswordMinimumUpperCase(in ComponentName who, int userHandle); - void setPasswordMinimumLowerCase(in ComponentName who, int length); - int getPasswordMinimumLowerCase(in ComponentName who); + void setPasswordMinimumLowerCase(in ComponentName who, int length, int userHandle); + int getPasswordMinimumLowerCase(in ComponentName who, int userHandle); - void setPasswordMinimumLetters(in ComponentName who, int length); - int getPasswordMinimumLetters(in ComponentName who); + void setPasswordMinimumLetters(in ComponentName who, int length, int userHandle); + int getPasswordMinimumLetters(in ComponentName who, int userHandle); - void setPasswordMinimumNumeric(in ComponentName who, int length); - int getPasswordMinimumNumeric(in ComponentName who); + void setPasswordMinimumNumeric(in ComponentName who, int length, int userHandle); + int getPasswordMinimumNumeric(in ComponentName who, int userHandle); - void setPasswordMinimumSymbols(in ComponentName who, int length); - int getPasswordMinimumSymbols(in ComponentName who); + void setPasswordMinimumSymbols(in ComponentName who, int length, int userHandle); + int getPasswordMinimumSymbols(in ComponentName who, int userHandle); - void setPasswordMinimumNonLetter(in ComponentName who, int length); - int getPasswordMinimumNonLetter(in ComponentName who); + void setPasswordMinimumNonLetter(in ComponentName who, int length, int userHandle); + int getPasswordMinimumNonLetter(in ComponentName who, int userHandle); - void setPasswordHistoryLength(in ComponentName who, int length); - int getPasswordHistoryLength(in ComponentName who); + void setPasswordHistoryLength(in ComponentName who, int length, int userHandle); + int getPasswordHistoryLength(in ComponentName who, int userHandle); - void setPasswordExpirationTimeout(in ComponentName who, long expiration); - long getPasswordExpirationTimeout(in ComponentName who); + void setPasswordExpirationTimeout(in ComponentName who, long expiration, int userHandle); + long getPasswordExpirationTimeout(in ComponentName who, int userHandle); - long getPasswordExpiration(in ComponentName who); + long getPasswordExpiration(in ComponentName who, int userHandle); - boolean isActivePasswordSufficient(); - int getCurrentFailedPasswordAttempts(); + boolean isActivePasswordSufficient(int userHandle); + int getCurrentFailedPasswordAttempts(int userHandle); - void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num); - int getMaximumFailedPasswordsForWipe(in ComponentName admin); + void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, int userHandle); + int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle); - boolean resetPassword(String password, int flags); + boolean resetPassword(String password, int flags, int userHandle); - void setMaximumTimeToLock(in ComponentName who, long timeMs); - long getMaximumTimeToLock(in ComponentName who); + void setMaximumTimeToLock(in ComponentName who, long timeMs, int userHandle); + long getMaximumTimeToLock(in ComponentName who, int userHandle); void lockNow(); - void wipeData(int flags); + void wipeData(int flags, int userHandle); - ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList); - ComponentName getGlobalProxyAdmin(); + ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList, int userHandle); + ComponentName getGlobalProxyAdmin(int userHandle); - int setStorageEncryption(in ComponentName who, boolean encrypt); - boolean getStorageEncryption(in ComponentName who); - int getStorageEncryptionStatus(); + int setStorageEncryption(in ComponentName who, boolean encrypt, int userHandle); + boolean getStorageEncryption(in ComponentName who, int userHandle); + int getStorageEncryptionStatus(int userHandle); - void setCameraDisabled(in ComponentName who, boolean disabled); - boolean getCameraDisabled(in ComponentName who); + void setCameraDisabled(in ComponentName who, boolean disabled, int userHandle); + boolean getCameraDisabled(in ComponentName who, int userHandle); - void setKeyguardWidgetsDisabled(in ComponentName who, int which); - int getKeyguardWidgetsDisabled(in ComponentName who); + void setKeyguardWidgetsDisabled(in ComponentName who, int which, int userHandle); + int getKeyguardWidgetsDisabled(in ComponentName who, int userHandle); - void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing); - boolean isAdminActive(in ComponentName policyReceiver); - List getActiveAdmins(); - boolean packageHasActiveAdmins(String packageName); - void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result); - void removeActiveAdmin(in ComponentName policyReceiver); - boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy); + void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle); + boolean isAdminActive(in ComponentName policyReceiver, int userHandle); + List getActiveAdmins(int userHandle); + boolean packageHasActiveAdmins(String packageName, int userHandle); + void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result, int userHandle); + void removeActiveAdmin(in ComponentName policyReceiver, int userHandle); + boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy, int userHandle); void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase, - int numbers, int symbols, int nonletter); - void reportFailedPasswordAttempt(); - void reportSuccessfulPasswordAttempt(); + int numbers, int symbols, int nonletter, int userHandle); + void reportFailedPasswordAttempt(int userHandle); + void reportSuccessfulPasswordAttempt(int userHandle); } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 0710d96ff2535..3207435d8bf9b 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -165,7 +165,7 @@ public class LockPatternUtils { } public int getRequestedMinimumPasswordLength() { - return getDevicePolicyManager().getPasswordMinimumLength(null); + return getDevicePolicyManager().getPasswordMinimumLength(null, getCurrentOrCallingUserId()); } /** @@ -173,47 +173,54 @@ public class LockPatternUtils { * MODE_PATTERN which allows the user to choose anything. */ public int getRequestedPasswordQuality() { - return getDevicePolicyManager().getPasswordQuality(null); + return getDevicePolicyManager().getPasswordQuality(null, getCurrentOrCallingUserId()); } public int getRequestedPasswordHistoryLength() { - return getDevicePolicyManager().getPasswordHistoryLength(null); + return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId()); } public int getRequestedPasswordMinimumLetters() { - return getDevicePolicyManager().getPasswordMinimumLetters(null); + return getDevicePolicyManager().getPasswordMinimumLetters(null, + getCurrentOrCallingUserId()); } public int getRequestedPasswordMinimumUpperCase() { - return getDevicePolicyManager().getPasswordMinimumUpperCase(null); + return getDevicePolicyManager().getPasswordMinimumUpperCase(null, + getCurrentOrCallingUserId()); } public int getRequestedPasswordMinimumLowerCase() { - return getDevicePolicyManager().getPasswordMinimumLowerCase(null); + return getDevicePolicyManager().getPasswordMinimumLowerCase(null, + getCurrentOrCallingUserId()); } public int getRequestedPasswordMinimumNumeric() { - return getDevicePolicyManager().getPasswordMinimumNumeric(null); + return getDevicePolicyManager().getPasswordMinimumNumeric(null, + getCurrentOrCallingUserId()); } public int getRequestedPasswordMinimumSymbols() { - return getDevicePolicyManager().getPasswordMinimumSymbols(null); + return getDevicePolicyManager().getPasswordMinimumSymbols(null, + getCurrentOrCallingUserId()); } public int getRequestedPasswordMinimumNonLetter() { - return getDevicePolicyManager().getPasswordMinimumNonLetter(null); + return getDevicePolicyManager().getPasswordMinimumNonLetter(null, + getCurrentOrCallingUserId()); } + /** * Returns the actual password mode, as set by keyguard after updating the password. * * @return */ public void reportFailedPasswordAttempt() { - getDevicePolicyManager().reportFailedPasswordAttempt(); + getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId()); } public void reportSuccessfulPasswordAttempt() { - getDevicePolicyManager().reportSuccessfulPasswordAttempt(); + getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId()); } public void setCurrentUser(int userId) { @@ -249,7 +256,9 @@ public class LockPatternUtils { private int getCurrentOrCallingUserId() { int callingUid = Binder.getCallingUid(); if (callingUid == android.os.Process.SYSTEM_UID) { - return mCurrentUserId; + // TODO: This is a little inefficient. See if all users of this are able to + // handle USER_CURRENT and pass that instead. + return getCurrentUser(); } else { return UserHandle.getUserId(callingUid); } @@ -481,21 +490,21 @@ public class LockPatternUtils { deleteGallery(); setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, - pattern.size(), 0, 0, 0, 0, 0, 0); + pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId()); } else { setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK); setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); finishBiometricWeak(); dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, - 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId()); } } else { if (keyStore.isEmpty()) { keyStore.reset(); } dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, - 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, getCurrentOrCallingUserId()); } } catch (RemoteException re) { Log.e(TAG, "Couldn't save lock pattern " + re); @@ -532,7 +541,8 @@ public class LockPatternUtils { /** Update the encryption password if it is enabled **/ private void updateEncryptionPassword(String password) { DevicePolicyManager dpm = getDevicePolicyManager(); - if (dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) { + if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId()) + != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) { return; } @@ -558,7 +568,7 @@ public class LockPatternUtils { * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} */ public void saveLockPassword(String password, int quality) { - this.saveLockPassword(password, quality, false); + this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId()); } /** @@ -570,23 +580,42 @@ public class LockPatternUtils { * @param isFallback Specifies if this is a fallback to biometric weak */ public void saveLockPassword(String password, int quality, boolean isFallback) { + saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId()); + } + + /** + * Save a lock password. Does not ensure that the password is as good + * as the requested mode, but will adjust the mode to be as good as the + * pattern. + * @param password The password to save + * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} + * @param isFallback Specifies if this is a fallback to biometric weak + * @param userHandle The userId of the user to change the password for + */ + public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) { // Compute the hash final byte[] hash = passwordToHash(password); try { - getLockSettings().setLockPassword(hash, getCurrentOrCallingUserId()); + if (Process.myUid() != Process.SYSTEM_UID && userHandle != UserHandle.myUserId()) { + throw new SecurityException( + "Only the system process can save lock password for another user"); + } + getLockSettings().setLockPassword(hash, userHandle); DevicePolicyManager dpm = getDevicePolicyManager(); KeyStore keyStore = KeyStore.getInstance(); if (password != null) { - // Update the encryption password. - updateEncryptionPassword(password); + if (userHandle == UserHandle.USER_OWNER) { + // Update the encryption password. + updateEncryptionPassword(password); - // Update the keystore password - keyStore.password(password); + // Update the keystore password + keyStore.password(password); + } int computedQuality = computePasswordQuality(password); if (!isFallback) { deleteGallery(); - setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality)); + setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { int letters = 0; int uppercase = 0; @@ -612,25 +641,27 @@ public class LockPatternUtils { } dpm.setActivePasswordState(Math.max(quality, computedQuality), password.length(), letters, uppercase, lowercase, - numbers, symbols, nonletter); + numbers, symbols, nonletter, userHandle); } else { // The password is not anything. dpm.setActivePasswordState( DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, userHandle); } } else { // Case where it's a fallback for biometric weak - setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK); - setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality)); + setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, + userHandle); + setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality), + userHandle); finishBiometricWeak(); dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, - 0, 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, 0, userHandle); } // Add the password to the password history. We assume all // password // hashes have the same length for simplicity of implementation. - String passwordHistory = getString(PASSWORD_HISTORY_KEY); + String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); if (passwordHistory == null) { passwordHistory = new String(); } @@ -645,7 +676,7 @@ public class LockPatternUtils { * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory .length())); } - setString(PASSWORD_HISTORY_KEY, passwordHistory); + setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle); } else { // Conditionally reset the keystore if empty. If // non-empty, we are just switching key guard type @@ -653,7 +684,8 @@ public class LockPatternUtils { keyStore.reset(); } dpm.setActivePasswordState( - DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0); + DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, + userHandle); } } catch (RemoteException re) { // Cant do much @@ -849,7 +881,7 @@ public class LockPatternUtils { if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) { return false; } - if (getDevicePolicyManager().getCameraDisabled(null)) { + if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) { return false; } @@ -1027,6 +1059,10 @@ public class LockPatternUtils { } private void setLong(String secureSettingKey, long value) { + setLong(secureSettingKey, value, getCurrentOrCallingUserId()); + } + + private void setLong(String secureSettingKey, long value, int userHandle) { try { getLockSettings().setLong(secureSettingKey, value, getCurrentOrCallingUserId()); } catch (RemoteException re) { @@ -1036,17 +1072,20 @@ public class LockPatternUtils { } private String getString(String secureSettingKey) { + return getString(secureSettingKey, getCurrentOrCallingUserId()); + } + + private String getString(String secureSettingKey, int userHandle) { try { - return getLockSettings().getString(secureSettingKey, null, - getCurrentOrCallingUserId()); + return getLockSettings().getString(secureSettingKey, null, userHandle); } catch (RemoteException re) { return null; } } - private void setString(String secureSettingKey, String value) { + private void setString(String secureSettingKey, String value, int userHandle) { try { - getLockSettings().setString(secureSettingKey, value, getCurrentOrCallingUserId()); + getLockSettings().setString(secureSettingKey, value, userHandle); } catch (RemoteException re) { // What can we do? Log.e(TAG, "Couldn't write string " + secureSettingKey + re); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index 47ec243eeea1d..49c439b9cd779 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -33,6 +33,7 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; import android.os.Looper; +import android.os.UserHandle; import android.os.UserManager; import android.util.AttributeSet; import android.util.Log; @@ -344,7 +345,7 @@ public class KeyguardHostView extends KeyguardViewBase { final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern; final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager() - .getMaximumFailedPasswordsForWipe(null); + .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser()); final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; @@ -678,7 +679,7 @@ public class KeyguardHostView extends KeyguardViewBase { private void maybePopulateWidgets() { DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - if (dpm != null && dpm.getKeyguardWidgetsDisabled(null) + if (dpm != null && dpm.getKeyguardWidgetsDisabled(null, mLockPatternUtils.getCurrentUser()) != DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_NONE) { Log.v(TAG, "Keyguard widgets disabled because of device policy admin"); return; diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java index 75542361ed4f0..dc20e746e97e4 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java @@ -191,8 +191,9 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri } private void updateTargets() { + int currentUserHandle = mLockPatternUtils.getCurrentUser(); boolean disabledByAdmin = mLockPatternUtils.getDevicePolicyManager() - .getCameraDisabled(null); + .getCameraDisabled(null, currentUserHandle); final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext()); boolean disabledBySimState = monitor.isSimLocked(); boolean cameraTargetPresent = diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java index 372b0fc802c1d..035465a3d54cf 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java @@ -559,7 +559,7 @@ public class KeyguardViewMediator { // From DevicePolicyAdmin final long policyTimeout = mLockPatternUtils.getDevicePolicyManager() - .getMaximumTimeToLock(null); + .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser()); long timeout; if (policyTimeout > 0) { diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 28a4310734c51..aec5d6ed2555b 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -16,7 +16,6 @@ package com.android.server; -import com.android.internal.content.PackageMonitor; import com.android.internal.os.storage.ExternalStorageFormatter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; @@ -28,7 +27,9 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.app.Activity; +import android.app.ActivityManagerNative; import android.app.AlarmManager; +import android.app.AppGlobals; import android.app.PendingIntent; import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminReceiver; @@ -40,6 +41,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; @@ -49,6 +51,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IPowerManager; import android.os.PowerManager; +import android.os.Process; import android.os.RecoverySystem; import android.os.RemoteCallback; import android.os.RemoteException; @@ -56,10 +59,12 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; +import android.util.SparseArray; import android.util.Xml; import android.view.IWindowManager; import android.view.WindowManagerPolicy; @@ -82,56 +87,86 @@ import java.util.Set; * Implementation of the device policy APIs. */ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + private static final String DEVICE_POLICIES_XML = "device_policies.xml"; + private static final String TAG = "DevicePolicyManagerService"; private static final int REQUEST_EXPIRE_PASSWORD = 5571; - private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms + private static final long MS_PER_DAY = 86400 * 1000; + + private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; - private static final long MS_PER_DAY = 86400 * 1000; + private static final boolean DBG = false; final Context mContext; - final MyPackageMonitor mMonitor; final PowerManager.WakeLock mWakeLock; IPowerManager mIPowerManager; IWindowManager mIWindowManager; - int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - int mActivePasswordLength = 0; - int mActivePasswordUpperCase = 0; - int mActivePasswordLowerCase = 0; - int mActivePasswordLetters = 0; - int mActivePasswordNumeric = 0; - int mActivePasswordSymbols = 0; - int mActivePasswordNonLetter = 0; - int mFailedPasswordAttempts = 0; + public static class DevicePolicyData { + int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + int mActivePasswordLength = 0; + int mActivePasswordUpperCase = 0; + int mActivePasswordLowerCase = 0; + int mActivePasswordLetters = 0; + int mActivePasswordNumeric = 0; + int mActivePasswordSymbols = 0; + int mActivePasswordNonLetter = 0; + int mFailedPasswordAttempts = 0; + + int mUserHandle;; + int mPasswordOwner = -1; + long mLastMaximumTimeToLock = -1; + + final HashMap mAdminMap + = new HashMap(); + final ArrayList mAdminList + = new ArrayList(); + + public DevicePolicyData(int userHandle) { + mUserHandle = userHandle; + } + } + + final SparseArray mUserData = new SparseArray(); - int mPasswordOwner = -1; Handler mHandler = new Handler(); - long mLastMaximumTimeToLock = -1; - - final HashMap mAdminMap - = new HashMap(); - final ArrayList mAdminList - = new ArrayList(); - BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); + final String action = intent.getAction(); + final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + getSendingUserId()); if (Intent.ACTION_BOOT_COMPLETED.equals(action) || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) { - Slog.v(TAG, "Sending password expiration notifications for action " + action); + Slog.v(TAG, "Sending password expiration notifications for action " + action + + " for user " + userHandle); mHandler.post(new Runnable() { public void run() { - handlePasswordExpirationNotification(); + handlePasswordExpirationNotification(getUserData(userHandle)); } }); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + removeUserData(userHandle); + } else if (Intent.ACTION_USER_STARTED.equals(action) + || Intent.ACTION_PACKAGE_CHANGED.equals(action) + || Intent.ACTION_PACKAGE_REMOVED.equals(action) + || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { + + if (Intent.ACTION_USER_STARTED.equals(action)) { + // Reset the policy data + synchronized (DevicePolicyManagerService.this) { + mUserData.remove(userHandle); + } + } + + handlePackagesChanged(userHandle); } } }; @@ -194,6 +229,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int getUid() { return info.getActivityInfo().applicationInfo.uid; } + public UserHandle getUserHandle() { + return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid)); + } + void writeToXml(XmlSerializer out) throws IllegalArgumentException, IllegalStateException, IOException { out.startTag(null, "policies"); @@ -421,39 +460,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - class MyPackageMonitor extends PackageMonitor { - @Override - public void onSomePackagesChanged() { - synchronized (DevicePolicyManagerService.this) { - boolean removed = false; - for (int i=mAdminList.size()-1; i>=0; i--) { - ActiveAdmin aa = mAdminList.get(i); - int change = isPackageDisappearing(aa.info.getPackageName()); - if (change == PACKAGE_PERMANENT_CHANGE - || change == PACKAGE_TEMPORARY_CHANGE) { - Slog.w(TAG, "Admin unexpectedly uninstalled: " - + aa.info.getComponent()); - removed = true; - mAdminList.remove(i); - } else if (isPackageModified(aa.info.getPackageName())) { - try { - mContext.getPackageManager().getReceiverInfo( - aa.info.getComponent(), 0); - } catch (NameNotFoundException e) { - Slog.w(TAG, "Admin package change removed component: " - + aa.info.getComponent()); - removed = true; - mAdminList.remove(i); - } - } - } - if (removed) { - validatePasswordOwnerLocked(); - syncDeviceCapabilitiesLocked(); - saveSettingsLocked(); + private void handlePackagesChanged(int userHandle) { + boolean removed = false; + Slog.d(TAG, "Handling package changes for user " + userHandle); + DevicePolicyData policy = getUserData(userHandle); + IPackageManager pm = AppGlobals.getPackageManager(); + for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { + ActiveAdmin aa = policy.mAdminList.get(i); + try { + if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null + || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) { + removed = true; + policy.mAdminList.remove(i); } + } catch (RemoteException re) { + // Shouldn't happen } } + if (removed) { + validatePasswordOwnerLocked(policy); + syncDeviceCapabilitiesLocked(policy); + saveSettingsLocked(policy.mUserHandle); + } } /** @@ -461,22 +489,62 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ public DevicePolicyManagerService(Context context) { mContext = context; - mMonitor = new MyPackageMonitor(); - mMonitor.register(context, null, true); mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)) .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM"); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); - context.registerReceiver(mReceiver, filter); + filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_STARTED); + context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); + filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + filter.addDataScheme("package"); + context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); + } + + /** + * Creates and loads the policy data from xml. + * @param userHandle the user for whom to load the policy data + * @return + */ + DevicePolicyData getUserData(int userHandle) { + synchronized (this) { + DevicePolicyData policy = mUserData.get(userHandle); + if (policy == null) { + policy = new DevicePolicyData(userHandle); + mUserData.append(userHandle, policy); + loadSettingsLocked(policy, userHandle); + } + return policy; + } + } + + void removeUserData(int userHandle) { + synchronized (this) { + if (userHandle == UserHandle.USER_OWNER) { + Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring."); + return; + } + DevicePolicyData policy = mUserData.get(userHandle); + if (policy != null) { + mUserData.remove(userHandle); + } + File policyFile = new File(Environment.getUserSystemDirectory(userHandle), + DEVICE_POLICIES_XML); + policyFile.delete(); + Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath()); + } } /** * 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) { - final long expiration = getPasswordExpirationLocked(null); + protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) { + final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle); final long now = System.currentTimeMillis(); final long timeToExpire = expiration - now; final long alarmTime; @@ -499,9 +567,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long token = Binder.clearCallingIdentity(); try { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD, + PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD, new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION), - PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT, + new UserHandle(policy.mUserHandle)); am.cancel(pi); if (alarmTime != 0) { am.set(AlarmManager.RTC, alarmTime, pi); @@ -527,8 +596,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mIWindowManager; } - ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) { - ActiveAdmin admin = mAdminMap.get(who); + ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) { + ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who); if (admin != null && who.getPackageName().equals(admin.info.getActivityInfo().packageName) && who.getClassName().equals(admin.info.getActivityInfo().name)) { @@ -540,8 +609,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { final int callingUid = Binder.getCallingUid(); + final int userHandle = UserHandle.getUserId(callingUid); + final DevicePolicyData policy = getUserData(userHandle); if (who != null) { - ActiveAdmin admin = mAdminMap.get(who); + ActiveAdmin admin = policy.mAdminMap.get(who); if (admin == null) { throw new SecurityException("No active admin " + who); } @@ -556,9 +627,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return admin; } else { - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i 0) { - for (int i=0; i 0) { + for (int i = 0; i < count; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.info.usesPolicy(reqPolicy)) { sendAdminCommandLocked(admin, action); } @@ -598,8 +670,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - void removeActiveAdminLocked(final ComponentName adminReceiver) { - final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); + void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) { + final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin != null) { sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED, @@ -607,28 +679,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void onReceive(Context context, Intent intent) { synchronized (DevicePolicyManagerService.this) { + int userHandle = admin.getUserHandle().getIdentifier(); + DevicePolicyData policy = getUserData(userHandle); boolean doProxyCleanup = admin.info.usesPolicy( DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); - mAdminList.remove(admin); - mAdminMap.remove(adminReceiver); - validatePasswordOwnerLocked(); - syncDeviceCapabilitiesLocked(); + policy.mAdminList.remove(admin); + policy.mAdminMap.remove(adminReceiver); + validatePasswordOwnerLocked(policy); + syncDeviceCapabilitiesLocked(policy); if (doProxyCleanup) { - resetGlobalProxyLocked(); + resetGlobalProxyLocked(getUserData(userHandle)); } - saveSettingsLocked(); - updateMaximumTimeToLockLocked(); + saveSettingsLocked(userHandle); + updateMaximumTimeToLockLocked(policy); } } }); } } - public DeviceAdminInfo findAdmin(ComponentName adminName) { + public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) { + enforceCrossUserPermission(userHandle); Intent resolveIntent = new Intent(); resolveIntent.setComponent(adminName); List infos = mContext.getPackageManager().queryBroadcastReceivers( - resolveIntent, PackageManager.GET_META_DATA); + resolveIntent, PackageManager.GET_META_DATA, userHandle); if (infos == null || infos.size() <= 0) { throw new IllegalArgumentException("Unknown admin: " + adminName); } @@ -636,21 +711,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { return new DeviceAdminInfo(mContext, infos.get(0)); } catch (XmlPullParserException e) { - Slog.w(TAG, "Bad device admin requested: " + adminName, e); + Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e); return null; } catch (IOException e) { - Slog.w(TAG, "Bad device admin requested: " + adminName, e); + Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e); return null; } } - private static JournaledFile makeJournaledFile() { - final String base = "/data/system/device_policies.xml"; + private static JournaledFile makeJournaledFile(int userHandle) { + final String base = userHandle == 0 + ? "/data/system/" + DEVICE_POLICIES_XML + : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML) + .getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); } - private void saveSettingsLocked() { - JournaledFile journal = makeJournaledFile(); + private void saveSettingsLocked(int userHandle) { + DevicePolicyData policy = getUserData(userHandle); + JournaledFile journal = makeJournaledFile(userHandle); FileOutputStream stream = null; try { stream = new FileOutputStream(journal.chooseForWrite(), false); @@ -660,9 +739,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.startTag(null, "policies"); - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i= 0) { + if (policy.mPasswordOwner >= 0) { out.startTag(null, "password-owner"); - out.attribute(null, "value", Integer.toString(mPasswordOwner)); + out.attribute(null, "value", Integer.toString(policy.mPasswordOwner)); out.endTag(null, "password-owner"); } - if (mFailedPasswordAttempts != 0) { + if (policy.mFailedPasswordAttempts != 0) { out.startTag(null, "failed-password-attempts"); - out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts)); + out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts)); out.endTag(null, "failed-password-attempts"); } - if (mActivePasswordQuality != 0 || mActivePasswordLength != 0 - || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0 - || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0 - || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) { + if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 + || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0 + || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0 + || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) { out.startTag(null, "active-password"); - out.attribute(null, "quality", Integer.toString(mActivePasswordQuality)); - out.attribute(null, "length", Integer.toString(mActivePasswordLength)); - out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase)); - out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase)); - out.attribute(null, "letters", Integer.toString(mActivePasswordLetters)); + out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality)); + out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength)); + out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase)); + out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase)); + out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters)); out.attribute(null, "numeric", Integer - .toString(mActivePasswordNumeric)); - out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols)); - out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter)); + .toString(policy.mActivePasswordNumeric)); + out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols)); + out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter)); out.endTag(null, "active-password"); } @@ -705,7 +784,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endDocument(); stream.close(); journal.commit(); - sendChangedNotification(); + sendChangedNotification(userHandle); } catch (IOException e) { try { if (stream != null) { @@ -718,20 +797,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void sendChangedNotification() { + private void sendChangedNotification(int userHandle) { Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); long ident = Binder.clearCallingIdentity(); try { - // TODO: This shouldn't be sent to all users, if DPM is per user. - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle)); } finally { Binder.restoreCallingIdentity(ident); } } - private void loadSettingsLocked() { - JournaledFile journal = makeJournaledFile(); + private void loadSettingsLocked(DevicePolicyData policy, int userHandle) { + JournaledFile journal = makeJournaledFile(userHandle); FileInputStream stream = null; File file = journal.chooseForRead(); try { @@ -760,40 +838,46 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String name = parser.getAttributeValue(null, "name"); try { DeviceAdminInfo dai = findAdmin( - ComponentName.unflattenFromString(name)); + ComponentName.unflattenFromString(name), userHandle); + if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) + != userHandle)) { + Slog.w(TAG, "findAdmin returned an incorrect uid " + + dai.getActivityInfo().applicationInfo.uid + " for user " + + userHandle); + } if (dai != null) { ActiveAdmin ap = new ActiveAdmin(dai); ap.readFromXml(parser); - mAdminMap.put(ap.info.getComponent(), ap); - mAdminList.add(ap); + policy.mAdminMap.put(ap.info.getComponent(), ap); + policy.mAdminList.add(ap); } } catch (RuntimeException e) { Slog.w(TAG, "Failed loading admin " + name, e); } } else if ("failed-password-attempts".equals(tag)) { - mFailedPasswordAttempts = Integer.parseInt( + policy.mFailedPasswordAttempts = Integer.parseInt( parser.getAttributeValue(null, "value")); XmlUtils.skipCurrentTag(parser); } else if ("password-owner".equals(tag)) { - mPasswordOwner = Integer.parseInt( + policy.mPasswordOwner = Integer.parseInt( parser.getAttributeValue(null, "value")); XmlUtils.skipCurrentTag(parser); } else if ("active-password".equals(tag)) { - mActivePasswordQuality = Integer.parseInt( + policy.mActivePasswordQuality = Integer.parseInt( parser.getAttributeValue(null, "quality")); - mActivePasswordLength = Integer.parseInt( + policy.mActivePasswordLength = Integer.parseInt( parser.getAttributeValue(null, "length")); - mActivePasswordUpperCase = Integer.parseInt( + policy.mActivePasswordUpperCase = Integer.parseInt( parser.getAttributeValue(null, "uppercase")); - mActivePasswordLowerCase = Integer.parseInt( + policy.mActivePasswordLowerCase = Integer.parseInt( parser.getAttributeValue(null, "lowercase")); - mActivePasswordLetters = Integer.parseInt( + policy.mActivePasswordLetters = Integer.parseInt( parser.getAttributeValue(null, "letters")); - mActivePasswordNumeric = Integer.parseInt( + policy.mActivePasswordNumeric = Integer.parseInt( parser.getAttributeValue(null, "numeric")); - mActivePasswordSymbols = Integer.parseInt( + policy.mActivePasswordSymbols = Integer.parseInt( parser.getAttributeValue(null, "symbols")); - mActivePasswordNonLetter = Integer.parseInt( + policy.mActivePasswordNonLetter = Integer.parseInt( parser.getAttributeValue(null, "nonletter")); XmlUtils.skipCurrentTag(parser); } else { @@ -827,24 +911,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // a sanity check in case the two get out of sync; this should // never normally happen. LockPatternUtils utils = new LockPatternUtils(mContext); - if (utils.getActivePasswordQuality() < mActivePasswordQuality) { + if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) { Slog.w(TAG, "Active password quality 0x" - + Integer.toHexString(mActivePasswordQuality) + + Integer.toHexString(policy.mActivePasswordQuality) + " does not match actual quality 0x" + Integer.toHexString(utils.getActivePasswordQuality())); - mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - mActivePasswordLength = 0; - mActivePasswordUpperCase = 0; - mActivePasswordLowerCase = 0; - mActivePasswordLetters = 0; - mActivePasswordNumeric = 0; - mActivePasswordSymbols = 0; - mActivePasswordNonLetter = 0; + policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + policy.mActivePasswordLength = 0; + policy.mActivePasswordUpperCase = 0; + policy.mActivePasswordLowerCase = 0; + policy.mActivePasswordLetters = 0; + policy.mActivePasswordNumeric = 0; + policy.mActivePasswordSymbols = 0; + policy.mActivePasswordNonLetter = 0; } - validatePasswordOwnerLocked(); - syncDeviceCapabilitiesLocked(); - updateMaximumTimeToLockLocked(); + validatePasswordOwnerLocked(policy); + syncDeviceCapabilitiesLocked(policy); + updateMaximumTimeToLockLocked(policy); } static void validateQualityConstant(int quality) { @@ -862,19 +946,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + Integer.toHexString(quality)); } - void validatePasswordOwnerLocked() { - if (mPasswordOwner >= 0) { + void validatePasswordOwnerLocked(DevicePolicyData policy) { + if (policy.mPasswordOwner >= 0) { boolean haveOwner = false; - for (int i=mAdminList.size()-1; i>=0; i--) { - if (mAdminList.get(i).getUid() == mPasswordOwner) { + for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { + if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) { haveOwner = true; break; } } if (!haveOwner) { - Slog.w(TAG, "Previous password owner " + mPasswordOwner + Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner + " no longer active; disabling"); - mPasswordOwner = -1; + policy.mPasswordOwner = -1; } } } @@ -883,11 +967,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Pushes down policy information to the system for any policies related to general device * capabilities that need to be enforced by lower level services (e.g. Camera services). */ - void syncDeviceCapabilitiesLocked() { + void syncDeviceCapabilitiesLocked(DevicePolicyData policy) { // Ensure the status of the camera is synced down to the system. Interested native services // should monitor this value and act accordingly. boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false); - boolean cameraDisabled = getCameraDisabled(null); + boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle); if (cameraDisabled != systemState) { long token = Binder.clearCallingIdentity(); try { @@ -903,19 +987,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void systemReady() { synchronized (this) { - loadSettingsLocked(); + loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER); } } - private void handlePasswordExpirationNotification() { + private void handlePasswordExpirationNotification(DevicePolicyData policy) { synchronized (this) { final long now = System.currentTimeMillis(); - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); if (N <= 0) { return; } for (int i=0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) && admin.passwordExpirationTimeout > 0L && admin.passwordExpirationDate > 0L @@ -923,7 +1007,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); } } - setExpirationAlarmCheckLocked(mContext); + setExpirationAlarmCheckLocked(mContext, policy); } } @@ -931,27 +1015,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * @param adminReceiver The admin to add * @param refreshing true = update an active admin, no error */ - public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) { + public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); + enforceCrossUserPermission(userHandle); - DeviceAdminInfo info = findAdmin(adminReceiver); + DevicePolicyData policy = getUserData(userHandle); + DeviceAdminInfo info = findAdmin(adminReceiver, userHandle); if (info == null) { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } synchronized (this) { long ident = Binder.clearCallingIdentity(); try { - if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) { + if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { throw new IllegalArgumentException("Admin is already added"); } ActiveAdmin newAdmin = new ActiveAdmin(info); - mAdminMap.put(adminReceiver, newAdmin); + policy.mAdminMap.put(adminReceiver, newAdmin); int replaceIndex = -1; if (refreshing) { - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i < N; i++) { - ActiveAdmin oldAdmin = mAdminList.get(i); + ActiveAdmin oldAdmin = policy.mAdminList.get(i); if (oldAdmin.info.getComponent().equals(adminReceiver)) { replaceIndex = i; break; @@ -959,11 +1045,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } if (replaceIndex == -1) { - mAdminList.add(newAdmin); + policy.mAdminList.add(newAdmin); } else { - mAdminList.set(replaceIndex, newAdmin); + policy.mAdminList.set(replaceIndex, newAdmin); } - saveSettingsLocked(); + saveSettingsLocked(userHandle); sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED); } finally { Binder.restoreCallingIdentity(ident); @@ -971,15 +1057,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public boolean isAdminActive(ComponentName adminReceiver) { + public boolean isAdminActive(ComponentName adminReceiver, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - return getActiveAdminUncheckedLocked(adminReceiver) != null; + return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null; } } - public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) { + public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver); + ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (administrator == null) { throw new SecurityException("No active admin " + adminReceiver); } @@ -987,25 +1075,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public List getActiveAdmins() { + public List getActiveAdmins(int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); if (N <= 0) { return null; } ArrayList res = new ArrayList(N); for (int i=0; i admin.passwordExpirationTimeout)) { timeout = admin.passwordExpirationTimeout; @@ -1188,16 +1294,17 @@ 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) { + private long getPasswordExpirationLocked(ComponentName who, int userHandle) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.passwordExpirationDate : 0L; } long timeout = 0L; - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (timeout == 0L || (admin.passwordExpirationDate != 0 && timeout > admin.passwordExpirationDate)) { timeout = admin.passwordExpirationDate; @@ -1206,13 +1313,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return timeout; } - public long getPasswordExpiration(ComponentName who) { + public long getPasswordExpiration(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - return getPasswordExpirationLocked(who); + return getPasswordExpirationLocked(who, userHandle); } } - public void setPasswordMinimumUpperCase(ComponentName who, int length) { + public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1221,23 +1330,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordUpperCase != length) { ap.minimumPasswordUpperCase = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumUpperCase(ComponentName who) { + public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordUpperCase : length; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i= getPasswordMinimumUpperCase(null) - && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null) - && mActivePasswordLetters >= getPasswordMinimumLetters(null) - && mActivePasswordNumeric >= getPasswordMinimumNumeric(null) - && mActivePasswordSymbols >= getPasswordMinimumSymbols(null) - && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null); + 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); } } - public int getCurrentFailedPasswordAttempts() { + public int getCurrentFailedPasswordAttempts(int userHandle) { + enforceCrossUserPermission(userHandle); 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); - return mFailedPasswordAttempts; + return getUserData(userHandle).mFailedPasswordAttempts; } } - public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) { + public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) { + enforceCrossUserPermission(userHandle); 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. @@ -1458,23 +1588,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); if (ap.maximumFailedPasswordsForWipe != num) { ap.maximumFailedPasswordsForWipe = num; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getMaximumFailedPasswordsForWipe(ComponentName who) { + public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); int count = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.maximumFailedPasswordsForWipe : count; } - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i= 0 && mPasswordOwner != callingUid) { + DevicePolicyData policy = getUserData(userHandle); + if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) { Slog.w(TAG, "resetPassword: already set by another uid and not entered by user"); return false; } @@ -1590,13 +1724,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long ident = Binder.clearCallingIdentity(); try { LockPatternUtils utils = new LockPatternUtils(mContext); - utils.saveLockPassword(password, quality); + utils.saveLockPassword(password, quality, false, userHandle); synchronized (this) { int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0 ? callingUid : -1; - if (mPasswordOwner != newOwner) { - mPasswordOwner = newOwner; - saveSettingsLocked(); + if (policy.mPasswordOwner != newOwner) { + policy.mPasswordOwner = newOwner; + saveSettingsLocked(userHandle); } } } finally { @@ -1606,7 +1740,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return true; } - public void setMaximumTimeToLock(ComponentName who, long timeMs) { + public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1615,15 +1750,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_FORCE_LOCK); if (ap.maximumTimeToUnlock != timeMs) { ap.maximumTimeToUnlock = timeMs; - saveSettingsLocked(); - updateMaximumTimeToLockLocked(); + saveSettingsLocked(userHandle); + updateMaximumTimeToLockLocked(getUserData(userHandle)); } } } - void updateMaximumTimeToLockLocked() { - long timeMs = getMaximumTimeToLock(null); - if (mLastMaximumTimeToLock == timeMs) { + void updateMaximumTimeToLockLocked(DevicePolicyData policy) { + long timeMs = getMaximumTimeToLock(null, policy.mUserHandle); + if (policy.mLastMaximumTimeToLock == timeMs) { return; } @@ -1638,7 +1773,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); } - mLastMaximumTimeToLock = timeMs; + policy.mLastMaximumTimeToLock = timeMs; try { getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs); @@ -1650,18 +1785,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public long getMaximumTimeToLock(ComponentName who) { + public long getMaximumTimeToLock(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { long time = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.maximumTimeToUnlock : time; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i 0) { for (int i=0; i 0L ? (timeout + System.currentTimeMillis()) : 0L; admin.passwordExpirationDate = expiration; } } - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } - public void reportFailedPasswordAttempt() { + public void reportFailedPasswordAttempt(int userHandle) { + enforceCrossUserPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); long ident = Binder.clearCallingIdentity(); try { - mFailedPasswordAttempts++; - saveSettingsLocked(); - int max = getMaximumFailedPasswordsForWipe(null); - if (max > 0 && mFailedPasswordAttempts >= max) { + policy.mFailedPasswordAttempts++; + saveSettingsLocked(userHandle); + int max = getMaximumFailedPasswordsForWipe(null, userHandle); + if (max > 0 && policy.mFailedPasswordAttempts >= max) { wipeDataLocked(0); } sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED, - DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); + DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } finally { Binder.restoreCallingIdentity(ident); } } } - public void reportSuccessfulPasswordAttempt() { + public void reportSuccessfulPasswordAttempt(int userHandle) { + enforceCrossUserPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); synchronized (this) { - if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) { + DevicePolicyData policy = getUserData(userHandle); + if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) { long ident = Binder.clearCallingIdentity(); try { - mFailedPasswordAttempts = 0; - mPasswordOwner = -1; - saveSettingsLocked(); + policy.mFailedPasswordAttempts = 0; + policy.mPasswordOwner = -1; + saveSettingsLocked(userHandle); sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, - DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); + DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } finally { Binder.restoreCallingIdentity(ident); } @@ -1858,26 +2023,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public ComponentName setGlobalProxy(ComponentName who, String proxySpec, - String exclusionList) { + String exclusionList, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized(this) { if (who == null) { throw new NullPointerException("ComponentName is null"); } + // Only check if owner has set global proxy. We don't allow other users to set it. + DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); // Scan through active admins and find if anyone has already // set the global proxy. - Set compSet = mAdminMap.keySet(); + Set compSet = policy.mAdminMap.keySet(); for (ComponentName component : compSet) { - ActiveAdmin ap = mAdminMap.get(component); + ActiveAdmin ap = policy.mAdminMap.get(component); if ((ap.specifiesGlobalProxy) && (!component.equals(who))) { // Another admin already sets the global proxy // Return it to the caller. return component; } } + + // If the user is not the owner, don't set the global proxy. Fail silently. + if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { + Slog.w(TAG, "Only the owner is allowed to set the global proxy. User " + + userHandle + " is not permitted."); + return null; + } if (proxySpec == null) { admin.specifiesGlobalProxy = false; admin.globalProxySpec = null; @@ -1892,19 +2067,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Reset the global proxy accordingly // Do this using system permissions, as apps cannot write to secure settings long origId = Binder.clearCallingIdentity(); - resetGlobalProxyLocked(); + resetGlobalProxyLocked(policy); Binder.restoreCallingIdentity(origId); return null; } } - public ComponentName getGlobalProxyAdmin() { + public ComponentName getGlobalProxyAdmin(int userHandle) { + enforceCrossUserPermission(userHandle); synchronized(this) { + DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); // Scan through active admins and find if anyone has already // set the global proxy. - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin ap = mAdminList.get(i); + ActiveAdmin ap = policy.mAdminList.get(i); if (ap.specifiesGlobalProxy) { // Device admin sets the global proxy // Return it to the caller. @@ -1916,10 +2093,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } - private void resetGlobalProxyLocked() { - final int N = mAdminList.size(); + private void resetGlobalProxyLocked(DevicePolicyData policy) { + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin ap = mAdminList.get(i); + ActiveAdmin ap = policy.mAdminList.get(i); if (ap.specifiesGlobalProxy) { saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList); return; @@ -1957,12 +2134,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Set the storage encryption request for a single admin. Returns the new total request * status (for all admins). */ - public int setStorageEncryption(ComponentName who, boolean encrypt) { + public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { // Check for permissions if (who == null) { throw new NullPointerException("ComponentName is null"); } + // Only owner can set storage encryption + if (userHandle != UserHandle.USER_OWNER + || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { + Slog.w(TAG, "Only owner is allowed to set storage encryption. User " + + UserHandle.getCallingUserId() + " is not permitted."); + return 0; + } + ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_ENCRYPTED_STORAGE); @@ -1974,14 +2160,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // (1) Record the value for the admin so it's sticky if (ap.encryptionRequested != encrypt) { ap.encryptionRequested = encrypt; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } + DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); // (2) Compute "max" for all admins boolean newRequested = false; - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - newRequested |= mAdminList.get(i).encryptionRequested; + newRequested |= policy.mAdminList.get(i).encryptionRequested; } // Notify OS of new request @@ -1998,20 +2185,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Get the current storage encryption request status for a given admin, or aggregate of all * active admins. */ - public boolean getStorageEncryption(ComponentName who) { + public boolean getStorageEncryption(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { // Check for permissions if a particular caller is specified if (who != null) { // When checking for a single caller, status is based on caller's request - ActiveAdmin ap = getActiveAdminUncheckedLocked(who); + ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle); return ap != null ? ap.encryptionRequested : false; } // If no particular caller is specified, return the aggregate set of requests. // This is short circuited by returning true on the first hit. - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - if (mAdminList.get(i).encryptionRequested) { + if (policy.mAdminList.get(i).encryptionRequested) { return true; } } @@ -2022,7 +2211,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Get the current encryption status of the device. */ - public int getStorageEncryptionStatus() { + public int getStorageEncryptionStatus(int userHandle) { + enforceCrossUserPermission(userHandle); return getEncryptionStatus(); } @@ -2069,7 +2259,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Disables all device cameras according to the specified admin. */ - public void setCameraDisabled(ComponentName who, boolean disabled) { + public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -2078,9 +2269,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); if (ap.disableCamera != disabled) { ap.disableCamera = disabled; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } - syncDeviceCapabilitiesLocked(); + syncDeviceCapabilitiesLocked(getUserData(userHandle)); } } @@ -2088,17 +2279,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Gets whether or not all device cameras are disabled for a given admin, or disabled for any * active admins. */ - public boolean getCameraDisabled(ComponentName who) { + public boolean getCameraDisabled(ComponentName who, int userHandle) { synchronized (this) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return (admin != null) ? admin.disableCamera : false; } + DevicePolicyData policy = getUserData(userHandle); // Determine whether or not the device camera is disabled for any active admins. - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.disableCamera) { return true; } @@ -2110,7 +2302,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Selectively disable keyguard widgets. */ - public void setKeyguardWidgetsDisabled(ComponentName who, int which) { + public void setKeyguardWidgetsDisabled(ComponentName who, int which, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -2119,9 +2312,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS); if ((ap.disableKeyguardWidgets & which) != which) { ap.disableKeyguardWidgets |= which; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } - syncDeviceCapabilitiesLocked(); + syncDeviceCapabilitiesLocked(getUserData(userHandle)); } } @@ -2129,24 +2322,39 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Gets the disabled state for widgets in keyguard for the given admin, * or the aggregate of all active admins if who is null. */ - public int getKeyguardWidgetsDisabled(ComponentName who) { + public int getKeyguardWidgetsDisabled(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return (admin != null) ? admin.disableKeyguardWidgets : 0; } // Determine whether or not keyguard widgets are disabled for any active admins. - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); int which = 0; for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); which |= admin.disableKeyguardWidgets; } return which; } } + private void enforceCrossUserPermission(int userHandle) { + if (userHandle < 0) { + throw new IllegalArgumentException("Invalid userId " + userHandle); + } + final int callingUid = Binder.getCallingUid(); + if (userHandle == UserHandle.getUserId(callingUid)) return; + if (callingUid != Process.SYSTEM_UID && callingUid != 0) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have" + + " INTERACT_ACROSS_USERS_FULL permission"); + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -2163,19 +2371,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { p.println("Current Device Policy Manager state:"); - p.println(" Enabled Device Admins:"); - final int N = mAdminList.size(); - for (int i=0; i