Add password expiration support to DevicePolicyManager.
Change-Id: Ib2629ec547c123ac489d7f4cbd4e0a1d4aa07620
This commit is contained in:
@@ -34318,6 +34318,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="USES_POLICY_EXPIRE_PASSWORD"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="6"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="USES_POLICY_FORCE_LOCK"
|
||||
type="int"
|
||||
transient="false"
|
||||
@@ -34487,6 +34498,21 @@
|
||||
<parameter name="intent" type="android.content.Intent">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onPasswordExpiring"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="context" type="android.content.Context">
|
||||
</parameter>
|
||||
<parameter name="intent" type="android.content.Intent">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onPasswordFailed"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -34576,6 +34602,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="ACTION_PASSWORD_EXPIRING"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.app.action.ACTION_PASSWORD_EXPIRING""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="ACTION_PASSWORD_FAILED"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
@@ -34688,6 +34725,32 @@
|
||||
<parameter name="admin" type="android.content.ComponentName">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getPasswordExpiration"
|
||||
return="long"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="admin" type="android.content.ComponentName">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getPasswordExpirationTimeout"
|
||||
return="long"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="admin" type="android.content.ComponentName">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getPasswordHistoryLength"
|
||||
return="int"
|
||||
abstract="false"
|
||||
@@ -34928,6 +34991,21 @@
|
||||
<parameter name="timeMs" type="long">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setPasswordExpirationTimeout"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="admin" type="android.content.ComponentName">
|
||||
</parameter>
|
||||
<parameter name="timeout" type="long">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setPasswordHistoryLength"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -246305,7 +246383,7 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="arg0" type="T">
|
||||
<parameter name="t" type="T">
|
||||
</parameter>
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
@@ -112,6 +112,15 @@ public final class DeviceAdminInfo implements Parcelable {
|
||||
*/
|
||||
public static final int USES_POLICY_SETS_GLOBAL_PROXY = 5;
|
||||
|
||||
/**
|
||||
* A type of policy that this device admin can use: force the user to
|
||||
* change their password after an administrator-defined time limit.
|
||||
*
|
||||
* <p>To control this policy, the device admin must have an "expire-password"
|
||||
* tag in the "uses-policies" section of its meta-data.
|
||||
*/
|
||||
public static final int USES_POLICY_EXPIRE_PASSWORD = 6;
|
||||
|
||||
/** @hide */
|
||||
public static class PolicyInfo {
|
||||
public final int ident;
|
||||
@@ -150,7 +159,10 @@ public final class DeviceAdminInfo implements Parcelable {
|
||||
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_SETS_GLOBAL_PROXY, "set-global-proxy",
|
||||
com.android.internal.R.string.policylab_setGlobalProxy,
|
||||
com.android.internal.R.string.policydesc_setGlobalProxy));
|
||||
|
||||
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_EXPIRE_PASSWORD, "expire-password",
|
||||
com.android.internal.R.string.policylab_expirePassword,
|
||||
com.android.internal.R.string.policydesc_expirePassword));
|
||||
|
||||
for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
|
||||
PolicyInfo pi = sPoliciesDisplayOrder.get(i);
|
||||
sRevKnownPolicies.put(pi.ident, pi);
|
||||
|
||||
@@ -145,7 +145,19 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PASSWORD_SUCCEEDED
|
||||
= "android.app.action.ACTION_PASSWORD_SUCCEEDED";
|
||||
|
||||
|
||||
/**
|
||||
* Action periodically sent to a device administrator when the device password
|
||||
* is expiring.
|
||||
*
|
||||
* <p>The calling device admin must have requested
|
||||
* {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to receive
|
||||
* this broadcast.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PASSWORD_EXPIRING
|
||||
= "android.app.action.ACTION_PASSWORD_EXPIRING";
|
||||
|
||||
/**
|
||||
* Name under which an DevicePolicy component publishes information
|
||||
* about itself. This meta-data must reference an XML resource containing
|
||||
@@ -251,7 +263,28 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
*/
|
||||
public void onPasswordSucceeded(Context context, Intent intent) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called periodically when the password is about to expire or has expired. It will typically
|
||||
* be called on device boot, once per day before the password expires and at the time when it
|
||||
* expires.
|
||||
*
|
||||
* <p>If the password is not updated by the user, this method will continue to be called
|
||||
* once per day until the password is changed or the device admin disables password expiration.
|
||||
*
|
||||
* <p>The admin will typically post a notification requesting the user to change their password
|
||||
* in response to this call. The actual password expiration time can be obtained by calling
|
||||
* {@link DevicePolicyManager#getPasswordExpiration(ComponentName) }
|
||||
*
|
||||
* <p>The admin should be sure to take down any notifications it posted in response to this call
|
||||
* when it receives {@link DeviceAdminReceiver#onPasswordChanged(Context, Intent) }.
|
||||
*
|
||||
* @param context The running context as per {@link #onReceive}.
|
||||
* @param intent The received intent as per {@link #onReceive}.
|
||||
*/
|
||||
public void onPasswordExpiring(Context context, Intent intent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept standard device administrator broadcasts. Implementations
|
||||
* should not override this method; it is better to implement the
|
||||
@@ -276,6 +309,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
}
|
||||
} else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
|
||||
onDisabled(context, intent);
|
||||
} else if (ACTION_PASSWORD_EXPIRING.equals(action)) {
|
||||
onPasswordExpiring(context, intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,6 +680,73 @@ public class DevicePolicyManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a device admin to set the password expiration timeout. Calling this method
|
||||
* will restart the countdown for password expiration for the given admin, as will changing
|
||||
* the device password (for all admins).
|
||||
*
|
||||
* <p>The provided timeout is the time delta in ms and will be added to the current time.
|
||||
* For example, to have the password expire 5 days from now, timeout would be
|
||||
* 5 * 86400 * 1000 = 432000000 ms for timeout.
|
||||
*
|
||||
* <p>To disable password expiration, a value of 0 may be used for timeout.
|
||||
*
|
||||
* <p>Timeout must be at least 1 day or IllegalArgumentException will be thrown.
|
||||
*
|
||||
* <p>The calling device admin must have requested
|
||||
* {@link DeviceAdminInfo#USES_POLICY_EXPIRE_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 timeout The limit (in ms) that a password can remain in effect. A value of 0
|
||||
* means there is no restriction (unlimited).
|
||||
*/
|
||||
public void setPasswordExpirationTimeout(ComponentName admin, long timeout) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.setPasswordExpirationTimeout(admin, timeout);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed talking with device policy service", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current password expiration timeout for the given admin or the aggregate
|
||||
* of all admins if admin is null.
|
||||
*
|
||||
* @param admin The name of the admin component to check, or null to aggregate all admins.
|
||||
* @return The timeout for the given admin or the minimum of all timeouts
|
||||
*/
|
||||
public long getPasswordExpirationTimeout(ComponentName admin) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getPasswordExpirationTimeout(admin);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed talking with device policy service", e);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current password expiration time for the given admin or an aggregate of
|
||||
* all admins if admin is null.
|
||||
*
|
||||
* @param admin The name of the admin component to check, or null to aggregate all admins.
|
||||
* @return The password expiration time, in ms.
|
||||
*/
|
||||
public long getPasswordExpiration(ComponentName admin) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getPasswordExpiration(admin);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed talking with device policy service", e);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current password history length for all admins
|
||||
* or a particular one.
|
||||
|
||||
@@ -52,6 +52,11 @@ interface IDevicePolicyManager {
|
||||
void setPasswordHistoryLength(in ComponentName who, int length);
|
||||
int getPasswordHistoryLength(in ComponentName who);
|
||||
|
||||
void setPasswordExpirationTimeout(in ComponentName who, long expiration);
|
||||
long getPasswordExpirationTimeout(in ComponentName who);
|
||||
|
||||
long getPasswordExpiration(in ComponentName who);
|
||||
|
||||
boolean isActivePasswordSufficient();
|
||||
int getCurrentFailedPasswordAttempts();
|
||||
|
||||
|
||||
@@ -1396,6 +1396,11 @@
|
||||
<string name="policydesc_setGlobalProxy">Set the device global proxy
|
||||
to be used while policy is enabled. Only the first device admin
|
||||
sets the effective global proxy.</string>
|
||||
<!-- Title of policy access to enforce password expiration [CHAR LIMIT=30]-->
|
||||
<string name="policylab_expirePassword">Set password expiration</string>
|
||||
<!-- Description of policy access to enforce password expiration [CHAR LIMIT=110]-->
|
||||
<string name="policydesc_expirePassword">Control how long before lockscreen password needs to be
|
||||
changed</string>
|
||||
|
||||
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
|
||||
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.admin.DeviceAdminInfo;
|
||||
import android.app.admin.DeviceAdminReceiver;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
@@ -37,10 +39,13 @@ import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IPowerManager;
|
||||
import android.os.PowerManager;
|
||||
@@ -49,7 +54,6 @@ import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.net.Proxy;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
import android.util.PrintWriterPrinter;
|
||||
@@ -64,8 +68,9 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -74,8 +79,20 @@ import java.util.Set;
|
||||
* Implementation of the device policy APIs.
|
||||
*/
|
||||
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
|
||||
|
||||
static final String TAG = "DevicePolicyManagerService";
|
||||
|
||||
private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 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 long MS_PER_HOUR = 3600 * 1000;
|
||||
private static final long MS_PER_MINUTE = 60 * 1000;
|
||||
private static final long MIN_TIMEOUT = 86400 * 1000; // minimum expiration timeout is 1 day
|
||||
|
||||
final Context mContext;
|
||||
final MyPackageMonitor mMonitor;
|
||||
final PowerManager.WakeLock mWakeLock;
|
||||
@@ -93,12 +110,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
int mFailedPasswordAttempts = 0;
|
||||
|
||||
int mPasswordOwner = -1;
|
||||
Handler mHandler = new Handler();
|
||||
|
||||
final HashMap<ComponentName, ActiveAdmin> mAdminMap
|
||||
= new HashMap<ComponentName, ActiveAdmin>();
|
||||
final ArrayList<ActiveAdmin> mAdminList
|
||||
= new ArrayList<ActiveAdmin>();
|
||||
|
||||
BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|
||||
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
|
||||
Slog.v(TAG, "Sending password expiration notifications for action " + action);
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
handlePasswordExpirationNotification();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static class ActiveAdmin {
|
||||
final DeviceAdminInfo info;
|
||||
|
||||
@@ -113,6 +147,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
int minimumPasswordNonLetter = 0;
|
||||
long maximumTimeToUnlock = 0;
|
||||
int maximumFailedPasswordsForWipe = 0;
|
||||
long passwordExpirationTimeout = 0L;
|
||||
long passwordExpirationDate = 0L;
|
||||
|
||||
// TODO: review implementation decisions with frameworks team
|
||||
boolean specifiesGlobalProxy = false;
|
||||
@@ -200,6 +236,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
out.endTag(null, "global-proxy-exclusion-list");
|
||||
}
|
||||
}
|
||||
if (passwordExpirationTimeout != 0L) {
|
||||
out.startTag(null, "password-expiration-timeout");
|
||||
out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
|
||||
out.endTag(null, "password-expiration-timeout");
|
||||
}
|
||||
if (passwordExpirationDate != 0L) {
|
||||
out.startTag(null, "password-expiration-date");
|
||||
out.attribute(null, "value", Long.toString(passwordExpirationDate));
|
||||
out.endTag(null, "password-expiration-date");
|
||||
}
|
||||
}
|
||||
|
||||
void readFromXml(XmlPullParser parser)
|
||||
@@ -256,6 +302,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
} else if ("global-proxy-exclusion-list".equals(tag)) {
|
||||
globalProxyExclusionList =
|
||||
parser.getAttributeValue(null, "value");
|
||||
} else if ("password-expiration-timeout".equals(tag)) {
|
||||
passwordExpirationTimeout = Long.parseLong(
|
||||
parser.getAttributeValue(null, "value"));
|
||||
} else if ("password-expiration-date".equals(tag)) {
|
||||
passwordExpirationDate = Long.parseLong(
|
||||
parser.getAttributeValue(null, "value"));
|
||||
} else {
|
||||
Slog.w(TAG, "Unknown admin tag: " + tag);
|
||||
}
|
||||
@@ -296,6 +348,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
pw.println(maximumFailedPasswordsForWipe);
|
||||
pw.print(prefix); pw.print("specifiesGlobalProxy=");
|
||||
pw.println(specifiesGlobalProxy);
|
||||
pw.print(prefix); pw.print("passwordExpirationTimeout=");
|
||||
pw.println(passwordExpirationTimeout);
|
||||
pw.print(prefix); pw.print("passwordExpirationDate=");
|
||||
pw.println(passwordExpirationDate);
|
||||
if (globalProxySpec != null) {
|
||||
pw.print(prefix); pw.print("globalProxySpec=");
|
||||
pw.println(globalProxySpec);
|
||||
@@ -348,6 +404,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
mMonitor.register(context, 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);
|
||||
}
|
||||
|
||||
static String countdownString(long time) {
|
||||
long days = time / MS_PER_DAY;
|
||||
long hours = (time / MS_PER_HOUR) % 24;
|
||||
long minutes = (time / MS_PER_MINUTE) % 60;
|
||||
return days + "d" + hours + "h" + minutes + "m";
|
||||
}
|
||||
|
||||
protected void setExpirationAlarmCheckLocked(Context context) {
|
||||
final long expiration = getPasswordExpirationLocked(null);
|
||||
final long now = System.currentTimeMillis();
|
||||
final long timeToExpire = expiration - now;
|
||||
final long alarmTime;
|
||||
if (timeToExpire > 0L && timeToExpire < MS_PER_DAY) {
|
||||
// Next expiration is less than a day, set alarm for exact expiration time
|
||||
alarmTime = now + timeToExpire;
|
||||
} else {
|
||||
// Check again in 24 hours...
|
||||
alarmTime = now + MS_PER_DAY;
|
||||
}
|
||||
|
||||
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
|
||||
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
|
||||
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
am.cancel(pi);
|
||||
am.set(AlarmManager.RTC, alarmTime, pi);
|
||||
}
|
||||
|
||||
private IPowerManager getIPowerManager() {
|
||||
@@ -402,6 +490,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
void sendAdminCommandLocked(ActiveAdmin admin, String action) {
|
||||
Intent intent = new Intent(action);
|
||||
intent.setComponent(admin.info.getComponent());
|
||||
if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
|
||||
intent.putExtra("expiration", admin.passwordExpirationDate);
|
||||
}
|
||||
mContext.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@@ -696,6 +787,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePasswordExpirationNotification() {
|
||||
synchronized (this) {
|
||||
final long now = System.currentTimeMillis();
|
||||
final int N = mAdminList.size();
|
||||
if (N <= 0) {
|
||||
return;
|
||||
}
|
||||
for (int i=0; i < N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
|
||||
&& admin.passwordExpirationTimeout > 0L
|
||||
&& admin.passwordExpirationDate > 0L
|
||||
&& now > admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
|
||||
sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
|
||||
}
|
||||
}
|
||||
setExpirationAlarmCheckLocked(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveAdmin(ComponentName adminReceiver) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
|
||||
@@ -877,6 +988,74 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
|
||||
synchronized (this) {
|
||||
if (who == null) {
|
||||
throw new NullPointerException("ComponentName is null");
|
||||
}
|
||||
if (timeout != 0L && timeout < MIN_TIMEOUT) {
|
||||
throw new IllegalArgumentException("Timeout must be > " + MIN_TIMEOUT + "ms");
|
||||
}
|
||||
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
|
||||
DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
|
||||
// Calling this API automatically bumps the expiration date
|
||||
final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
|
||||
ap.passwordExpirationDate = expiration;
|
||||
ap.passwordExpirationTimeout = timeout;
|
||||
if (timeout > 0L) {
|
||||
Slog.w(TAG, "setPasswordExpiration(): password will expire on "
|
||||
+ DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
|
||||
.format(new Date(expiration)));
|
||||
}
|
||||
saveSettingsLocked();
|
||||
setExpirationAlarmCheckLocked(mContext); // in case this is the first one
|
||||
}
|
||||
}
|
||||
|
||||
public long getPasswordExpirationTimeout(ComponentName who) {
|
||||
synchronized (this) {
|
||||
long timeout = 0L;
|
||||
if (who != null) {
|
||||
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
|
||||
return admin != null ? admin.passwordExpirationTimeout : timeout;
|
||||
}
|
||||
|
||||
final int N = mAdminList.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
|
||||
&& timeout > admin.passwordExpirationTimeout)) {
|
||||
timeout = admin.passwordExpirationTimeout;
|
||||
}
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
|
||||
private long getPasswordExpirationLocked(ComponentName who) {
|
||||
long timeout = 0L;
|
||||
if (who != null) {
|
||||
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
|
||||
return admin != null ? admin.passwordExpirationDate : timeout;
|
||||
}
|
||||
|
||||
final int N = mAdminList.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (timeout == 0L || (admin.passwordExpirationDate != 0
|
||||
&& timeout > admin.passwordExpirationDate)) {
|
||||
timeout = admin.passwordExpirationDate;
|
||||
}
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public long getPasswordExpiration(ComponentName who) {
|
||||
synchronized (this) {
|
||||
return getPasswordExpirationLocked(who);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPasswordMinimumUpperCase(ComponentName who, int length) {
|
||||
synchronized (this) {
|
||||
if (who == null) {
|
||||
@@ -1431,6 +1610,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
mActivePasswordNonLetter = nonletter;
|
||||
mFailedPasswordAttempts = 0;
|
||||
saveSettingsLocked();
|
||||
updatePasswordExpirationsLocked();
|
||||
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
|
||||
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
|
||||
} finally {
|
||||
@@ -1440,6 +1620,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePasswordExpirationsLocked() {
|
||||
final int N = mAdminList.size();
|
||||
if (N > 0) {
|
||||
for (int i=0; i<N; i++) {
|
||||
ActiveAdmin admin = mAdminList.get(i);
|
||||
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
|
||||
admin.passwordExpirationDate = System.currentTimeMillis()
|
||||
+ admin.passwordExpirationTimeout;
|
||||
}
|
||||
}
|
||||
saveSettingsLocked();
|
||||
}
|
||||
}
|
||||
|
||||
public void reportFailedPasswordAttempt() {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
|
||||
|
||||
Reference in New Issue
Block a user