blob: 2b43b0131cd8f839615386010bdd263c2fb421b2 [file] [log] [blame]
Dianne Hackbornd6847842010-01-12 18:14:19 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080019import com.android.internal.content.PackageMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070020import com.android.internal.os.storage.ExternalStorageFormatter;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080021import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070022import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080023import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080024import com.android.internal.widget.LockPatternUtils;
Dianne Hackbornd6847842010-01-12 18:14:19 -080025
26import org.xmlpull.v1.XmlPullParser;
27import org.xmlpull.v1.XmlPullParserException;
28import org.xmlpull.v1.XmlSerializer;
29
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080030import android.app.Activity;
Jim Millera4e28d12010-11-08 16:15:47 -080031import android.app.AlarmManager;
32import android.app.PendingIntent;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080033import android.app.admin.DeviceAdminInfo;
34import android.app.admin.DeviceAdminReceiver;
35import android.app.admin.DevicePolicyManager;
36import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080037import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080038import android.content.ComponentName;
Oscar Montemayor69238c62010-08-03 10:51:06 -070039import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080040import android.content.Context;
41import android.content.Intent;
Jim Millera4e28d12010-11-08 16:15:47 -080042import android.content.IntentFilter;
Dianne Hackbornd6847842010-01-12 18:14:19 -080043import android.content.pm.PackageManager;
44import android.content.pm.ResolveInfo;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080045import android.content.pm.PackageManager.NameNotFoundException;
Jim Millera4e28d12010-11-08 16:15:47 -080046import android.net.ConnectivityManager;
Dianne Hackbornd6847842010-01-12 18:14:19 -080047import android.os.Binder;
Jim Millera4e28d12010-11-08 16:15:47 -080048import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080049import android.os.IBinder;
50import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070051import android.os.PowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080052import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080053import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080054import android.os.RemoteException;
55import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080056import android.os.SystemClock;
Oscar Montemayor69238c62010-08-03 10:51:06 -070057import android.provider.Settings;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -070058import android.util.Slog;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080059import android.util.PrintWriterPrinter;
60import android.util.Printer;
Dianne Hackbornd6847842010-01-12 18:14:19 -080061import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080062import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080063
64import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080065import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080066import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070067import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080068import java.io.FileOutputStream;
69import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080070import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080071import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080072import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080073import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080074import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080075import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070076import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077
78/**
79 * Implementation of the device policy APIs.
80 */
81public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Jim Millera4e28d12010-11-08 16:15:47 -080082 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
83
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080084 static final String TAG = "DevicePolicyManagerService";
Konstantin Lopyrev32558232010-05-20 16:18:05 -070085
Jim Millera4e28d12010-11-08 16:15:47 -080086 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
87
88 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
89 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
90
91 private static final long MS_PER_DAY = 86400 * 1000;
92 private static final long MS_PER_HOUR = 3600 * 1000;
93 private static final long MS_PER_MINUTE = 60 * 1000;
94 private static final long MIN_TIMEOUT = 86400 * 1000; // minimum expiration timeout is 1 day
95
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080096 final Context mContext;
97 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070098 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080099
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800100 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700101
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800102 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800103 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700104 int mActivePasswordUpperCase = 0;
105 int mActivePasswordLowerCase = 0;
106 int mActivePasswordLetters = 0;
107 int mActivePasswordNumeric = 0;
108 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700109 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800110 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700111
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800112 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800113 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700114
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800115 final HashMap<ComponentName, ActiveAdmin> mAdminMap
116 = new HashMap<ComponentName, ActiveAdmin>();
117 final ArrayList<ActiveAdmin> mAdminList
118 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700119
Jim Millera4e28d12010-11-08 16:15:47 -0800120 BroadcastReceiver mReceiver = new BroadcastReceiver() {
121 @Override
122 public void onReceive(Context context, Intent intent) {
123 String action = intent.getAction();
124 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
125 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
126 Slog.v(TAG, "Sending password expiration notifications for action " + action);
127 mHandler.post(new Runnable() {
128 public void run() {
129 handlePasswordExpirationNotification();
130 }
131 });
132 }
133 }
134 };
135
Dianne Hackbornd6847842010-01-12 18:14:19 -0800136 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800137 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700138
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800139 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800140 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700141 int passwordHistoryLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700142 int minimumPasswordUpperCase = 0;
143 int minimumPasswordLowerCase = 0;
144 int minimumPasswordLetters = 1;
145 int minimumPasswordNumeric = 1;
146 int minimumPasswordSymbols = 1;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700147 int minimumPasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800148 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800149 int maximumFailedPasswordsForWipe = 0;
Jim Millera4e28d12010-11-08 16:15:47 -0800150 long passwordExpirationTimeout = 0L;
151 long passwordExpirationDate = 0L;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700152
Oscar Montemayor69238c62010-08-03 10:51:06 -0700153 // TODO: review implementation decisions with frameworks team
154 boolean specifiesGlobalProxy = false;
155 String globalProxySpec = null;
156 String globalProxyExclusionList = null;
157
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800158 ActiveAdmin(DeviceAdminInfo _info) {
159 info = _info;
160 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700161
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800162 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700163
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800164 void writeToXml(XmlSerializer out)
165 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800166 out.startTag(null, "policies");
167 info.writePoliciesToXml(out);
168 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800169 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
170 out.startTag(null, "password-quality");
171 out.attribute(null, "value", Integer.toString(passwordQuality));
172 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800173 if (minimumPasswordLength > 0) {
174 out.startTag(null, "min-password-length");
175 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700176 out.endTag(null, "min-password-length");
177 }
178 if(passwordHistoryLength > 0) {
179 out.startTag(null, "password-history-length");
180 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
181 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800182 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700183 if (minimumPasswordUpperCase > 0) {
184 out.startTag(null, "min-password-uppercase");
185 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
186 out.endTag(null, "min-password-uppercase");
187 }
188 if (minimumPasswordLowerCase > 0) {
189 out.startTag(null, "min-password-lowercase");
190 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
191 out.endTag(null, "min-password-lowercase");
192 }
193 if (minimumPasswordLetters > 0) {
194 out.startTag(null, "min-password-letters");
195 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
196 out.endTag(null, "min-password-letters");
197 }
198 if (minimumPasswordNumeric > 0) {
199 out.startTag(null, "min-password-numeric");
200 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
201 out.endTag(null, "min-password-numeric");
202 }
203 if (minimumPasswordSymbols > 0) {
204 out.startTag(null, "min-password-symbols");
205 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
206 out.endTag(null, "min-password-symbols");
207 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700208 if (minimumPasswordNonLetter > 0) {
209 out.startTag(null, "min-password-nonletter");
210 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
211 out.endTag(null, "min-password-nonletter");
212 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800213 }
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700214 if (maximumTimeToUnlock != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800215 out.startTag(null, "max-time-to-unlock");
216 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
217 out.endTag(null, "max-time-to-unlock");
218 }
219 if (maximumFailedPasswordsForWipe != 0) {
220 out.startTag(null, "max-failed-password-wipe");
221 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
222 out.endTag(null, "max-failed-password-wipe");
223 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700224 if (specifiesGlobalProxy) {
225 out.startTag(null, "specifies-global-proxy");
226 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
227 out.endTag(null, "specifies_global_proxy");
228 if (globalProxySpec != null) {
229 out.startTag(null, "global-proxy-spec");
230 out.attribute(null, "value", globalProxySpec);
231 out.endTag(null, "global-proxy-spec");
232 }
233 if (globalProxyExclusionList != null) {
234 out.startTag(null, "global-proxy-exclusion-list");
235 out.attribute(null, "value", globalProxyExclusionList);
236 out.endTag(null, "global-proxy-exclusion-list");
237 }
238 }
Jim Millera4e28d12010-11-08 16:15:47 -0800239 if (passwordExpirationTimeout != 0L) {
240 out.startTag(null, "password-expiration-timeout");
241 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
242 out.endTag(null, "password-expiration-timeout");
243 }
244 if (passwordExpirationDate != 0L) {
245 out.startTag(null, "password-expiration-date");
246 out.attribute(null, "value", Long.toString(passwordExpirationDate));
247 out.endTag(null, "password-expiration-date");
248 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800249 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700250
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800251 void readFromXml(XmlPullParser parser)
252 throws XmlPullParserException, IOException {
253 int outerDepth = parser.getDepth();
254 int type;
255 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
256 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
257 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
258 continue;
259 }
260 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800261 if ("policies".equals(tag)) {
262 info.readPoliciesFromXml(parser);
263 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800264 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800265 parser.getAttributeValue(null, "value"));
266 } else if ("min-password-length".equals(tag)) {
267 minimumPasswordLength = Integer.parseInt(
268 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700269 } else if ("password-history-length".equals(tag)) {
270 passwordHistoryLength = Integer.parseInt(
271 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700272 } else if ("min-password-uppercase".equals(tag)) {
273 minimumPasswordUpperCase = Integer.parseInt(
274 parser.getAttributeValue(null, "value"));
275 } else if ("min-password-lowercase".equals(tag)) {
276 minimumPasswordLowerCase = Integer.parseInt(
277 parser.getAttributeValue(null, "value"));
278 } else if ("min-password-letters".equals(tag)) {
279 minimumPasswordLetters = Integer.parseInt(
280 parser.getAttributeValue(null, "value"));
281 } else if ("min-password-numeric".equals(tag)) {
282 minimumPasswordNumeric = Integer.parseInt(
283 parser.getAttributeValue(null, "value"));
284 } else if ("min-password-symbols".equals(tag)) {
285 minimumPasswordSymbols = Integer.parseInt(
286 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700287 } else if ("min-password-nonletter".equals(tag)) {
288 minimumPasswordNonLetter = Integer.parseInt(
289 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800290 } else if ("max-time-to-unlock".equals(tag)) {
291 maximumTimeToUnlock = Long.parseLong(
292 parser.getAttributeValue(null, "value"));
293 } else if ("max-failed-password-wipe".equals(tag)) {
294 maximumFailedPasswordsForWipe = Integer.parseInt(
295 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700296 } else if ("specifies-global-proxy".equals(tag)) {
297 specifiesGlobalProxy = Boolean.getBoolean(
298 parser.getAttributeValue(null, "value"));
299 } else if ("global-proxy-spec".equals(tag)) {
300 globalProxySpec =
301 parser.getAttributeValue(null, "value");
302 } else if ("global-proxy-exclusion-list".equals(tag)) {
303 globalProxyExclusionList =
304 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800305 } else if ("password-expiration-timeout".equals(tag)) {
306 passwordExpirationTimeout = Long.parseLong(
307 parser.getAttributeValue(null, "value"));
308 } else if ("password-expiration-date".equals(tag)) {
309 passwordExpirationDate = Long.parseLong(
310 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800311 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700312 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800313 }
314 XmlUtils.skipCurrentTag(parser);
315 }
316 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700317
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800318 void dump(String prefix, PrintWriter pw) {
319 pw.print(prefix); pw.print("uid="); pw.println(getUid());
320 pw.print(prefix); pw.println("policies:");
321 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
322 if (pols != null) {
323 for (int i=0; i<pols.size(); i++) {
324 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
325 }
326 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700327 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700328 pw.println(Integer.toHexString(passwordQuality));
329 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800330 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700331 pw.print(prefix); pw.print("passwordHistoryLength=");
332 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700333 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
334 pw.println(minimumPasswordUpperCase);
335 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
336 pw.println(minimumPasswordLowerCase);
337 pw.print(prefix); pw.print("minimumPasswordLetters=");
338 pw.println(minimumPasswordLetters);
339 pw.print(prefix); pw.print("minimumPasswordNumeric=");
340 pw.println(minimumPasswordNumeric);
341 pw.print(prefix); pw.print("minimumPasswordSymbols=");
342 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700343 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
344 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800345 pw.print(prefix); pw.print("maximumTimeToUnlock=");
346 pw.println(maximumTimeToUnlock);
347 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
348 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700349 pw.print(prefix); pw.print("specifiesGlobalProxy=");
350 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800351 pw.print(prefix); pw.print("passwordExpirationTimeout=");
352 pw.println(passwordExpirationTimeout);
353 pw.print(prefix); pw.print("passwordExpirationDate=");
354 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700355 if (globalProxySpec != null) {
356 pw.print(prefix); pw.print("globalProxySpec=");
357 pw.println(globalProxySpec);
358 }
359 if (globalProxyExclusionList != null) {
360 pw.print(prefix); pw.print("globalProxyEclusionList=");
361 pw.println(globalProxyExclusionList);
362 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800363 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800364 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700365
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800366 class MyPackageMonitor extends PackageMonitor {
367 public void onSomePackagesChanged() {
368 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800369 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800370 for (int i=mAdminList.size()-1; i>=0; i--) {
371 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700372 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800373 if (change == PACKAGE_PERMANENT_CHANGE
374 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700375 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800376 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800377 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800378 mAdminList.remove(i);
379 } else if (isPackageModified(aa.info.getPackageName())) {
380 try {
381 mContext.getPackageManager().getReceiverInfo(
382 aa.info.getComponent(), 0);
383 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700384 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800385 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800386 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800387 mAdminList.remove(i);
388 }
389 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800390 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800391 if (removed) {
392 validatePasswordOwnerLocked();
393 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800394 }
395 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800396 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700397
Dianne Hackbornd6847842010-01-12 18:14:19 -0800398 /**
399 * Instantiates the service.
400 */
401 public DevicePolicyManagerService(Context context) {
402 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800403 mMonitor = new MyPackageMonitor();
404 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700405 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
406 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800407 IntentFilter filter = new IntentFilter();
408 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
409 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
410 context.registerReceiver(mReceiver, filter);
411 }
412
413 static String countdownString(long time) {
414 long days = time / MS_PER_DAY;
415 long hours = (time / MS_PER_HOUR) % 24;
416 long minutes = (time / MS_PER_MINUTE) % 60;
417 return days + "d" + hours + "h" + minutes + "m";
418 }
419
420 protected void setExpirationAlarmCheckLocked(Context context) {
421 final long expiration = getPasswordExpirationLocked(null);
422 final long now = System.currentTimeMillis();
423 final long timeToExpire = expiration - now;
424 final long alarmTime;
425 if (timeToExpire > 0L && timeToExpire < MS_PER_DAY) {
426 // Next expiration is less than a day, set alarm for exact expiration time
427 alarmTime = now + timeToExpire;
428 } else {
429 // Check again in 24 hours...
430 alarmTime = now + MS_PER_DAY;
431 }
432
433 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
434 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
435 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
436 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
437 am.cancel(pi);
438 am.set(AlarmManager.RTC, alarmTime, pi);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800439 }
440
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800441 private IPowerManager getIPowerManager() {
442 if (mIPowerManager == null) {
443 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
444 mIPowerManager = IPowerManager.Stub.asInterface(b);
445 }
446 return mIPowerManager;
447 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700448
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800449 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800450 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800451 if (admin != null
452 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
453 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
454 return admin;
455 }
456 return null;
457 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700458
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800459 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
460 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800461 final int callingUid = Binder.getCallingUid();
462 if (who != null) {
463 ActiveAdmin admin = mAdminMap.get(who);
464 if (admin == null) {
465 throw new SecurityException("No active admin " + who);
466 }
467 if (admin.getUid() != callingUid) {
468 throw new SecurityException("Admin " + who + " is not owned by uid "
469 + Binder.getCallingUid());
470 }
471 if (!admin.info.usesPolicy(reqPolicy)) {
472 throw new SecurityException("Admin " + admin.info.getComponent()
473 + " did not specify uses-policy for: "
474 + admin.info.getTagForPolicy(reqPolicy));
475 }
476 return admin;
477 } else {
478 final int N = mAdminList.size();
479 for (int i=0; i<N; i++) {
480 ActiveAdmin admin = mAdminList.get(i);
481 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
482 return admin;
483 }
484 }
485 throw new SecurityException("No active admin owned by uid "
486 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800487 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800488 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700489
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800490 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800491 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800492 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800493 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
494 intent.putExtra("expiration", admin.passwordExpirationDate);
495 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800496 mContext.sendBroadcast(intent);
497 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700498
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800499 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800500 final int N = mAdminList.size();
501 if (N > 0) {
502 for (int i=0; i<N; i++) {
503 ActiveAdmin admin = mAdminList.get(i);
504 if (admin.info.usesPolicy(reqPolicy)) {
505 sendAdminCommandLocked(admin, action);
506 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800507 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800508 }
509 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700510
Dianne Hackbornd6847842010-01-12 18:14:19 -0800511 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800512 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
513 if (admin != null) {
Oscar Montemayor69238c62010-08-03 10:51:06 -0700514 boolean doProxyCleanup =
515 admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800516 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800517 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800518 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800519 mAdminList.remove(admin);
520 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800521 validatePasswordOwnerLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -0700522 if (doProxyCleanup) {
523 resetGlobalProxy();
524 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800525 }
526 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700527
Dianne Hackbornd6847842010-01-12 18:14:19 -0800528 public DeviceAdminInfo findAdmin(ComponentName adminName) {
529 Intent resolveIntent = new Intent();
530 resolveIntent.setComponent(adminName);
531 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
532 resolveIntent, PackageManager.GET_META_DATA);
533 if (infos == null || infos.size() <= 0) {
534 throw new IllegalArgumentException("Unknown admin: " + adminName);
535 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700536
Dianne Hackbornd6847842010-01-12 18:14:19 -0800537 try {
538 return new DeviceAdminInfo(mContext, infos.get(0));
539 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700540 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800541 return null;
542 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700543 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800544 return null;
545 }
546 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700547
Dianne Hackbornd6847842010-01-12 18:14:19 -0800548 private static JournaledFile makeJournaledFile() {
549 final String base = "/data/system/device_policies.xml";
550 return new JournaledFile(new File(base), new File(base + ".tmp"));
551 }
552
553 private void saveSettingsLocked() {
554 JournaledFile journal = makeJournaledFile();
555 FileOutputStream stream = null;
556 try {
557 stream = new FileOutputStream(journal.chooseForWrite(), false);
558 XmlSerializer out = new FastXmlSerializer();
559 out.setOutput(stream, "utf-8");
560 out.startDocument(null, true);
561
562 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700563
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800564 final int N = mAdminList.size();
565 for (int i=0; i<N; i++) {
566 ActiveAdmin ap = mAdminList.get(i);
567 if (ap != null) {
568 out.startTag(null, "admin");
569 out.attribute(null, "name", ap.info.getComponent().flattenToString());
570 ap.writeToXml(out);
571 out.endTag(null, "admin");
572 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800573 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700574
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800575 if (mPasswordOwner >= 0) {
576 out.startTag(null, "password-owner");
577 out.attribute(null, "value", Integer.toString(mPasswordOwner));
578 out.endTag(null, "password-owner");
579 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700580
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800581 if (mFailedPasswordAttempts != 0) {
582 out.startTag(null, "failed-password-attempts");
583 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
584 out.endTag(null, "failed-password-attempts");
585 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700586
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700587 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
588 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
589 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700590 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700591 out.startTag(null, "active-password");
592 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
593 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700594 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
595 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
596 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
597 out.attribute(null, "numeric", Integer
598 .toString(mActivePasswordNumeric));
599 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700600 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700601 out.endTag(null, "active-password");
602 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700603
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700604 out.endTag(null, "policies");
605
Dianne Hackbornd6847842010-01-12 18:14:19 -0800606 out.endDocument();
607 stream.close();
608 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700609 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800610 } catch (IOException e) {
611 try {
612 if (stream != null) {
613 stream.close();
614 }
615 } catch (IOException ex) {
616 // Ignore
617 }
618 journal.rollback();
619 }
620 }
621
Jim Miller284b62e2010-06-08 14:27:42 -0700622 private void sendChangedNotification() {
623 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
624 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
625 mContext.sendBroadcast(intent);
626 }
627
Dianne Hackbornd6847842010-01-12 18:14:19 -0800628 private void loadSettingsLocked() {
629 JournaledFile journal = makeJournaledFile();
630 FileInputStream stream = null;
631 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800632 try {
633 stream = new FileInputStream(file);
634 XmlPullParser parser = Xml.newPullParser();
635 parser.setInput(stream, null);
636
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800637 int type;
638 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
639 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800640 }
641 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800642 if (!"policies".equals(tag)) {
643 throw new XmlPullParserException(
644 "Settings do not start with policies tag: found " + tag);
645 }
646 type = parser.next();
647 int outerDepth = parser.getDepth();
648 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
649 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
650 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
651 continue;
652 }
653 tag = parser.getName();
654 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800655 String name = parser.getAttributeValue(null, "name");
656 try {
657 DeviceAdminInfo dai = findAdmin(
658 ComponentName.unflattenFromString(name));
659 if (dai != null) {
660 ActiveAdmin ap = new ActiveAdmin(dai);
661 ap.readFromXml(parser);
662 mAdminMap.put(ap.info.getComponent(), ap);
663 mAdminList.add(ap);
664 }
665 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700666 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800667 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800668 } else if ("failed-password-attempts".equals(tag)) {
669 mFailedPasswordAttempts = Integer.parseInt(
670 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800671 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800672 } else if ("password-owner".equals(tag)) {
673 mPasswordOwner = Integer.parseInt(
674 parser.getAttributeValue(null, "value"));
675 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700676 } else if ("active-password".equals(tag)) {
677 mActivePasswordQuality = Integer.parseInt(
678 parser.getAttributeValue(null, "quality"));
679 mActivePasswordLength = Integer.parseInt(
680 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700681 mActivePasswordUpperCase = Integer.parseInt(
682 parser.getAttributeValue(null, "uppercase"));
683 mActivePasswordLowerCase = Integer.parseInt(
684 parser.getAttributeValue(null, "lowercase"));
685 mActivePasswordLetters = Integer.parseInt(
686 parser.getAttributeValue(null, "letters"));
687 mActivePasswordNumeric = Integer.parseInt(
688 parser.getAttributeValue(null, "numeric"));
689 mActivePasswordSymbols = Integer.parseInt(
690 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700691 mActivePasswordNonLetter = Integer.parseInt(
692 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700693 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800694 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700695 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800696 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800697 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800698 }
699 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700700 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800701 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700702 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800703 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700704 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700705 } catch (FileNotFoundException e) {
706 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800707 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700708 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800709 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700710 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800711 }
712 try {
713 if (stream != null) {
714 stream.close();
715 }
716 } catch (IOException e) {
717 // Ignore
718 }
719
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700720 // Validate that what we stored for the password quality matches
721 // sufficiently what is currently set. Note that this is only
722 // a sanity check in case the two get out of sync; this should
723 // never normally happen.
724 LockPatternUtils utils = new LockPatternUtils(mContext);
725 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
726 Slog.w(TAG, "Active password quality 0x"
727 + Integer.toHexString(mActivePasswordQuality)
728 + " does not match actual quality 0x"
729 + Integer.toHexString(utils.getActivePasswordQuality()));
730 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
731 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700732 mActivePasswordUpperCase = 0;
733 mActivePasswordLowerCase = 0;
734 mActivePasswordLetters = 0;
735 mActivePasswordNumeric = 0;
736 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700737 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700738 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700739
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800740 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700741
Dianne Hackborn254cb442010-01-27 19:23:59 -0800742 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800743 if (timeMs <= 0) {
744 timeMs = Integer.MAX_VALUE;
745 }
746 try {
747 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
748 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700749 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800750 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800751 }
752
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700753 static void validateQualityConstant(int quality) {
754 switch (quality) {
755 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
756 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
757 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
758 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
759 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700760 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700761 return;
762 }
763 throw new IllegalArgumentException("Invalid quality constant: 0x"
764 + Integer.toHexString(quality));
765 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700766
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800767 void validatePasswordOwnerLocked() {
768 if (mPasswordOwner >= 0) {
769 boolean haveOwner = false;
770 for (int i=mAdminList.size()-1; i>=0; i--) {
771 if (mAdminList.get(i).getUid() == mPasswordOwner) {
772 haveOwner = true;
773 break;
774 }
775 }
776 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700777 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800778 + " no longer active; disabling");
779 mPasswordOwner = -1;
780 }
781 }
782 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700783
Dianne Hackbornd6847842010-01-12 18:14:19 -0800784 public void systemReady() {
785 synchronized (this) {
786 loadSettingsLocked();
787 }
788 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700789
Jim Millera4e28d12010-11-08 16:15:47 -0800790 private void handlePasswordExpirationNotification() {
791 synchronized (this) {
792 final long now = System.currentTimeMillis();
793 final int N = mAdminList.size();
794 if (N <= 0) {
795 return;
796 }
797 for (int i=0; i < N; i++) {
798 ActiveAdmin admin = mAdminList.get(i);
799 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
800 && admin.passwordExpirationTimeout > 0L
801 && admin.passwordExpirationDate > 0L
802 && now > admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
803 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
804 }
805 }
806 setExpirationAlarmCheckLocked(mContext);
807 }
808 }
809
Dianne Hackbornd6847842010-01-12 18:14:19 -0800810 public void setActiveAdmin(ComponentName adminReceiver) {
811 mContext.enforceCallingOrSelfPermission(
812 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700813
Dianne Hackbornd6847842010-01-12 18:14:19 -0800814 DeviceAdminInfo info = findAdmin(adminReceiver);
815 if (info == null) {
816 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
817 }
818 synchronized (this) {
819 long ident = Binder.clearCallingIdentity();
820 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800821 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
822 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800823 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800824 ActiveAdmin admin = new ActiveAdmin(info);
825 mAdminMap.put(adminReceiver, admin);
826 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800827 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800828 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800829 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800830 } finally {
831 Binder.restoreCallingIdentity(ident);
832 }
833 }
834 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700835
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800836 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800837 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800838 return getActiveAdminUncheckedLocked(adminReceiver) != null;
839 }
840 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700841
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800842 public List<ComponentName> getActiveAdmins() {
843 synchronized (this) {
844 final int N = mAdminList.size();
845 if (N <= 0) {
846 return null;
847 }
848 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
849 for (int i=0; i<N; i++) {
850 res.add(mAdminList.get(i).info.getComponent());
851 }
852 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800853 }
854 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700855
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800856 public boolean packageHasActiveAdmins(String packageName) {
857 synchronized (this) {
858 final int N = mAdminList.size();
859 for (int i=0; i<N; i++) {
860 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
861 return true;
862 }
863 }
864 return false;
865 }
866 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700867
Dianne Hackbornd6847842010-01-12 18:14:19 -0800868 public void removeActiveAdmin(ComponentName adminReceiver) {
869 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800870 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
871 if (admin == null) {
872 return;
873 }
874 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800875 mContext.enforceCallingOrSelfPermission(
876 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
877 }
878 long ident = Binder.clearCallingIdentity();
879 try {
880 removeActiveAdminLocked(adminReceiver);
881 } finally {
882 Binder.restoreCallingIdentity(ident);
883 }
884 }
885 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700886
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700887 public void setPasswordQuality(ComponentName who, int quality) {
888 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700889
Dianne Hackbornd6847842010-01-12 18:14:19 -0800890 synchronized (this) {
891 if (who == null) {
892 throw new NullPointerException("ComponentName is null");
893 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800894 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
895 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700896 if (ap.passwordQuality != quality) {
897 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800898 saveSettingsLocked();
899 }
900 }
901 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700902
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800903 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800904 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800905 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700906
Dianne Hackborn254cb442010-01-27 19:23:59 -0800907 if (who != null) {
908 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800909 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800910 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700911
Dianne Hackborn254cb442010-01-27 19:23:59 -0800912 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800913 for (int i=0; i<N; i++) {
914 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800915 if (mode < admin.passwordQuality) {
916 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800917 }
918 }
919 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800920 }
921 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700922
Dianne Hackborn254cb442010-01-27 19:23:59 -0800923 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800924 synchronized (this) {
925 if (who == null) {
926 throw new NullPointerException("ComponentName is null");
927 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800928 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
929 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800930 if (ap.minimumPasswordLength != length) {
931 ap.minimumPasswordLength = length;
932 saveSettingsLocked();
933 }
934 }
935 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700936
Dianne Hackborn254cb442010-01-27 19:23:59 -0800937 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800938 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800939 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700940
Dianne Hackborn254cb442010-01-27 19:23:59 -0800941 if (who != null) {
942 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
943 return admin != null ? admin.minimumPasswordLength : length;
944 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700945
Dianne Hackborn254cb442010-01-27 19:23:59 -0800946 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800947 for (int i=0; i<N; i++) {
948 ActiveAdmin admin = mAdminList.get(i);
949 if (length < admin.minimumPasswordLength) {
950 length = admin.minimumPasswordLength;
951 }
952 }
953 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800954 }
955 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700956
957 public void setPasswordHistoryLength(ComponentName who, int length) {
958 synchronized (this) {
959 if (who == null) {
960 throw new NullPointerException("ComponentName is null");
961 }
962 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
963 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
964 if (ap.passwordHistoryLength != length) {
965 ap.passwordHistoryLength = length;
966 saveSettingsLocked();
967 }
968 }
969 }
970
971 public int getPasswordHistoryLength(ComponentName who) {
972 synchronized (this) {
973 int length = 0;
974
975 if (who != null) {
976 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
977 return admin != null ? admin.passwordHistoryLength : length;
978 }
979
980 final int N = mAdminList.size();
981 for (int i = 0; i < N; i++) {
982 ActiveAdmin admin = mAdminList.get(i);
983 if (length < admin.passwordHistoryLength) {
984 length = admin.passwordHistoryLength;
985 }
986 }
987 return length;
988 }
989 }
990
Jim Millera4e28d12010-11-08 16:15:47 -0800991 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
992 synchronized (this) {
993 if (who == null) {
994 throw new NullPointerException("ComponentName is null");
995 }
996 if (timeout != 0L && timeout < MIN_TIMEOUT) {
997 throw new IllegalArgumentException("Timeout must be > " + MIN_TIMEOUT + "ms");
998 }
999 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1000 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1001 // Calling this API automatically bumps the expiration date
1002 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1003 ap.passwordExpirationDate = expiration;
1004 ap.passwordExpirationTimeout = timeout;
1005 if (timeout > 0L) {
1006 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1007 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1008 .format(new Date(expiration)));
1009 }
1010 saveSettingsLocked();
1011 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1012 }
1013 }
1014
1015 public long getPasswordExpirationTimeout(ComponentName who) {
1016 synchronized (this) {
1017 long timeout = 0L;
1018 if (who != null) {
1019 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1020 return admin != null ? admin.passwordExpirationTimeout : timeout;
1021 }
1022
1023 final int N = mAdminList.size();
1024 for (int i = 0; i < N; i++) {
1025 ActiveAdmin admin = mAdminList.get(i);
1026 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1027 && timeout > admin.passwordExpirationTimeout)) {
1028 timeout = admin.passwordExpirationTimeout;
1029 }
1030 }
1031 return timeout;
1032 }
1033 }
1034
1035 private long getPasswordExpirationLocked(ComponentName who) {
1036 long timeout = 0L;
1037 if (who != null) {
1038 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1039 return admin != null ? admin.passwordExpirationDate : timeout;
1040 }
1041
1042 final int N = mAdminList.size();
1043 for (int i = 0; i < N; i++) {
1044 ActiveAdmin admin = mAdminList.get(i);
1045 if (timeout == 0L || (admin.passwordExpirationDate != 0
1046 && timeout > admin.passwordExpirationDate)) {
1047 timeout = admin.passwordExpirationDate;
1048 }
1049 }
1050 return timeout;
1051 }
1052
1053 public long getPasswordExpiration(ComponentName who) {
1054 synchronized (this) {
1055 return getPasswordExpirationLocked(who);
1056 }
1057 }
1058
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001059 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1060 synchronized (this) {
1061 if (who == null) {
1062 throw new NullPointerException("ComponentName is null");
1063 }
1064 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1065 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1066 if (ap.minimumPasswordUpperCase != length) {
1067 ap.minimumPasswordUpperCase = length;
1068 saveSettingsLocked();
1069 }
1070 }
1071 }
1072
1073 public int getPasswordMinimumUpperCase(ComponentName who) {
1074 synchronized (this) {
1075 int length = 0;
1076
1077 if (who != null) {
1078 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1079 return admin != null ? admin.minimumPasswordUpperCase : length;
1080 }
1081
1082 final int N = mAdminList.size();
1083 for (int i=0; i<N; i++) {
1084 ActiveAdmin admin = mAdminList.get(i);
1085 if (length < admin.minimumPasswordUpperCase) {
1086 length = admin.minimumPasswordUpperCase;
1087 }
1088 }
1089 return length;
1090 }
1091 }
1092
1093 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1094 synchronized (this) {
1095 if (who == null) {
1096 throw new NullPointerException("ComponentName is null");
1097 }
1098 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1099 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1100 if (ap.minimumPasswordLowerCase != length) {
1101 ap.minimumPasswordLowerCase = length;
1102 saveSettingsLocked();
1103 }
1104 }
1105 }
1106
1107 public int getPasswordMinimumLowerCase(ComponentName who) {
1108 synchronized (this) {
1109 int length = 0;
1110
1111 if (who != null) {
1112 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1113 return admin != null ? admin.minimumPasswordLowerCase : length;
1114 }
1115
1116 final int N = mAdminList.size();
1117 for (int i=0; i<N; i++) {
1118 ActiveAdmin admin = mAdminList.get(i);
1119 if (length < admin.minimumPasswordLowerCase) {
1120 length = admin.minimumPasswordLowerCase;
1121 }
1122 }
1123 return length;
1124 }
1125 }
1126
1127 public void setPasswordMinimumLetters(ComponentName who, int length) {
1128 synchronized (this) {
1129 if (who == null) {
1130 throw new NullPointerException("ComponentName is null");
1131 }
1132 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1133 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1134 if (ap.minimumPasswordLetters != length) {
1135 ap.minimumPasswordLetters = length;
1136 saveSettingsLocked();
1137 }
1138 }
1139 }
1140
1141 public int getPasswordMinimumLetters(ComponentName who) {
1142 synchronized (this) {
1143 int length = 0;
1144
1145 if (who != null) {
1146 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1147 return admin != null ? admin.minimumPasswordLetters : length;
1148 }
1149
1150 final int N = mAdminList.size();
1151 for (int i=0; i<N; i++) {
1152 ActiveAdmin admin = mAdminList.get(i);
1153 if (length < admin.minimumPasswordLetters) {
1154 length = admin.minimumPasswordLetters;
1155 }
1156 }
1157 return length;
1158 }
1159 }
1160
1161 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1162 synchronized (this) {
1163 if (who == null) {
1164 throw new NullPointerException("ComponentName is null");
1165 }
1166 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1167 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1168 if (ap.minimumPasswordNumeric != length) {
1169 ap.minimumPasswordNumeric = length;
1170 saveSettingsLocked();
1171 }
1172 }
1173 }
1174
1175 public int getPasswordMinimumNumeric(ComponentName who) {
1176 synchronized (this) {
1177 int length = 0;
1178
1179 if (who != null) {
1180 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1181 return admin != null ? admin.minimumPasswordNumeric : length;
1182 }
1183
1184 final int N = mAdminList.size();
1185 for (int i = 0; i < N; i++) {
1186 ActiveAdmin admin = mAdminList.get(i);
1187 if (length < admin.minimumPasswordNumeric) {
1188 length = admin.minimumPasswordNumeric;
1189 }
1190 }
1191 return length;
1192 }
1193 }
1194
1195 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1196 synchronized (this) {
1197 if (who == null) {
1198 throw new NullPointerException("ComponentName is null");
1199 }
1200 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1201 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1202 if (ap.minimumPasswordSymbols != length) {
1203 ap.minimumPasswordSymbols = length;
1204 saveSettingsLocked();
1205 }
1206 }
1207 }
1208
1209 public int getPasswordMinimumSymbols(ComponentName who) {
1210 synchronized (this) {
1211 int length = 0;
1212
1213 if (who != null) {
1214 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1215 return admin != null ? admin.minimumPasswordSymbols : length;
1216 }
1217
1218 final int N = mAdminList.size();
1219 for (int i=0; i<N; i++) {
1220 ActiveAdmin admin = mAdminList.get(i);
1221 if (length < admin.minimumPasswordSymbols) {
1222 length = admin.minimumPasswordSymbols;
1223 }
1224 }
1225 return length;
1226 }
1227 }
1228
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001229 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1230 synchronized (this) {
1231 if (who == null) {
1232 throw new NullPointerException("ComponentName is null");
1233 }
1234 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1235 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1236 if (ap.minimumPasswordNonLetter != length) {
1237 ap.minimumPasswordNonLetter = length;
1238 saveSettingsLocked();
1239 }
1240 }
1241 }
1242
1243 public int getPasswordMinimumNonLetter(ComponentName who) {
1244 synchronized (this) {
1245 int length = 0;
1246
1247 if (who != null) {
1248 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1249 return admin != null ? admin.minimumPasswordNonLetter : length;
1250 }
1251
1252 final int N = mAdminList.size();
1253 for (int i=0; i<N; i++) {
1254 ActiveAdmin admin = mAdminList.get(i);
1255 if (length < admin.minimumPasswordNonLetter) {
1256 length = admin.minimumPasswordNonLetter;
1257 }
1258 }
1259 return length;
1260 }
1261 }
1262
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001263 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001264 synchronized (this) {
1265 // This API can only be called by an active device admin,
1266 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001267 getActiveAdminForCallerLocked(null,
1268 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001269 if (mActivePasswordQuality < getPasswordQuality(null)
1270 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1271 return false;
1272 }
1273 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1274 return true;
1275 }
1276 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1277 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1278 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1279 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001280 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1281 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001282 }
1283 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001284
Dianne Hackbornd6847842010-01-12 18:14:19 -08001285 public int getCurrentFailedPasswordAttempts() {
1286 synchronized (this) {
1287 // This API can only be called by an active device admin,
1288 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001289 getActiveAdminForCallerLocked(null,
1290 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001291 return mFailedPasswordAttempts;
1292 }
1293 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001294
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001295 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1296 synchronized (this) {
1297 // This API can only be called by an active device admin,
1298 // so try to retrieve it to check that the caller is one.
1299 getActiveAdminForCallerLocked(who,
1300 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1301 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1302 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1303 if (ap.maximumFailedPasswordsForWipe != num) {
1304 ap.maximumFailedPasswordsForWipe = num;
1305 saveSettingsLocked();
1306 }
1307 }
1308 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001309
Dianne Hackborn254cb442010-01-27 19:23:59 -08001310 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001311 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001312 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001313
Dianne Hackborn254cb442010-01-27 19:23:59 -08001314 if (who != null) {
1315 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1316 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1317 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001318
Dianne Hackborn254cb442010-01-27 19:23:59 -08001319 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001320 for (int i=0; i<N; i++) {
1321 ActiveAdmin admin = mAdminList.get(i);
1322 if (count == 0) {
1323 count = admin.maximumFailedPasswordsForWipe;
1324 } else if (admin.maximumFailedPasswordsForWipe != 0
1325 && count > admin.maximumFailedPasswordsForWipe) {
1326 count = admin.maximumFailedPasswordsForWipe;
1327 }
1328 }
1329 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001330 }
1331 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001332
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001333 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001334 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001335 synchronized (this) {
1336 // This API can only be called by an active device admin,
1337 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001338 getActiveAdminForCallerLocked(null,
1339 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001340 quality = getPasswordQuality(null);
1341 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001342 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001343 if (realQuality < quality
1344 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001345 Slog.w(TAG, "resetPassword: password quality 0x"
1346 + Integer.toHexString(quality)
1347 + " does not meet required quality 0x"
1348 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001349 return false;
1350 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001351 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001352 }
1353 int length = getPasswordMinimumLength(null);
1354 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001355 Slog.w(TAG, "resetPassword: password length " + password.length()
1356 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001357 return false;
1358 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001359 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1360 int letters = 0;
1361 int uppercase = 0;
1362 int lowercase = 0;
1363 int numbers = 0;
1364 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001365 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001366 for (int i = 0; i < password.length(); i++) {
1367 char c = password.charAt(i);
1368 if (c >= 'A' && c <= 'Z') {
1369 letters++;
1370 uppercase++;
1371 } else if (c >= 'a' && c <= 'z') {
1372 letters++;
1373 lowercase++;
1374 } else if (c >= '0' && c <= '9') {
1375 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001376 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001377 } else {
1378 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001379 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001380 }
1381 }
1382 int neededLetters = getPasswordMinimumLetters(null);
1383 if(letters < neededLetters) {
1384 Slog.w(TAG, "resetPassword: number of letters " + letters
1385 + " does not meet required number of letters " + neededLetters);
1386 return false;
1387 }
1388 int neededNumbers = getPasswordMinimumNumeric(null);
1389 if (numbers < neededNumbers) {
1390 Slog
1391 .w(TAG, "resetPassword: number of numerical digits " + numbers
1392 + " does not meet required number of numerical digits "
1393 + neededNumbers);
1394 return false;
1395 }
1396 int neededLowerCase = getPasswordMinimumLowerCase(null);
1397 if (lowercase < neededLowerCase) {
1398 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1399 + " does not meet required number of lowercase letters "
1400 + neededLowerCase);
1401 return false;
1402 }
1403 int neededUpperCase = getPasswordMinimumUpperCase(null);
1404 if (uppercase < neededUpperCase) {
1405 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1406 + " does not meet required number of uppercase letters "
1407 + neededUpperCase);
1408 return false;
1409 }
1410 int neededSymbols = getPasswordMinimumSymbols(null);
1411 if (symbols < neededSymbols) {
1412 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1413 + " does not meet required number of special symbols " + neededSymbols);
1414 return false;
1415 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001416 int neededNonLetter = getPasswordMinimumNonLetter(null);
1417 if (nonletter < neededNonLetter) {
1418 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1419 + " does not meet required number of non-letter characters "
1420 + neededNonLetter);
1421 return false;
1422 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001423 }
1424
1425 LockPatternUtils utils = new LockPatternUtils(mContext);
1426 if(utils.checkPasswordHistory(password)) {
1427 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1428 + getPasswordHistoryLength(null) + " passwords");
1429 return false;
1430 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001431 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001432
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001433 int callingUid = Binder.getCallingUid();
1434 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001435 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001436 return false;
1437 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001438
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001439 // Don't do this with the lock held, because it is going to call
1440 // back in to the service.
1441 long ident = Binder.clearCallingIdentity();
1442 try {
1443 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001444 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001445 synchronized (this) {
1446 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1447 != 0 ? callingUid : -1;
1448 if (mPasswordOwner != newOwner) {
1449 mPasswordOwner = newOwner;
1450 saveSettingsLocked();
1451 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001452 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001453 } finally {
1454 Binder.restoreCallingIdentity(ident);
1455 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001456
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001457 return true;
1458 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001459
Dianne Hackbornd6847842010-01-12 18:14:19 -08001460 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1461 synchronized (this) {
1462 if (who == null) {
1463 throw new NullPointerException("ComponentName is null");
1464 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001465 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001466 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001467 if (ap.maximumTimeToUnlock != timeMs) {
1468 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001469
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001470 long ident = Binder.clearCallingIdentity();
1471 try {
1472 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001473
Dianne Hackborn254cb442010-01-27 19:23:59 -08001474 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001475 if (timeMs <= 0) {
1476 timeMs = Integer.MAX_VALUE;
1477 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001478
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001479 try {
1480 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1481 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001482 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001483 }
1484 } finally {
1485 Binder.restoreCallingIdentity(ident);
1486 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001487 }
1488 }
1489 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001490
Dianne Hackborn254cb442010-01-27 19:23:59 -08001491 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001492 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001493 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001494
Dianne Hackborn254cb442010-01-27 19:23:59 -08001495 if (who != null) {
1496 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1497 return admin != null ? admin.maximumTimeToUnlock : time;
1498 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001499
Dianne Hackborn254cb442010-01-27 19:23:59 -08001500 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001501 for (int i=0; i<N; i++) {
1502 ActiveAdmin admin = mAdminList.get(i);
1503 if (time == 0) {
1504 time = admin.maximumTimeToUnlock;
1505 } else if (admin.maximumTimeToUnlock != 0
1506 && time > admin.maximumTimeToUnlock) {
1507 time = admin.maximumTimeToUnlock;
1508 }
1509 }
1510 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001511 }
1512 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001513
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001514 public void lockNow() {
1515 synchronized (this) {
1516 // This API can only be called by an active device admin,
1517 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001518 getActiveAdminForCallerLocked(null,
1519 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001520 long ident = Binder.clearCallingIdentity();
1521 try {
1522 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1523 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1524 } catch (RemoteException e) {
1525 } finally {
1526 Binder.restoreCallingIdentity(ident);
1527 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001528 }
1529 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001530
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001531 void wipeDataLocked(int flags) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001532 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
1533 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1534 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1535 mWakeLock.acquire(10000);
1536 mContext.startService(intent);
1537 } else {
1538 try {
1539 RecoverySystem.rebootWipeUserData(mContext);
1540 } catch (IOException e) {
1541 Slog.w(TAG, "Failed requesting data wipe", e);
1542 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001543 }
1544 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001545
Dianne Hackbornd6847842010-01-12 18:14:19 -08001546 public void wipeData(int flags) {
1547 synchronized (this) {
1548 // This API can only be called by an active device admin,
1549 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001550 getActiveAdminForCallerLocked(null,
1551 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001552 long ident = Binder.clearCallingIdentity();
1553 try {
1554 wipeDataLocked(flags);
1555 } finally {
1556 Binder.restoreCallingIdentity(ident);
1557 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001558 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001559 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001560
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001561 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1562 mContext.enforceCallingOrSelfPermission(
1563 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001564
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001565 synchronized (this) {
1566 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1567 if (admin == null) {
1568 try {
1569 result.sendResult(null);
1570 } catch (RemoteException e) {
1571 }
1572 return;
1573 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001574 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001575 intent.setComponent(admin.info.getComponent());
1576 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1577 @Override
1578 public void onReceive(Context context, Intent intent) {
1579 try {
1580 result.sendResult(getResultExtras(false));
1581 } catch (RemoteException e) {
1582 }
1583 }
1584 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001585 }
1586 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001587
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001588 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001589 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001590 mContext.enforceCallingOrSelfPermission(
1591 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001592
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001593 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001594
Dianne Hackbornd6847842010-01-12 18:14:19 -08001595 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001596 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001597 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1598 || mActivePasswordUpperCase != uppercase
1599 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001600 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001601 long ident = Binder.clearCallingIdentity();
1602 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001603 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001604 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001605 mActivePasswordLetters = letters;
1606 mActivePasswordLowerCase = lowercase;
1607 mActivePasswordUpperCase = uppercase;
1608 mActivePasswordNumeric = numbers;
1609 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001610 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001611 mFailedPasswordAttempts = 0;
1612 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001613 updatePasswordExpirationsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001614 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001615 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001616 } finally {
1617 Binder.restoreCallingIdentity(ident);
1618 }
1619 }
1620 }
1621 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001622
Jim Millera4e28d12010-11-08 16:15:47 -08001623 private void updatePasswordExpirationsLocked() {
1624 final int N = mAdminList.size();
1625 if (N > 0) {
1626 for (int i=0; i<N; i++) {
1627 ActiveAdmin admin = mAdminList.get(i);
1628 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
1629 admin.passwordExpirationDate = System.currentTimeMillis()
1630 + admin.passwordExpirationTimeout;
1631 }
1632 }
1633 saveSettingsLocked();
1634 }
1635 }
1636
Dianne Hackbornd6847842010-01-12 18:14:19 -08001637 public void reportFailedPasswordAttempt() {
1638 mContext.enforceCallingOrSelfPermission(
1639 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001640
Dianne Hackbornd6847842010-01-12 18:14:19 -08001641 synchronized (this) {
1642 long ident = Binder.clearCallingIdentity();
1643 try {
1644 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001645 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001646 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001647 if (max > 0 && mFailedPasswordAttempts >= max) {
1648 wipeDataLocked(0);
1649 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001650 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001651 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001652 } finally {
1653 Binder.restoreCallingIdentity(ident);
1654 }
1655 }
1656 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001657
Dianne Hackbornd6847842010-01-12 18:14:19 -08001658 public void reportSuccessfulPasswordAttempt() {
1659 mContext.enforceCallingOrSelfPermission(
1660 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001661
Dianne Hackbornd6847842010-01-12 18:14:19 -08001662 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001663 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001664 long ident = Binder.clearCallingIdentity();
1665 try {
1666 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001667 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001668 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001669 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001670 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001671 } finally {
1672 Binder.restoreCallingIdentity(ident);
1673 }
1674 }
1675 }
1676 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001677
Oscar Montemayor69238c62010-08-03 10:51:06 -07001678 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1679 String exclusionList) {
1680 synchronized(this) {
1681 if (who == null) {
1682 throw new NullPointerException("ComponentName is null");
1683 }
1684
1685 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1686 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1687
1688 // Scan through active admins and find if anyone has already
1689 // set the global proxy.
1690 final int N = mAdminList.size();
1691 Set<ComponentName> compSet = mAdminMap.keySet();
1692 for (ComponentName component : compSet) {
1693 ActiveAdmin ap = mAdminMap.get(component);
1694 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1695 // Another admin already sets the global proxy
1696 // Return it to the caller.
1697 return component;
1698 }
1699 }
1700 if (proxySpec == null) {
1701 admin.specifiesGlobalProxy = false;
1702 admin.globalProxySpec = null;
1703 admin.globalProxyExclusionList = null;
1704 } else {
1705
1706 admin.specifiesGlobalProxy = true;
1707 admin.globalProxySpec = proxySpec;
1708 admin.globalProxyExclusionList = exclusionList;
1709 }
1710
1711 // Reset the global proxy accordingly
1712 // Do this using system permissions, as apps cannot write to secure settings
1713 long origId = Binder.clearCallingIdentity();
1714 resetGlobalProxy();
1715 Binder.restoreCallingIdentity(origId);
1716 return null;
1717 }
1718 }
1719
1720 public ComponentName getGlobalProxyAdmin() {
1721 synchronized(this) {
1722 // Scan through active admins and find if anyone has already
1723 // set the global proxy.
1724 final int N = mAdminList.size();
1725 for (int i = 0; i < N; i++) {
1726 ActiveAdmin ap = mAdminList.get(i);
1727 if (ap.specifiesGlobalProxy) {
1728 // Device admin sets the global proxy
1729 // Return it to the caller.
1730 return ap.info.getComponent();
1731 }
1732 }
1733 }
1734 // No device admin sets the global proxy.
1735 return null;
1736 }
1737
1738 private void resetGlobalProxy() {
1739 final int N = mAdminList.size();
1740 for (int i = 0; i < N; i++) {
1741 ActiveAdmin ap = mAdminList.get(i);
1742 if (ap.specifiesGlobalProxy) {
1743 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1744 return;
1745 }
1746 }
1747 // No device admins defining global proxies - reset global proxy settings to none
1748 saveGlobalProxy(null, null);
1749 }
1750
1751 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1752 if (exclusionList == null) {
1753 exclusionList = "";
1754 }
1755 if (proxySpec == null) {
1756 proxySpec = "";
1757 }
1758 // Remove white spaces
1759 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001760 String data[] = proxySpec.split(":");
1761 int proxyPort = 8080;
1762 if (data.length > 1) {
1763 try {
1764 proxyPort = Integer.parseInt(data[1]);
1765 } catch (NumberFormatException e) {}
1766 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001767 exclusionList = exclusionList.trim();
1768 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001769 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1770 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1771 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1772 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001773 }
1774
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001775 @Override
1776 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1777 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1778 != PackageManager.PERMISSION_GRANTED) {
1779
1780 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1781 + Binder.getCallingPid()
1782 + ", uid=" + Binder.getCallingUid());
1783 return;
1784 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001785
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001786 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001787
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001788 synchronized (this) {
1789 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001790
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001791 p.println(" Enabled Device Admins:");
1792 final int N = mAdminList.size();
1793 for (int i=0; i<N; i++) {
1794 ActiveAdmin ap = mAdminList.get(i);
1795 if (ap != null) {
1796 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1797 pw.println(":");
1798 ap.dump(" ", pw);
1799 }
1800 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001801
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001802 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001803 pw.print(" mActivePasswordQuality=0x");
1804 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001805 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001806 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1807 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1808 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1809 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1810 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001811 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001812 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1813 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1814 }
1815 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001816}