From 3255823de062e981f7bfc7994919207988697e45 Mon Sep 17 00:00:00 2001 From: Konstantin Lopyrev Date: Thu, 20 May 2010 16:18:05 -0700 Subject: [PATCH] Fix 2673731: Adding support for password history to Device Admin. Change-Id: If3240048813e32b2bae79fe5cb8a73aea20ec56c --- api/current.xml | 28 +++ .../app/admin/DevicePolicyManager.java | 173 +++++++++----- .../app/admin/IDevicePolicyManager.aidl | 3 + .../internal/widget/LockPatternUtils.java | 43 ++-- .../server/DevicePolicyManagerService.java | 211 +++++++++++------- 5 files changed, 300 insertions(+), 158 deletions(-) diff --git a/api/current.xml b/api/current.xml index 4893ff9508e7f..ce170e719b939 100644 --- a/api/current.xml +++ b/api/current.xml @@ -31730,6 +31730,19 @@ + + + + + + + + + + You can optionally include the {@link #EXTRA_ADD_EXPLANATION} * field to provide the user with additional explanation (in addition * to your component's description) about what is being added. @@ -76,14 +76,14 @@ public class DevicePolicyManager { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"; - + /** * The ComponentName of the administrator component. * * @see #ACTION_ADD_DEVICE_ADMIN */ public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN"; - + /** * An optional CharSequence providing additional explanation for why the * admin is being added. @@ -91,22 +91,21 @@ public class DevicePolicyManager { * @see #ACTION_ADD_DEVICE_ADMIN */ public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION"; - + /** - * Activity action: have the user enter a new password. This activity - * should be launched after using {@link #setPasswordQuality(ComponentName, int)} - * or {@link #setPasswordMinimumLength(ComponentName, int)} to have the - * user enter a new password that meets the current requirements. You can - * use {@link #isActivePasswordSufficient()} to determine whether you need - * to have the user select a new password in order to meet the current - * constraints. Upon being resumed from this activity, - * you can check the new password characteristics to see if they are - * sufficient. + * Activity action: have the user enter a new password. This activity should + * be launched after using {@link #setPasswordQuality(ComponentName, int)}, + * or {@link #setPasswordMinimumLength(ComponentName, int)} to have the user + * enter a new password that meets the current requirements. You can use + * {@link #isActivePasswordSufficient()} to determine whether you need to + * have the user select a new password in order to meet the current + * constraints. Upon being resumed from this activity, you can check the new + * password characteristics to see if they are sufficient. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD"; - + /** * Return true if the given administrator component is currently * active (enabled) in the system. @@ -121,7 +120,7 @@ public class DevicePolicyManager { } return false; } - + /** * Return a list of all currently active device administrator's component * names. Note that if there are no administrators than null may be @@ -137,7 +136,7 @@ public class DevicePolicyManager { } return null; } - + /** * @hide */ @@ -151,7 +150,7 @@ public class DevicePolicyManager { } return false; } - + /** * Remove a current administration component. This can only be called * by the application that owns the administration component; if you @@ -167,28 +166,28 @@ public class DevicePolicyManager { } } } - + /** * Constant for {@link #setPasswordQuality}: the policy has no requirements * for the password. Note that quality constants are ordered so that higher * values are more restrictive. */ public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; - + /** * Constant for {@link #setPasswordQuality}: the policy requires some kind * of password, but doesn't care what it is. Note that quality constants * are ordered so that higher values are more restrictive. */ public static final int PASSWORD_QUALITY_SOMETHING = 0x10000; - + /** * Constant for {@link #setPasswordQuality}: the user must have entered a * password containing at least numeric characters. Note that quality * constants are ordered so that higher values are more restrictive. */ public static final int PASSWORD_QUALITY_NUMERIC = 0x20000; - + /** * Constant for {@link #setPasswordQuality}: the user must have entered a * password containing at least alphabetic (or other symbol) characters. @@ -196,7 +195,7 @@ public class DevicePolicyManager { * restrictive. */ public static final int PASSWORD_QUALITY_ALPHABETIC = 0x40000; - + /** * Constant for {@link #setPasswordQuality}: the user must have entered a * password containing at least both> numeric and @@ -204,7 +203,7 @@ public class DevicePolicyManager { * ordered so that higher values are more restrictive. */ public static final int PASSWORD_QUALITY_ALPHANUMERIC = 0x50000; - + /** * Called by an application that is administering the device to set the * password restrictions it is imposing. After setting this, the user @@ -213,16 +212,16 @@ public class DevicePolicyManager { * will remain until the user has set a new one, so the change does not * take place immediately. To prompt the user for a new password, use * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. - * + * *

Quality constants are ordered so that higher values are more restrictive; * thus the highest requested quality constant (between the policy set here, * the user's preference, and any other considerations) is the one that * is in effect. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. - * + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param quality The new desired quality. One of * {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING}, @@ -238,7 +237,7 @@ public class DevicePolicyManager { } } } - + /** * Retrieve the current minimum password quality for all admins * or a particular one. @@ -255,7 +254,7 @@ public class DevicePolicyManager { } return PASSWORD_QUALITY_UNSPECIFIED; } - + /** * Called by an application that is administering the device to set the * minimum allowed password length. After setting this, the user @@ -268,11 +267,11 @@ public class DevicePolicyManager { * {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_ALPHABETIC}, * or {@link #PASSWORD_QUALITY_ALPHANUMERIC} * with {@link #setPasswordQuality}. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. - * + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param length The new desired minimum password length. A value of 0 * means there is no restriction. @@ -286,7 +285,7 @@ public class DevicePolicyManager { } } } - + /** * Retrieve the current minimum password length for all admins * or a particular one. @@ -303,7 +302,57 @@ public class DevicePolicyManager { } return 0; } - + + /** + * Called by an application that is administering the device to set the length + * of the password history. After setting this, the user will not be able to + * enter a new password that is the same as any password in the history. Note + * that the current password will remain until the user has set a new one, so + * the change does not take place immediately. To prompt the user for a new + * password, use {@link #ACTION_SET_NEW_PASSWORD} after setting this value. + * This constraint is only imposed if the administrator has also requested + * either {@link #PASSWORD_QUALITY_NUMERIC}, + * {@link #PASSWORD_QUALITY_ALPHABETIC}, or + * {@link #PASSWORD_QUALITY_ALPHANUMERIC} with {@link #setPasswordQuality}. + * + *

+ * The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this + * method; if it has not, a security exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated + * with. + * @param length The new desired length of password history. A value of 0 + * means there is no restriction. + */ + public void setPasswordHistoryLength(ComponentName admin, int length) { + if (mService != null) { + try { + mService.setPasswordHistoryLength(admin, length); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Retrieve the current password history length for all admins + * or a particular one. + * @param admin The name of the admin component to check, or null to aggregate + * all admins. + * @return The length of the password history + */ + public int getPasswordHistoryLength(ComponentName admin) { + if (mService != null) { + try { + return mService.getPasswordHistoryLength(admin); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return 0; + } + /** * Return the maximum password length that the device supports for a * particular password quality. @@ -314,16 +363,16 @@ public class DevicePolicyManager { // Kind-of arbitrary. return 16; } - + /** * Determine whether the current password the user has set is sufficient * to meet the policy requirements (quality, minimum length) that have been * requested. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. - * + * * @return Returns true if the password meets the current requirements, * else false. */ @@ -337,11 +386,11 @@ public class DevicePolicyManager { } return false; } - + /** * Retrieve the number of times the user has failed at entering a * password since that last successful password entry. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call * this method; if it has not, a security exception will be thrown. @@ -364,14 +413,14 @@ public class DevicePolicyManager { * watching for failed passwords and wiping the device, and requires * that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}}. - * + * *

To implement any other policy (e.g. wiping data for a particular * application only, erasing or revoking credentials, or reporting the * failure to a server), you should implement * {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)} * instead. Do not use this API, because if the maximum count is reached, * the device will be wiped immediately, and your callback will not be invoked. - * + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param num The number of failed password attempts at which point the * device will wipe its data. @@ -385,7 +434,7 @@ public class DevicePolicyManager { } } } - + /** * Retrieve the current maximum number of login attempts that are allowed * before the device wipes itself, for all admins @@ -403,13 +452,13 @@ public class DevicePolicyManager { } return 0; } - + /** * Flag for {@link #resetPassword}: don't allow other admins to change * the password again until the user has entered it. */ public static final int RESET_PASSWORD_REQUIRE_ENTRY = 0x0001; - + /** * Force a new device unlock password (the password needed to access the * entire device, not for individual accounts) on the user. This takes @@ -422,11 +471,11 @@ public class DevicePolicyManager { * that the password may be a stronger quality (containing alphanumeric * characters when the requested quality is only numeric), in which case * the currently active quality will be increased to match. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. - * + * * @param password The new password for the user. * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}. * @return Returns true if the password was applied, or false if it is @@ -442,16 +491,16 @@ public class DevicePolicyManager { } return false; } - + /** * Called by an application that is administering the device to set the * maximum time for user activity until the device will lock. This limits * the length that the user can set. It takes effect immediately. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call * this method; if it has not, a security exception will be thrown. - * + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param timeMs The new desired maximum time to lock in milliseconds. * A value of 0 means there is no restriction. @@ -465,7 +514,7 @@ public class DevicePolicyManager { } } } - + /** * Retrieve the current maximum time to unlock for all admins * or a particular one. @@ -482,11 +531,11 @@ public class DevicePolicyManager { } return 0; } - + /** * Make the device lock immediately, as if the lock screen timeout has * expired at the point of this call. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call * this method; if it has not, a security exception will be thrown. @@ -500,16 +549,16 @@ public class DevicePolicyManager { } } } - + /** * Ask the user date be wiped. This will cause the device to reboot, * erasing all user data while next booting up. External storage such * as SD cards will not be erased. - * + * *

The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call * this method; if it has not, a security exception will be thrown. - * + * * @param flags Bit mask of additional options: currently must be 0. */ public void wipeData(int flags) { @@ -521,7 +570,7 @@ public class DevicePolicyManager { } } } - + /** * @hide */ @@ -534,7 +583,7 @@ public class DevicePolicyManager { } } } - + /** * @hide */ @@ -547,10 +596,10 @@ public class DevicePolicyManager { Log.w(TAG, "Unable to retrieve device policy " + cn, e); return null; } - + ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; - + try { return new DeviceAdminInfo(mContext, ri); } catch (XmlPullParserException e) { @@ -561,7 +610,7 @@ public class DevicePolicyManager { return null; } } - + /** * @hide */ @@ -587,7 +636,7 @@ public class DevicePolicyManager { } } } - + /** * @hide */ @@ -600,7 +649,7 @@ public class DevicePolicyManager { } } } - + /** * @hide */ diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 6fc4dc5add605..98fc162f00580 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -31,6 +31,9 @@ interface IDevicePolicyManager { void setPasswordMinimumLength(in ComponentName who, int length); int getPasswordMinimumLength(in ComponentName who); + void setPasswordHistoryLength(in ComponentName who, int length); + int getPasswordHistoryLength(in ComponentName who); + boolean isActivePasswordSufficient(); int getCurrentFailedPasswordAttempts(); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 56bc85149be94..28684a48df5ca 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -86,12 +86,6 @@ public class LockPatternUtils { */ public static final int MIN_PATTERN_REGISTER_FAIL = 3; - /** - * The number of previous password hashes to store. This is used to prevent - * the user from setting the same password as any of the stored ones. - */ - public static final int MAX_PASSWORD_HISTORY_LENGTH = 5; - private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen"; @@ -146,6 +140,10 @@ public class LockPatternUtils { return getDevicePolicyManager().getPasswordQuality(null); } + public int getRequestedPasswordHistoryLength() { + return getDevicePolicyManager().getPasswordHistoryLength(null); + } + /** * Returns the actual password mode, as set by keyguard after updating the password. * @@ -219,7 +217,21 @@ public class LockPatternUtils { public boolean checkPasswordHistory(String password) { String passwordHashString = new String(passwordToHash(password)); String passwordHistory = getString(PASSWORD_HISTORY_KEY); - return passwordHistory != null && passwordHistory.contains(passwordHashString); + if (passwordHistory == null) { + return false; + } + // Password History may be too long... + int passwordHashLength = passwordHashString.length(); + int passwordHistoryLength = getRequestedPasswordHistoryLength(); + if(passwordHistoryLength == 0) { + return false; + } + int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength + + passwordHistoryLength - 1; + if (passwordHistory.length() > neededPasswordHistoryLength) { + passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength); + } + return passwordHistory.contains(passwordHashString); } /** @@ -413,12 +425,17 @@ public class LockPatternUtils { if (passwordHistory == null) { passwordHistory = new String(); } - passwordHistory = new String(hash) + "," + passwordHistory; - // Cut it to contain MAX_PASSWORD_HISTORY_LENGTH hashes - // and MAX_PASSWORD_HISTORY_LENGTH -1 commas. - passwordHistory = passwordHistory.substring(0, Math.min(hash.length - * MAX_PASSWORD_HISTORY_LENGTH + MAX_PASSWORD_HISTORY_LENGTH - 1, - passwordHistory.length())); + int passwordHistoryLength = getRequestedPasswordHistoryLength(); + if (passwordHistoryLength == 0) { + passwordHistory = ""; + } else { + passwordHistory = new String(hash) + "," + passwordHistory; + // Cut it to contain passwordHistoryLength hashes + // and passwordHistoryLength -1 commas. + passwordHistory = passwordHistory.substring(0, Math.min(hash.length + * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory + .length())); + } setString(PASSWORD_HISTORY_KEY, passwordHistory); } else { dpm.setActivePasswordState( diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 7fb7db09637f6..7de510ec5763a 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -67,37 +67,38 @@ import java.util.List; */ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { static final String TAG = "DevicePolicyManagerService"; - + final Context mContext; final MyPackageMonitor mMonitor; IPowerManager mIPowerManager; - + int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; int mActivePasswordLength = 0; int mFailedPasswordAttempts = 0; - + int mPasswordOwner = -1; - + final HashMap mAdminMap = new HashMap(); final ArrayList mAdminList = new ArrayList(); - + static class ActiveAdmin { final DeviceAdminInfo info; - + int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; int minimumPasswordLength = 0; + int passwordHistoryLength = 0; long maximumTimeToUnlock = 0; int maximumFailedPasswordsForWipe = 0; - + ActiveAdmin(DeviceAdminInfo _info) { info = _info; } - + int getUid() { return info.getActivityInfo().applicationInfo.uid; } - + void writeToXml(XmlSerializer out) throws IllegalArgumentException, IllegalStateException, IOException { out.startTag(null, "policies"); @@ -110,7 +111,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (minimumPasswordLength > 0) { out.startTag(null, "min-password-length"); out.attribute(null, "value", Integer.toString(minimumPasswordLength)); - out.endTag(null, "mn-password-length"); + out.endTag(null, "min-password-length"); + } + if(passwordHistoryLength > 0) { + out.startTag(null, "password-history-length"); + out.attribute(null, "value", Integer.toString(passwordHistoryLength)); + out.endTag(null, "password-history-length"); } } if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { @@ -124,7 +130,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, "max-failed-password-wipe"); } } - + void readFromXml(XmlPullParser parser) throws XmlPullParserException, IOException { int outerDepth = parser.getDepth(); @@ -143,6 +149,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("min-password-length".equals(tag)) { minimumPasswordLength = Integer.parseInt( parser.getAttributeValue(null, "value")); + } else if ("password-history-length".equals(tag)) { + passwordHistoryLength = Integer.parseInt( + parser.getAttributeValue(null, "value")); } else if ("max-time-to-unlock".equals(tag)) { maximumTimeToUnlock = Long.parseLong( parser.getAttributeValue(null, "value")); @@ -155,7 +164,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { XmlUtils.skipCurrentTag(parser); } } - + void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("uid="); pw.println(getUid()); pw.print(prefix); pw.println("policies:"); @@ -166,23 +175,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } pw.print(prefix); pw.print("passwordQuality=0x"); - pw.print(Integer.toHexString(passwordQuality)); - pw.print(" minimumPasswordLength="); + pw.println(Integer.toHexString(passwordQuality)); + pw.print(prefix); pw.print("minimumPasswordLength="); pw.println(minimumPasswordLength); + pw.print(prefix); pw.print("passwordHistoryLength="); + pw.println(passwordHistoryLength); pw.print(prefix); pw.print("maximumTimeToUnlock="); pw.println(maximumTimeToUnlock); pw.print(prefix); pw.print("maximumFailedPasswordsForWipe="); pw.println(maximumFailedPasswordsForWipe); } } - + class MyPackageMonitor extends PackageMonitor { 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()); + int change = isPackageDisappearing(aa.info.getPackageName()); if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) { Slog.w(TAG, "Admin unexpectedly uninstalled: " @@ -207,7 +218,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + /** * Instantiates the service. */ @@ -224,7 +235,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return mIPowerManager; } - + ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) { ActiveAdmin admin = mAdminMap.get(who); if (admin != null @@ -234,7 +245,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return null; } - + ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { final int callingUid = Binder.getCallingUid(); @@ -265,13 +276,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + Binder.getCallingUid() + " for policy #" + reqPolicy); } } - + void sendAdminCommandLocked(ActiveAdmin admin, String action) { Intent intent = new Intent(action); intent.setComponent(admin.info.getComponent()); mContext.sendBroadcast(intent); } - + void sendAdminCommandLocked(String action, int reqPolicy) { final int N = mAdminList.size(); if (N > 0) { @@ -283,7 +294,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + void removeActiveAdminLocked(ComponentName adminReceiver) { ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); if (admin != null) { @@ -295,7 +306,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { validatePasswordOwnerLocked(); } } - + public DeviceAdminInfo findAdmin(ComponentName adminName) { Intent resolveIntent = new Intent(); resolveIntent.setComponent(adminName); @@ -304,7 +315,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (infos == null || infos.size() <= 0) { throw new IllegalArgumentException("Unknown admin: " + adminName); } - + try { return new DeviceAdminInfo(mContext, infos.get(0)); } catch (XmlPullParserException e) { @@ -315,7 +326,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } } - + private static JournaledFile makeJournaledFile() { final String base = "/data/system/device_policies.xml"; return new JournaledFile(new File(base), new File(base + ".tmp")); @@ -331,7 +342,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.startDocument(null, true); out.startTag(null, "policies"); - + final int N = mAdminList.size(); for (int i=0; i= 0) { out.startTag(null, "password-owner"); out.attribute(null, "value", Integer.toString(mPasswordOwner)); out.endTag(null, "password-owner"); } - + if (mFailedPasswordAttempts != 0) { out.startTag(null, "failed-password-attempts"); out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts)); out.endTag(null, "failed-password-attempts"); } - + if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) { out.startTag(null, "active-password"); out.attribute(null, "quality", Integer.toString(mActivePasswordQuality)); out.attribute(null, "length", Integer.toString(mActivePasswordLength)); out.endTag(null, "active-password"); } - + out.endTag(null, "policies"); out.endDocument(); @@ -470,9 +481,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; mActivePasswordLength = 0; } - + validatePasswordOwnerLocked(); - + long timeMs = getMaximumTimeToLock(null); if (timeMs <= 0) { timeMs = Integer.MAX_VALUE; @@ -496,7 +507,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalArgumentException("Invalid quality constant: 0x" + Integer.toHexString(quality)); } - + void validatePasswordOwnerLocked() { if (mPasswordOwner >= 0) { boolean haveOwner = false; @@ -513,17 +524,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + public void systemReady() { synchronized (this) { loadSettingsLocked(); } } - + public void setActiveAdmin(ComponentName adminReceiver) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - + DeviceAdminInfo info = findAdmin(adminReceiver); if (info == null) { throw new IllegalArgumentException("Bad admin: " + adminReceiver); @@ -545,13 +556,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + public boolean isAdminActive(ComponentName adminReceiver) { synchronized (this) { return getActiveAdminUncheckedLocked(adminReceiver) != null; } } - + public List getActiveAdmins() { synchronized (this) { final int N = mAdminList.size(); @@ -565,7 +576,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return res; } } - + public boolean packageHasActiveAdmins(String packageName) { synchronized (this) { final int N = mAdminList.size(); @@ -577,7 +588,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } } - + public void removeActiveAdmin(ComponentName adminReceiver) { synchronized (this) { ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); @@ -596,10 +607,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + public void setPasswordQuality(ComponentName who, int quality) { validateQualityConstant(quality); - + synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -612,16 +623,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + public int getPasswordQuality(ComponentName who) { synchronized (this) { int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - + if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who); return admin != null ? admin.passwordQuality : mode; } - + final int N = mAdminList.size(); for (int i=0; i= getPasswordMinimumLength(null); } } - + public int getCurrentFailedPasswordAttempts() { synchronized (this) { // This API can only be called by an active device admin, @@ -687,7 +732,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mFailedPasswordAttempts; } } - + public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) { synchronized (this) { // This API can only be called by an active device admin, @@ -702,16 +747,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + public int getMaximumFailedPasswordsForWipe(ComponentName who) { synchronized (this) { int count = 0; - + if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who); return admin != null ? admin.maximumFailedPasswordsForWipe : count; } - + final int N = mAdminList.size(); for (int i=0; i= 0 && mPasswordOwner != callingUid) { Slog.w(TAG, "resetPassword: already set by another uid and not entered by user"); return false; } - + // Don't do this with the lock held, because it is going to call // back in to the service. long ident = Binder.clearCallingIdentity(); @@ -776,10 +821,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } finally { Binder.restoreCallingIdentity(ident); } - + return true; } - + public void setMaximumTimeToLock(ComponentName who, long timeMs) { synchronized (this) { if (who == null) { @@ -789,16 +834,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_FORCE_LOCK); if (ap.maximumTimeToUnlock != timeMs) { ap.maximumTimeToUnlock = timeMs; - + long ident = Binder.clearCallingIdentity(); try { saveSettingsLocked(); - + timeMs = getMaximumTimeToLock(null); if (timeMs <= 0) { timeMs = Integer.MAX_VALUE; } - + try { getIPowerManager().setMaximumScreenOffTimeount((int)timeMs); } catch (RemoteException e) { @@ -810,16 +855,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + public long getMaximumTimeToLock(ComponentName who) { synchronized (this) { long time = 0; - + if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who); return admin != null ? admin.maximumTimeToUnlock : time; } - + final int N = mAdminList.size(); for (int i=0; i= 0) { long ident = Binder.clearCallingIdentity(); @@ -965,7 +1010,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -976,12 +1021,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + ", uid=" + Binder.getCallingUid()); return; } - + final Printer p = new PrintWriterPrinter(pw); - + synchronized (this) { p.println("Current Device Policy Manager state:"); - + p.println(" Enabled Device Admins:"); final int N = mAdminList.size(); for (int i=0; i