blob: d549308705649db94afa8032c24f44bf3024ae9f [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;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080044import android.content.pm.PackageManager.NameNotFoundException;
Andy Stadler1f35d482010-11-19 15:39:41 -080045import android.content.pm.ResolveInfo;
Dianne Hackbornd6847842010-01-12 18:14:19 -080046import android.os.Binder;
Jim Millera4e28d12010-11-08 16:15:47 -080047import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080048import android.os.IBinder;
49import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070050import android.os.PowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080051import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080052import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080053import android.os.RemoteException;
54import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080055import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080056import android.os.SystemProperties;
Oscar Montemayor69238c62010-08-03 10:51:06 -070057import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080058import android.util.PrintWriterPrinter;
59import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080060import android.util.Slog;
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 Miller6b857682011-02-16 16:27:41 -080082 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080083
Jim Miller6b857682011-02-16 16:27:41 -080084 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
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;
Jim Millera4e28d12010-11-08 16:15:47 -080092
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080093 final Context mContext;
94 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070095 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080096
Dianne Hackborndf83afa2010-01-20 13:37:26 -080097 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070098
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080099 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800100 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700101 int mActivePasswordUpperCase = 0;
102 int mActivePasswordLowerCase = 0;
103 int mActivePasswordLetters = 0;
104 int mActivePasswordNumeric = 0;
105 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700106 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800107 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700108
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800109 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800110 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700111
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800112 final HashMap<ComponentName, ActiveAdmin> mAdminMap
113 = new HashMap<ComponentName, ActiveAdmin>();
114 final ArrayList<ActiveAdmin> mAdminList
115 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700116
Jim Millera4e28d12010-11-08 16:15:47 -0800117 BroadcastReceiver mReceiver = new BroadcastReceiver() {
118 @Override
119 public void onReceive(Context context, Intent intent) {
120 String action = intent.getAction();
121 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
122 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
123 Slog.v(TAG, "Sending password expiration notifications for action " + action);
124 mHandler.post(new Runnable() {
125 public void run() {
126 handlePasswordExpirationNotification();
127 }
128 });
129 }
130 }
131 };
132
Dianne Hackbornd6847842010-01-12 18:14:19 -0800133 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800134 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700135
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800136 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700137
138 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
139 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
140
141 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
142 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
143
144 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
145 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
146
147 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
148 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
149
150 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700151 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700152
153 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
154 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
155
156 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
157 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
158
159 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
160 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
161
162 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
163 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
164
165 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
166 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
167
168 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
169 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
170
171 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
172 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
173
Andy Stadler22dbfda2011-01-17 12:47:31 -0800174 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700175 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700176
Oscar Montemayor69238c62010-08-03 10:51:06 -0700177 // TODO: review implementation decisions with frameworks team
178 boolean specifiesGlobalProxy = false;
179 String globalProxySpec = null;
180 String globalProxyExclusionList = null;
181
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800182 ActiveAdmin(DeviceAdminInfo _info) {
183 info = _info;
184 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700185
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800186 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700187
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800188 void writeToXml(XmlSerializer out)
189 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800190 out.startTag(null, "policies");
191 info.writePoliciesToXml(out);
192 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800193 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
194 out.startTag(null, "password-quality");
195 out.attribute(null, "value", Integer.toString(passwordQuality));
196 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700197 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800198 out.startTag(null, "min-password-length");
199 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700200 out.endTag(null, "min-password-length");
201 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700202 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700203 out.startTag(null, "password-history-length");
204 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
205 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800206 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700207 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700208 out.startTag(null, "min-password-uppercase");
209 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
210 out.endTag(null, "min-password-uppercase");
211 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700212 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700213 out.startTag(null, "min-password-lowercase");
214 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
215 out.endTag(null, "min-password-lowercase");
216 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700217 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700218 out.startTag(null, "min-password-letters");
219 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
220 out.endTag(null, "min-password-letters");
221 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700222 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700223 out.startTag(null, "min-password-numeric");
224 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
225 out.endTag(null, "min-password-numeric");
226 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700227 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700228 out.startTag(null, "min-password-symbols");
229 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
230 out.endTag(null, "min-password-symbols");
231 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700232 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700233 out.startTag(null, "min-password-nonletter");
234 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
235 out.endTag(null, "min-password-nonletter");
236 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800237 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700238 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800239 out.startTag(null, "max-time-to-unlock");
240 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
241 out.endTag(null, "max-time-to-unlock");
242 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700243 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800244 out.startTag(null, "max-failed-password-wipe");
245 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
246 out.endTag(null, "max-failed-password-wipe");
247 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700248 if (specifiesGlobalProxy) {
249 out.startTag(null, "specifies-global-proxy");
250 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
251 out.endTag(null, "specifies_global_proxy");
252 if (globalProxySpec != null) {
253 out.startTag(null, "global-proxy-spec");
254 out.attribute(null, "value", globalProxySpec);
255 out.endTag(null, "global-proxy-spec");
256 }
257 if (globalProxyExclusionList != null) {
258 out.startTag(null, "global-proxy-exclusion-list");
259 out.attribute(null, "value", globalProxyExclusionList);
260 out.endTag(null, "global-proxy-exclusion-list");
261 }
262 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700263 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800264 out.startTag(null, "password-expiration-timeout");
265 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
266 out.endTag(null, "password-expiration-timeout");
267 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700268 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800269 out.startTag(null, "password-expiration-date");
270 out.attribute(null, "value", Long.toString(passwordExpirationDate));
271 out.endTag(null, "password-expiration-date");
272 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800273 if (encryptionRequested) {
274 out.startTag(null, "encryption-requested");
275 out.attribute(null, "value", Boolean.toString(encryptionRequested));
276 out.endTag(null, "encryption-requested");
277 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700278 if (disableCamera) {
279 out.startTag(null, "disable-camera");
280 out.attribute(null, "value", Boolean.toString(disableCamera));
281 out.endTag(null, "disable-camera");
282 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800283 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700284
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800285 void readFromXml(XmlPullParser parser)
286 throws XmlPullParserException, IOException {
287 int outerDepth = parser.getDepth();
288 int type;
289 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
290 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
291 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
292 continue;
293 }
294 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800295 if ("policies".equals(tag)) {
296 info.readPoliciesFromXml(parser);
297 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800298 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800299 parser.getAttributeValue(null, "value"));
300 } else if ("min-password-length".equals(tag)) {
301 minimumPasswordLength = Integer.parseInt(
302 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700303 } else if ("password-history-length".equals(tag)) {
304 passwordHistoryLength = Integer.parseInt(
305 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700306 } else if ("min-password-uppercase".equals(tag)) {
307 minimumPasswordUpperCase = Integer.parseInt(
308 parser.getAttributeValue(null, "value"));
309 } else if ("min-password-lowercase".equals(tag)) {
310 minimumPasswordLowerCase = Integer.parseInt(
311 parser.getAttributeValue(null, "value"));
312 } else if ("min-password-letters".equals(tag)) {
313 minimumPasswordLetters = Integer.parseInt(
314 parser.getAttributeValue(null, "value"));
315 } else if ("min-password-numeric".equals(tag)) {
316 minimumPasswordNumeric = Integer.parseInt(
317 parser.getAttributeValue(null, "value"));
318 } else if ("min-password-symbols".equals(tag)) {
319 minimumPasswordSymbols = Integer.parseInt(
320 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700321 } else if ("min-password-nonletter".equals(tag)) {
322 minimumPasswordNonLetter = Integer.parseInt(
323 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800324 } else if ("max-time-to-unlock".equals(tag)) {
325 maximumTimeToUnlock = Long.parseLong(
326 parser.getAttributeValue(null, "value"));
327 } else if ("max-failed-password-wipe".equals(tag)) {
328 maximumFailedPasswordsForWipe = Integer.parseInt(
329 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700330 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800331 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700332 parser.getAttributeValue(null, "value"));
333 } else if ("global-proxy-spec".equals(tag)) {
334 globalProxySpec =
335 parser.getAttributeValue(null, "value");
336 } else if ("global-proxy-exclusion-list".equals(tag)) {
337 globalProxyExclusionList =
338 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800339 } else if ("password-expiration-timeout".equals(tag)) {
340 passwordExpirationTimeout = Long.parseLong(
341 parser.getAttributeValue(null, "value"));
342 } else if ("password-expiration-date".equals(tag)) {
343 passwordExpirationDate = Long.parseLong(
344 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800345 } else if ("encryption-requested".equals(tag)) {
346 encryptionRequested = Boolean.parseBoolean(
347 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700348 } else if ("disable-camera".equals(tag)) {
349 disableCamera = Boolean.parseBoolean(
350 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800351 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700352 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800353 }
354 XmlUtils.skipCurrentTag(parser);
355 }
356 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700357
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800358 void dump(String prefix, PrintWriter pw) {
359 pw.print(prefix); pw.print("uid="); pw.println(getUid());
360 pw.print(prefix); pw.println("policies:");
361 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
362 if (pols != null) {
363 for (int i=0; i<pols.size(); i++) {
364 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
365 }
366 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700367 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700368 pw.println(Integer.toHexString(passwordQuality));
369 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800370 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700371 pw.print(prefix); pw.print("passwordHistoryLength=");
372 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700373 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
374 pw.println(minimumPasswordUpperCase);
375 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
376 pw.println(minimumPasswordLowerCase);
377 pw.print(prefix); pw.print("minimumPasswordLetters=");
378 pw.println(minimumPasswordLetters);
379 pw.print(prefix); pw.print("minimumPasswordNumeric=");
380 pw.println(minimumPasswordNumeric);
381 pw.print(prefix); pw.print("minimumPasswordSymbols=");
382 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700383 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
384 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800385 pw.print(prefix); pw.print("maximumTimeToUnlock=");
386 pw.println(maximumTimeToUnlock);
387 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
388 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700389 pw.print(prefix); pw.print("specifiesGlobalProxy=");
390 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800391 pw.print(prefix); pw.print("passwordExpirationTimeout=");
392 pw.println(passwordExpirationTimeout);
393 pw.print(prefix); pw.print("passwordExpirationDate=");
394 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700395 if (globalProxySpec != null) {
396 pw.print(prefix); pw.print("globalProxySpec=");
397 pw.println(globalProxySpec);
398 }
399 if (globalProxyExclusionList != null) {
400 pw.print(prefix); pw.print("globalProxyEclusionList=");
401 pw.println(globalProxyExclusionList);
402 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800403 pw.print(prefix); pw.print("encryptionRequested=");
404 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700405 pw.print(prefix); pw.print("disableCamera=");
406 pw.println(disableCamera);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800407 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800408 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700409
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800410 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800411 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800412 public void onSomePackagesChanged() {
413 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800414 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800415 for (int i=mAdminList.size()-1; i>=0; i--) {
416 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700417 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800418 if (change == PACKAGE_PERMANENT_CHANGE
419 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700420 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800421 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800422 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800423 mAdminList.remove(i);
424 } else if (isPackageModified(aa.info.getPackageName())) {
425 try {
426 mContext.getPackageManager().getReceiverInfo(
427 aa.info.getComponent(), 0);
428 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700429 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800430 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800431 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800432 mAdminList.remove(i);
433 }
434 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800435 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800436 if (removed) {
437 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700438 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700439 saveSettingsLocked();
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800440 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800441 }
442 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800443 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700444
Dianne Hackbornd6847842010-01-12 18:14:19 -0800445 /**
446 * Instantiates the service.
447 */
448 public DevicePolicyManagerService(Context context) {
449 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800450 mMonitor = new MyPackageMonitor();
451 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700452 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
453 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800454 IntentFilter filter = new IntentFilter();
455 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
456 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
457 context.registerReceiver(mReceiver, filter);
458 }
459
Andy Stadler043116a2010-11-29 17:43:32 -0800460 /**
461 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
462 * reminders. Clears alarm if no expirations are configured.
463 */
Jim Millera4e28d12010-11-08 16:15:47 -0800464 protected void setExpirationAlarmCheckLocked(Context context) {
465 final long expiration = getPasswordExpirationLocked(null);
466 final long now = System.currentTimeMillis();
467 final long timeToExpire = expiration - now;
468 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800469 if (expiration == 0) {
470 // No expirations are currently configured: Cancel alarm.
471 alarmTime = 0;
472 } else if (timeToExpire <= 0) {
473 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800474 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800475 } else {
476 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
477 // the expiration time.
478 long alarmInterval = timeToExpire % MS_PER_DAY;
479 if (alarmInterval == 0) {
480 alarmInterval = MS_PER_DAY;
481 }
482 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800483 }
484
Andy Stadler1f35d482010-11-19 15:39:41 -0800485 long token = Binder.clearCallingIdentity();
486 try {
487 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
488 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
489 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
490 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
491 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800492 if (alarmTime != 0) {
493 am.set(AlarmManager.RTC, alarmTime, pi);
494 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800495 } finally {
496 Binder.restoreCallingIdentity(token);
497 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800498 }
499
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800500 private IPowerManager getIPowerManager() {
501 if (mIPowerManager == null) {
502 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
503 mIPowerManager = IPowerManager.Stub.asInterface(b);
504 }
505 return mIPowerManager;
506 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700507
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800508 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800509 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800510 if (admin != null
511 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
512 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
513 return admin;
514 }
515 return null;
516 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700517
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800518 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
519 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800520 final int callingUid = Binder.getCallingUid();
521 if (who != null) {
522 ActiveAdmin admin = mAdminMap.get(who);
523 if (admin == null) {
524 throw new SecurityException("No active admin " + who);
525 }
526 if (admin.getUid() != callingUid) {
527 throw new SecurityException("Admin " + who + " is not owned by uid "
528 + Binder.getCallingUid());
529 }
530 if (!admin.info.usesPolicy(reqPolicy)) {
531 throw new SecurityException("Admin " + admin.info.getComponent()
532 + " did not specify uses-policy for: "
533 + admin.info.getTagForPolicy(reqPolicy));
534 }
535 return admin;
536 } else {
537 final int N = mAdminList.size();
538 for (int i=0; i<N; i++) {
539 ActiveAdmin admin = mAdminList.get(i);
540 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
541 return admin;
542 }
543 }
544 throw new SecurityException("No active admin owned by uid "
545 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800546 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800547 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700548
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800549 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700550 sendAdminCommandLocked(admin, action, null);
551 }
552
553 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800554 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800555 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800556 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
557 intent.putExtra("expiration", admin.passwordExpirationDate);
558 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700559 if (result != null) {
560 mContext.sendOrderedBroadcast(intent, null, result, mHandler,
561 Activity.RESULT_OK, null, null);
562 } else {
563 mContext.sendBroadcast(intent);
564 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800565 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700566
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800567 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800568 final int N = mAdminList.size();
569 if (N > 0) {
570 for (int i=0; i<N; i++) {
571 ActiveAdmin admin = mAdminList.get(i);
572 if (admin.info.usesPolicy(reqPolicy)) {
573 sendAdminCommandLocked(admin, action);
574 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800575 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800576 }
577 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700578
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700579 void removeActiveAdminLocked(final ComponentName adminReceiver) {
580 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800581 if (admin != null) {
582 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700583 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
584 new BroadcastReceiver() {
585 @Override
586 public void onReceive(Context context, Intent intent) {
587 synchronized (this) {
588 boolean doProxyCleanup = admin.info.usesPolicy(
589 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
590 mAdminList.remove(admin);
591 mAdminMap.remove(adminReceiver);
592 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700593 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700594 if (doProxyCleanup) {
595 resetGlobalProxy();
596 }
597 saveSettingsLocked();
598 }
599 }
600 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800601 }
602 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700603
Dianne Hackbornd6847842010-01-12 18:14:19 -0800604 public DeviceAdminInfo findAdmin(ComponentName adminName) {
605 Intent resolveIntent = new Intent();
606 resolveIntent.setComponent(adminName);
607 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
608 resolveIntent, PackageManager.GET_META_DATA);
609 if (infos == null || infos.size() <= 0) {
610 throw new IllegalArgumentException("Unknown admin: " + adminName);
611 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700612
Dianne Hackbornd6847842010-01-12 18:14:19 -0800613 try {
614 return new DeviceAdminInfo(mContext, infos.get(0));
615 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700616 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800617 return null;
618 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700619 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800620 return null;
621 }
622 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700623
Dianne Hackbornd6847842010-01-12 18:14:19 -0800624 private static JournaledFile makeJournaledFile() {
625 final String base = "/data/system/device_policies.xml";
626 return new JournaledFile(new File(base), new File(base + ".tmp"));
627 }
628
629 private void saveSettingsLocked() {
630 JournaledFile journal = makeJournaledFile();
631 FileOutputStream stream = null;
632 try {
633 stream = new FileOutputStream(journal.chooseForWrite(), false);
634 XmlSerializer out = new FastXmlSerializer();
635 out.setOutput(stream, "utf-8");
636 out.startDocument(null, true);
637
638 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700639
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800640 final int N = mAdminList.size();
641 for (int i=0; i<N; i++) {
642 ActiveAdmin ap = mAdminList.get(i);
643 if (ap != null) {
644 out.startTag(null, "admin");
645 out.attribute(null, "name", ap.info.getComponent().flattenToString());
646 ap.writeToXml(out);
647 out.endTag(null, "admin");
648 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800649 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700650
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800651 if (mPasswordOwner >= 0) {
652 out.startTag(null, "password-owner");
653 out.attribute(null, "value", Integer.toString(mPasswordOwner));
654 out.endTag(null, "password-owner");
655 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700656
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800657 if (mFailedPasswordAttempts != 0) {
658 out.startTag(null, "failed-password-attempts");
659 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
660 out.endTag(null, "failed-password-attempts");
661 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700662
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700663 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
664 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
665 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700666 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700667 out.startTag(null, "active-password");
668 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
669 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700670 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
671 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
672 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
673 out.attribute(null, "numeric", Integer
674 .toString(mActivePasswordNumeric));
675 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700676 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700677 out.endTag(null, "active-password");
678 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700679
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700680 out.endTag(null, "policies");
681
Dianne Hackbornd6847842010-01-12 18:14:19 -0800682 out.endDocument();
683 stream.close();
684 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700685 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800686 } catch (IOException e) {
687 try {
688 if (stream != null) {
689 stream.close();
690 }
691 } catch (IOException ex) {
692 // Ignore
693 }
694 journal.rollback();
695 }
696 }
697
Jim Miller284b62e2010-06-08 14:27:42 -0700698 private void sendChangedNotification() {
699 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
700 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
701 mContext.sendBroadcast(intent);
702 }
703
Dianne Hackbornd6847842010-01-12 18:14:19 -0800704 private void loadSettingsLocked() {
705 JournaledFile journal = makeJournaledFile();
706 FileInputStream stream = null;
707 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800708 try {
709 stream = new FileInputStream(file);
710 XmlPullParser parser = Xml.newPullParser();
711 parser.setInput(stream, null);
712
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800713 int type;
714 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
715 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800716 }
717 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800718 if (!"policies".equals(tag)) {
719 throw new XmlPullParserException(
720 "Settings do not start with policies tag: found " + tag);
721 }
722 type = parser.next();
723 int outerDepth = parser.getDepth();
724 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
725 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
726 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
727 continue;
728 }
729 tag = parser.getName();
730 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800731 String name = parser.getAttributeValue(null, "name");
732 try {
733 DeviceAdminInfo dai = findAdmin(
734 ComponentName.unflattenFromString(name));
735 if (dai != null) {
736 ActiveAdmin ap = new ActiveAdmin(dai);
737 ap.readFromXml(parser);
738 mAdminMap.put(ap.info.getComponent(), ap);
739 mAdminList.add(ap);
740 }
741 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700742 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800743 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800744 } else if ("failed-password-attempts".equals(tag)) {
745 mFailedPasswordAttempts = Integer.parseInt(
746 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800747 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800748 } else if ("password-owner".equals(tag)) {
749 mPasswordOwner = Integer.parseInt(
750 parser.getAttributeValue(null, "value"));
751 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700752 } else if ("active-password".equals(tag)) {
753 mActivePasswordQuality = Integer.parseInt(
754 parser.getAttributeValue(null, "quality"));
755 mActivePasswordLength = Integer.parseInt(
756 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700757 mActivePasswordUpperCase = Integer.parseInt(
758 parser.getAttributeValue(null, "uppercase"));
759 mActivePasswordLowerCase = Integer.parseInt(
760 parser.getAttributeValue(null, "lowercase"));
761 mActivePasswordLetters = Integer.parseInt(
762 parser.getAttributeValue(null, "letters"));
763 mActivePasswordNumeric = Integer.parseInt(
764 parser.getAttributeValue(null, "numeric"));
765 mActivePasswordSymbols = Integer.parseInt(
766 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700767 mActivePasswordNonLetter = Integer.parseInt(
768 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700769 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800770 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700771 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800772 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800773 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800774 }
775 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700776 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800777 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700778 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800779 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700780 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700781 } catch (FileNotFoundException e) {
782 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800783 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700784 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800785 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700786 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800787 }
788 try {
789 if (stream != null) {
790 stream.close();
791 }
792 } catch (IOException e) {
793 // Ignore
794 }
795
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700796 // Validate that what we stored for the password quality matches
797 // sufficiently what is currently set. Note that this is only
798 // a sanity check in case the two get out of sync; this should
799 // never normally happen.
800 LockPatternUtils utils = new LockPatternUtils(mContext);
801 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
802 Slog.w(TAG, "Active password quality 0x"
803 + Integer.toHexString(mActivePasswordQuality)
804 + " does not match actual quality 0x"
805 + Integer.toHexString(utils.getActivePasswordQuality()));
806 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
807 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700808 mActivePasswordUpperCase = 0;
809 mActivePasswordLowerCase = 0;
810 mActivePasswordLetters = 0;
811 mActivePasswordNumeric = 0;
812 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700813 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700814 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700815
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800816 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700817 syncDeviceCapabilitiesLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700818
Dianne Hackborn254cb442010-01-27 19:23:59 -0800819 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800820 if (timeMs <= 0) {
821 timeMs = Integer.MAX_VALUE;
822 }
823 try {
824 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
825 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700826 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800827 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800828 }
829
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700830 static void validateQualityConstant(int quality) {
831 switch (quality) {
832 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
833 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
834 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
835 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
836 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700837 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700838 return;
839 }
840 throw new IllegalArgumentException("Invalid quality constant: 0x"
841 + Integer.toHexString(quality));
842 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700843
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800844 void validatePasswordOwnerLocked() {
845 if (mPasswordOwner >= 0) {
846 boolean haveOwner = false;
847 for (int i=mAdminList.size()-1; i>=0; i--) {
848 if (mAdminList.get(i).getUid() == mPasswordOwner) {
849 haveOwner = true;
850 break;
851 }
852 }
853 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700854 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800855 + " no longer active; disabling");
856 mPasswordOwner = -1;
857 }
858 }
859 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700860
Ben Komalo2447edd2011-05-09 16:05:33 -0700861 /**
862 * Pushes down policy information to the system for any policies related to general device
863 * capabilities that need to be enforced by lower level services (e.g. Camera services).
864 */
865 void syncDeviceCapabilitiesLocked() {
866 // Ensure the status of the camera is synced down to the system. Interested native services
867 // should monitor this value and act accordingly.
868 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
869 boolean cameraDisabled = getCameraDisabled(null);
870 if (cameraDisabled != systemState) {
871 long token = Binder.clearCallingIdentity();
872 try {
873 String value = cameraDisabled ? "1" : "0";
874 Slog.v(TAG, "Change in camera state ["
875 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
876 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
877 } finally {
878 Binder.restoreCallingIdentity(token);
879 }
880 }
881 }
882
Dianne Hackbornd6847842010-01-12 18:14:19 -0800883 public void systemReady() {
884 synchronized (this) {
885 loadSettingsLocked();
886 }
887 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700888
Jim Millera4e28d12010-11-08 16:15:47 -0800889 private void handlePasswordExpirationNotification() {
890 synchronized (this) {
891 final long now = System.currentTimeMillis();
892 final int N = mAdminList.size();
893 if (N <= 0) {
894 return;
895 }
896 for (int i=0; i < N; i++) {
897 ActiveAdmin admin = mAdminList.get(i);
898 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
899 && admin.passwordExpirationTimeout > 0L
900 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800901 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800902 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
903 }
904 }
905 setExpirationAlarmCheckLocked(mContext);
906 }
907 }
908
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800909 /**
910 * @param adminReceiver The admin to add
911 * @param refreshing true = update an active admin, no error
912 */
913 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800914 mContext.enforceCallingOrSelfPermission(
915 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700916
Dianne Hackbornd6847842010-01-12 18:14:19 -0800917 DeviceAdminInfo info = findAdmin(adminReceiver);
918 if (info == null) {
919 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
920 }
921 synchronized (this) {
922 long ident = Binder.clearCallingIdentity();
923 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800924 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800925 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800926 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800927 ActiveAdmin newAdmin = new ActiveAdmin(info);
928 mAdminMap.put(adminReceiver, newAdmin);
929 int replaceIndex = -1;
930 if (refreshing) {
931 final int N = mAdminList.size();
932 for (int i=0; i < N; i++) {
933 ActiveAdmin oldAdmin = mAdminList.get(i);
934 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
935 replaceIndex = i;
936 break;
937 }
938 }
939 }
940 if (replaceIndex == -1) {
941 mAdminList.add(newAdmin);
942 } else {
943 mAdminList.set(replaceIndex, newAdmin);
944 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800945 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800946 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800947 } finally {
948 Binder.restoreCallingIdentity(ident);
949 }
950 }
951 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700952
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800953 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800954 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800955 return getActiveAdminUncheckedLocked(adminReceiver) != null;
956 }
957 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700958
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800959 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
960 synchronized (this) {
961 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
962 if (administrator == null) {
963 throw new SecurityException("No active admin " + adminReceiver);
964 }
965 return administrator.info.usesPolicy(policyId);
966 }
967 }
968
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800969 public List<ComponentName> getActiveAdmins() {
970 synchronized (this) {
971 final int N = mAdminList.size();
972 if (N <= 0) {
973 return null;
974 }
975 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
976 for (int i=0; i<N; i++) {
977 res.add(mAdminList.get(i).info.getComponent());
978 }
979 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800980 }
981 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700982
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800983 public boolean packageHasActiveAdmins(String packageName) {
984 synchronized (this) {
985 final int N = mAdminList.size();
986 for (int i=0; i<N; i++) {
987 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
988 return true;
989 }
990 }
991 return false;
992 }
993 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700994
Dianne Hackbornd6847842010-01-12 18:14:19 -0800995 public void removeActiveAdmin(ComponentName adminReceiver) {
996 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800997 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
998 if (admin == null) {
999 return;
1000 }
1001 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001002 mContext.enforceCallingOrSelfPermission(
1003 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1004 }
1005 long ident = Binder.clearCallingIdentity();
1006 try {
1007 removeActiveAdminLocked(adminReceiver);
1008 } finally {
1009 Binder.restoreCallingIdentity(ident);
1010 }
1011 }
1012 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001013
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001014 public void setPasswordQuality(ComponentName who, int quality) {
1015 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001016
Dianne Hackbornd6847842010-01-12 18:14:19 -08001017 synchronized (this) {
1018 if (who == null) {
1019 throw new NullPointerException("ComponentName is null");
1020 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001021 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1022 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001023 if (ap.passwordQuality != quality) {
1024 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001025 saveSettingsLocked();
1026 }
1027 }
1028 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001029
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001030 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001031 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001032 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001033
Dianne Hackborn254cb442010-01-27 19:23:59 -08001034 if (who != null) {
1035 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001036 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001037 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001038
Dianne Hackborn254cb442010-01-27 19:23:59 -08001039 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001040 for (int i=0; i<N; i++) {
1041 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001042 if (mode < admin.passwordQuality) {
1043 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001044 }
1045 }
1046 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001047 }
1048 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001049
Dianne Hackborn254cb442010-01-27 19:23:59 -08001050 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001051 synchronized (this) {
1052 if (who == null) {
1053 throw new NullPointerException("ComponentName is null");
1054 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001055 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1056 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001057 if (ap.minimumPasswordLength != length) {
1058 ap.minimumPasswordLength = length;
1059 saveSettingsLocked();
1060 }
1061 }
1062 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001063
Dianne Hackborn254cb442010-01-27 19:23:59 -08001064 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001065 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001066 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001067
Dianne Hackborn254cb442010-01-27 19:23:59 -08001068 if (who != null) {
1069 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1070 return admin != null ? admin.minimumPasswordLength : length;
1071 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001072
Dianne Hackborn254cb442010-01-27 19:23:59 -08001073 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001074 for (int i=0; i<N; i++) {
1075 ActiveAdmin admin = mAdminList.get(i);
1076 if (length < admin.minimumPasswordLength) {
1077 length = admin.minimumPasswordLength;
1078 }
1079 }
1080 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001081 }
1082 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001083
1084 public void setPasswordHistoryLength(ComponentName who, int length) {
1085 synchronized (this) {
1086 if (who == null) {
1087 throw new NullPointerException("ComponentName is null");
1088 }
1089 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1090 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1091 if (ap.passwordHistoryLength != length) {
1092 ap.passwordHistoryLength = length;
1093 saveSettingsLocked();
1094 }
1095 }
1096 }
1097
1098 public int getPasswordHistoryLength(ComponentName who) {
1099 synchronized (this) {
1100 int length = 0;
1101
1102 if (who != null) {
1103 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1104 return admin != null ? admin.passwordHistoryLength : length;
1105 }
1106
1107 final int N = mAdminList.size();
1108 for (int i = 0; i < N; i++) {
1109 ActiveAdmin admin = mAdminList.get(i);
1110 if (length < admin.passwordHistoryLength) {
1111 length = admin.passwordHistoryLength;
1112 }
1113 }
1114 return length;
1115 }
1116 }
1117
Jim Millera4e28d12010-11-08 16:15:47 -08001118 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1119 synchronized (this) {
1120 if (who == null) {
1121 throw new NullPointerException("ComponentName is null");
1122 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001123 if (timeout < 0) {
1124 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001125 }
1126 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1127 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1128 // Calling this API automatically bumps the expiration date
1129 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1130 ap.passwordExpirationDate = expiration;
1131 ap.passwordExpirationTimeout = timeout;
1132 if (timeout > 0L) {
1133 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1134 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1135 .format(new Date(expiration)));
1136 }
1137 saveSettingsLocked();
1138 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1139 }
1140 }
1141
Andy Stadler043116a2010-11-29 17:43:32 -08001142 /**
1143 * Return a single admin's expiration cycle time, or the min of all cycle times.
1144 * Returns 0 if not configured.
1145 */
Jim Millera4e28d12010-11-08 16:15:47 -08001146 public long getPasswordExpirationTimeout(ComponentName who) {
1147 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001148 if (who != null) {
1149 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001150 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001151 }
1152
Andy Stadler043116a2010-11-29 17:43:32 -08001153 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001154 final int N = mAdminList.size();
1155 for (int i = 0; i < N; i++) {
1156 ActiveAdmin admin = mAdminList.get(i);
1157 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1158 && timeout > admin.passwordExpirationTimeout)) {
1159 timeout = admin.passwordExpirationTimeout;
1160 }
1161 }
1162 return timeout;
1163 }
1164 }
1165
Andy Stadler043116a2010-11-29 17:43:32 -08001166 /**
1167 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1168 * Returns 0 if not configured.
1169 */
Jim Millera4e28d12010-11-08 16:15:47 -08001170 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001171 if (who != null) {
1172 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001173 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001174 }
1175
Andy Stadler043116a2010-11-29 17:43:32 -08001176 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001177 final int N = mAdminList.size();
1178 for (int i = 0; i < N; i++) {
1179 ActiveAdmin admin = mAdminList.get(i);
1180 if (timeout == 0L || (admin.passwordExpirationDate != 0
1181 && timeout > admin.passwordExpirationDate)) {
1182 timeout = admin.passwordExpirationDate;
1183 }
1184 }
1185 return timeout;
1186 }
1187
1188 public long getPasswordExpiration(ComponentName who) {
1189 synchronized (this) {
1190 return getPasswordExpirationLocked(who);
1191 }
1192 }
1193
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001194 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1195 synchronized (this) {
1196 if (who == null) {
1197 throw new NullPointerException("ComponentName is null");
1198 }
1199 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1200 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1201 if (ap.minimumPasswordUpperCase != length) {
1202 ap.minimumPasswordUpperCase = length;
1203 saveSettingsLocked();
1204 }
1205 }
1206 }
1207
1208 public int getPasswordMinimumUpperCase(ComponentName who) {
1209 synchronized (this) {
1210 int length = 0;
1211
1212 if (who != null) {
1213 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1214 return admin != null ? admin.minimumPasswordUpperCase : length;
1215 }
1216
1217 final int N = mAdminList.size();
1218 for (int i=0; i<N; i++) {
1219 ActiveAdmin admin = mAdminList.get(i);
1220 if (length < admin.minimumPasswordUpperCase) {
1221 length = admin.minimumPasswordUpperCase;
1222 }
1223 }
1224 return length;
1225 }
1226 }
1227
1228 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1229 synchronized (this) {
1230 if (who == null) {
1231 throw new NullPointerException("ComponentName is null");
1232 }
1233 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1234 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1235 if (ap.minimumPasswordLowerCase != length) {
1236 ap.minimumPasswordLowerCase = length;
1237 saveSettingsLocked();
1238 }
1239 }
1240 }
1241
1242 public int getPasswordMinimumLowerCase(ComponentName who) {
1243 synchronized (this) {
1244 int length = 0;
1245
1246 if (who != null) {
1247 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1248 return admin != null ? admin.minimumPasswordLowerCase : length;
1249 }
1250
1251 final int N = mAdminList.size();
1252 for (int i=0; i<N; i++) {
1253 ActiveAdmin admin = mAdminList.get(i);
1254 if (length < admin.minimumPasswordLowerCase) {
1255 length = admin.minimumPasswordLowerCase;
1256 }
1257 }
1258 return length;
1259 }
1260 }
1261
1262 public void setPasswordMinimumLetters(ComponentName who, int length) {
1263 synchronized (this) {
1264 if (who == null) {
1265 throw new NullPointerException("ComponentName is null");
1266 }
1267 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1268 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1269 if (ap.minimumPasswordLetters != length) {
1270 ap.minimumPasswordLetters = length;
1271 saveSettingsLocked();
1272 }
1273 }
1274 }
1275
1276 public int getPasswordMinimumLetters(ComponentName who) {
1277 synchronized (this) {
1278 int length = 0;
1279
1280 if (who != null) {
1281 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1282 return admin != null ? admin.minimumPasswordLetters : length;
1283 }
1284
1285 final int N = mAdminList.size();
1286 for (int i=0; i<N; i++) {
1287 ActiveAdmin admin = mAdminList.get(i);
1288 if (length < admin.minimumPasswordLetters) {
1289 length = admin.minimumPasswordLetters;
1290 }
1291 }
1292 return length;
1293 }
1294 }
1295
1296 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1297 synchronized (this) {
1298 if (who == null) {
1299 throw new NullPointerException("ComponentName is null");
1300 }
1301 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1302 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1303 if (ap.minimumPasswordNumeric != length) {
1304 ap.minimumPasswordNumeric = length;
1305 saveSettingsLocked();
1306 }
1307 }
1308 }
1309
1310 public int getPasswordMinimumNumeric(ComponentName who) {
1311 synchronized (this) {
1312 int length = 0;
1313
1314 if (who != null) {
1315 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1316 return admin != null ? admin.minimumPasswordNumeric : length;
1317 }
1318
1319 final int N = mAdminList.size();
1320 for (int i = 0; i < N; i++) {
1321 ActiveAdmin admin = mAdminList.get(i);
1322 if (length < admin.minimumPasswordNumeric) {
1323 length = admin.minimumPasswordNumeric;
1324 }
1325 }
1326 return length;
1327 }
1328 }
1329
1330 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1331 synchronized (this) {
1332 if (who == null) {
1333 throw new NullPointerException("ComponentName is null");
1334 }
1335 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1336 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1337 if (ap.minimumPasswordSymbols != length) {
1338 ap.minimumPasswordSymbols = length;
1339 saveSettingsLocked();
1340 }
1341 }
1342 }
1343
1344 public int getPasswordMinimumSymbols(ComponentName who) {
1345 synchronized (this) {
1346 int length = 0;
1347
1348 if (who != null) {
1349 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1350 return admin != null ? admin.minimumPasswordSymbols : length;
1351 }
1352
1353 final int N = mAdminList.size();
1354 for (int i=0; i<N; i++) {
1355 ActiveAdmin admin = mAdminList.get(i);
1356 if (length < admin.minimumPasswordSymbols) {
1357 length = admin.minimumPasswordSymbols;
1358 }
1359 }
1360 return length;
1361 }
1362 }
1363
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001364 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1365 synchronized (this) {
1366 if (who == null) {
1367 throw new NullPointerException("ComponentName is null");
1368 }
1369 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1370 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1371 if (ap.minimumPasswordNonLetter != length) {
1372 ap.minimumPasswordNonLetter = length;
1373 saveSettingsLocked();
1374 }
1375 }
1376 }
1377
1378 public int getPasswordMinimumNonLetter(ComponentName who) {
1379 synchronized (this) {
1380 int length = 0;
1381
1382 if (who != null) {
1383 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1384 return admin != null ? admin.minimumPasswordNonLetter : length;
1385 }
1386
1387 final int N = mAdminList.size();
1388 for (int i=0; i<N; i++) {
1389 ActiveAdmin admin = mAdminList.get(i);
1390 if (length < admin.minimumPasswordNonLetter) {
1391 length = admin.minimumPasswordNonLetter;
1392 }
1393 }
1394 return length;
1395 }
1396 }
1397
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001398 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001399 synchronized (this) {
1400 // This API can only be called by an active device admin,
1401 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001402 getActiveAdminForCallerLocked(null,
1403 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001404 if (mActivePasswordQuality < getPasswordQuality(null)
1405 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1406 return false;
1407 }
1408 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1409 return true;
1410 }
1411 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1412 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1413 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1414 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001415 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1416 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001417 }
1418 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001419
Dianne Hackbornd6847842010-01-12 18:14:19 -08001420 public int getCurrentFailedPasswordAttempts() {
1421 synchronized (this) {
1422 // This API can only be called by an active device admin,
1423 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001424 getActiveAdminForCallerLocked(null,
1425 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001426 return mFailedPasswordAttempts;
1427 }
1428 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001429
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001430 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1431 synchronized (this) {
1432 // This API can only be called by an active device admin,
1433 // so try to retrieve it to check that the caller is one.
1434 getActiveAdminForCallerLocked(who,
1435 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1436 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1437 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1438 if (ap.maximumFailedPasswordsForWipe != num) {
1439 ap.maximumFailedPasswordsForWipe = num;
1440 saveSettingsLocked();
1441 }
1442 }
1443 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001444
Dianne Hackborn254cb442010-01-27 19:23:59 -08001445 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001446 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001447 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001448
Dianne Hackborn254cb442010-01-27 19:23:59 -08001449 if (who != null) {
1450 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1451 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1452 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001453
Dianne Hackborn254cb442010-01-27 19:23:59 -08001454 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001455 for (int i=0; i<N; i++) {
1456 ActiveAdmin admin = mAdminList.get(i);
1457 if (count == 0) {
1458 count = admin.maximumFailedPasswordsForWipe;
1459 } else if (admin.maximumFailedPasswordsForWipe != 0
1460 && count > admin.maximumFailedPasswordsForWipe) {
1461 count = admin.maximumFailedPasswordsForWipe;
1462 }
1463 }
1464 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001465 }
1466 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001467
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001468 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001469 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001470 synchronized (this) {
1471 // This API can only be called by an active device admin,
1472 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001473 getActiveAdminForCallerLocked(null,
1474 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001475 quality = getPasswordQuality(null);
1476 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001477 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001478 if (realQuality < quality
1479 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001480 Slog.w(TAG, "resetPassword: password quality 0x"
1481 + Integer.toHexString(quality)
1482 + " does not meet required quality 0x"
1483 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001484 return false;
1485 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001486 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001487 }
1488 int length = getPasswordMinimumLength(null);
1489 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001490 Slog.w(TAG, "resetPassword: password length " + password.length()
1491 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001492 return false;
1493 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001494 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1495 int letters = 0;
1496 int uppercase = 0;
1497 int lowercase = 0;
1498 int numbers = 0;
1499 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001500 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001501 for (int i = 0; i < password.length(); i++) {
1502 char c = password.charAt(i);
1503 if (c >= 'A' && c <= 'Z') {
1504 letters++;
1505 uppercase++;
1506 } else if (c >= 'a' && c <= 'z') {
1507 letters++;
1508 lowercase++;
1509 } else if (c >= '0' && c <= '9') {
1510 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001511 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001512 } else {
1513 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001514 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001515 }
1516 }
1517 int neededLetters = getPasswordMinimumLetters(null);
1518 if(letters < neededLetters) {
1519 Slog.w(TAG, "resetPassword: number of letters " + letters
1520 + " does not meet required number of letters " + neededLetters);
1521 return false;
1522 }
1523 int neededNumbers = getPasswordMinimumNumeric(null);
1524 if (numbers < neededNumbers) {
1525 Slog
1526 .w(TAG, "resetPassword: number of numerical digits " + numbers
1527 + " does not meet required number of numerical digits "
1528 + neededNumbers);
1529 return false;
1530 }
1531 int neededLowerCase = getPasswordMinimumLowerCase(null);
1532 if (lowercase < neededLowerCase) {
1533 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1534 + " does not meet required number of lowercase letters "
1535 + neededLowerCase);
1536 return false;
1537 }
1538 int neededUpperCase = getPasswordMinimumUpperCase(null);
1539 if (uppercase < neededUpperCase) {
1540 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1541 + " does not meet required number of uppercase letters "
1542 + neededUpperCase);
1543 return false;
1544 }
1545 int neededSymbols = getPasswordMinimumSymbols(null);
1546 if (symbols < neededSymbols) {
1547 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1548 + " does not meet required number of special symbols " + neededSymbols);
1549 return false;
1550 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001551 int neededNonLetter = getPasswordMinimumNonLetter(null);
1552 if (nonletter < neededNonLetter) {
1553 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1554 + " does not meet required number of non-letter characters "
1555 + neededNonLetter);
1556 return false;
1557 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001558 }
1559
1560 LockPatternUtils utils = new LockPatternUtils(mContext);
1561 if(utils.checkPasswordHistory(password)) {
1562 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1563 + getPasswordHistoryLength(null) + " passwords");
1564 return false;
1565 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001566 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001567
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001568 int callingUid = Binder.getCallingUid();
1569 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001570 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001571 return false;
1572 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001573
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001574 // Don't do this with the lock held, because it is going to call
1575 // back in to the service.
1576 long ident = Binder.clearCallingIdentity();
1577 try {
1578 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001579 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001580 synchronized (this) {
1581 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1582 != 0 ? callingUid : -1;
1583 if (mPasswordOwner != newOwner) {
1584 mPasswordOwner = newOwner;
1585 saveSettingsLocked();
1586 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001587 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001588 } finally {
1589 Binder.restoreCallingIdentity(ident);
1590 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001591
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001592 return true;
1593 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001594
Dianne Hackbornd6847842010-01-12 18:14:19 -08001595 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1596 synchronized (this) {
1597 if (who == null) {
1598 throw new NullPointerException("ComponentName is null");
1599 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001600 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001601 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001602 if (ap.maximumTimeToUnlock != timeMs) {
1603 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001604
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001605 long ident = Binder.clearCallingIdentity();
1606 try {
1607 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001608
Dianne Hackborn254cb442010-01-27 19:23:59 -08001609 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001610 if (timeMs <= 0) {
1611 timeMs = Integer.MAX_VALUE;
1612 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001613
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001614 try {
1615 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1616 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001617 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001618 }
1619 } finally {
1620 Binder.restoreCallingIdentity(ident);
1621 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001622 }
1623 }
1624 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001625
Dianne Hackborn254cb442010-01-27 19:23:59 -08001626 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001627 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001628 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001629
Dianne Hackborn254cb442010-01-27 19:23:59 -08001630 if (who != null) {
1631 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1632 return admin != null ? admin.maximumTimeToUnlock : time;
1633 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001634
Dianne Hackborn254cb442010-01-27 19:23:59 -08001635 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001636 for (int i=0; i<N; i++) {
1637 ActiveAdmin admin = mAdminList.get(i);
1638 if (time == 0) {
1639 time = admin.maximumTimeToUnlock;
1640 } else if (admin.maximumTimeToUnlock != 0
1641 && time > admin.maximumTimeToUnlock) {
1642 time = admin.maximumTimeToUnlock;
1643 }
1644 }
1645 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001646 }
1647 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001648
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001649 public void lockNow() {
1650 synchronized (this) {
1651 // This API can only be called by an active device admin,
1652 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001653 getActiveAdminForCallerLocked(null,
1654 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001655 long ident = Binder.clearCallingIdentity();
1656 try {
1657 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1658 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1659 } catch (RemoteException e) {
1660 } finally {
1661 Binder.restoreCallingIdentity(ident);
1662 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001663 }
1664 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001665
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001666 void wipeDataLocked(int flags) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001667 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
1668 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1669 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1670 mWakeLock.acquire(10000);
1671 mContext.startService(intent);
1672 } else {
1673 try {
1674 RecoverySystem.rebootWipeUserData(mContext);
1675 } catch (IOException e) {
1676 Slog.w(TAG, "Failed requesting data wipe", e);
1677 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001678 }
1679 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001680
Dianne Hackbornd6847842010-01-12 18:14:19 -08001681 public void wipeData(int flags) {
1682 synchronized (this) {
1683 // This API can only be called by an active device admin,
1684 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001685 getActiveAdminForCallerLocked(null,
1686 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001687 long ident = Binder.clearCallingIdentity();
1688 try {
1689 wipeDataLocked(flags);
1690 } finally {
1691 Binder.restoreCallingIdentity(ident);
1692 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001693 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001694 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001695
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001696 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1697 mContext.enforceCallingOrSelfPermission(
1698 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001699
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001700 synchronized (this) {
1701 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1702 if (admin == null) {
1703 try {
1704 result.sendResult(null);
1705 } catch (RemoteException e) {
1706 }
1707 return;
1708 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001709 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001710 intent.setComponent(admin.info.getComponent());
1711 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1712 @Override
1713 public void onReceive(Context context, Intent intent) {
1714 try {
1715 result.sendResult(getResultExtras(false));
1716 } catch (RemoteException e) {
1717 }
1718 }
1719 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001720 }
1721 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001722
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001723 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001724 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001725 mContext.enforceCallingOrSelfPermission(
1726 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001727
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001728 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001729
Dianne Hackbornd6847842010-01-12 18:14:19 -08001730 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001731 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001732 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1733 || mActivePasswordUpperCase != uppercase
1734 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001735 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001736 long ident = Binder.clearCallingIdentity();
1737 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001738 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001739 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001740 mActivePasswordLetters = letters;
1741 mActivePasswordLowerCase = lowercase;
1742 mActivePasswordUpperCase = uppercase;
1743 mActivePasswordNumeric = numbers;
1744 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001745 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001746 mFailedPasswordAttempts = 0;
1747 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001748 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001749 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001750 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001751 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001752 } finally {
1753 Binder.restoreCallingIdentity(ident);
1754 }
1755 }
1756 }
1757 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001758
Andy Stadler043116a2010-11-29 17:43:32 -08001759 /**
1760 * Called any time the device password is updated. Resets all password expiration clocks.
1761 */
Jim Millera4e28d12010-11-08 16:15:47 -08001762 private void updatePasswordExpirationsLocked() {
1763 final int N = mAdminList.size();
1764 if (N > 0) {
1765 for (int i=0; i<N; i++) {
1766 ActiveAdmin admin = mAdminList.get(i);
1767 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001768 long timeout = admin.passwordExpirationTimeout;
1769 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1770 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001771 }
1772 }
1773 saveSettingsLocked();
1774 }
1775 }
1776
Dianne Hackbornd6847842010-01-12 18:14:19 -08001777 public void reportFailedPasswordAttempt() {
1778 mContext.enforceCallingOrSelfPermission(
1779 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001780
Dianne Hackbornd6847842010-01-12 18:14:19 -08001781 synchronized (this) {
1782 long ident = Binder.clearCallingIdentity();
1783 try {
1784 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001785 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001786 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001787 if (max > 0 && mFailedPasswordAttempts >= max) {
1788 wipeDataLocked(0);
1789 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001790 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001791 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001792 } finally {
1793 Binder.restoreCallingIdentity(ident);
1794 }
1795 }
1796 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001797
Dianne Hackbornd6847842010-01-12 18:14:19 -08001798 public void reportSuccessfulPasswordAttempt() {
1799 mContext.enforceCallingOrSelfPermission(
1800 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001801
Dianne Hackbornd6847842010-01-12 18:14:19 -08001802 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001803 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001804 long ident = Binder.clearCallingIdentity();
1805 try {
1806 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001807 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001808 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001809 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001810 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001811 } finally {
1812 Binder.restoreCallingIdentity(ident);
1813 }
1814 }
1815 }
1816 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001817
Oscar Montemayor69238c62010-08-03 10:51:06 -07001818 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1819 String exclusionList) {
1820 synchronized(this) {
1821 if (who == null) {
1822 throw new NullPointerException("ComponentName is null");
1823 }
1824
1825 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1826 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1827
1828 // Scan through active admins and find if anyone has already
1829 // set the global proxy.
Oscar Montemayor69238c62010-08-03 10:51:06 -07001830 Set<ComponentName> compSet = mAdminMap.keySet();
1831 for (ComponentName component : compSet) {
1832 ActiveAdmin ap = mAdminMap.get(component);
1833 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1834 // Another admin already sets the global proxy
1835 // Return it to the caller.
1836 return component;
1837 }
1838 }
1839 if (proxySpec == null) {
1840 admin.specifiesGlobalProxy = false;
1841 admin.globalProxySpec = null;
1842 admin.globalProxyExclusionList = null;
1843 } else {
1844
1845 admin.specifiesGlobalProxy = true;
1846 admin.globalProxySpec = proxySpec;
1847 admin.globalProxyExclusionList = exclusionList;
1848 }
1849
1850 // Reset the global proxy accordingly
1851 // Do this using system permissions, as apps cannot write to secure settings
1852 long origId = Binder.clearCallingIdentity();
1853 resetGlobalProxy();
1854 Binder.restoreCallingIdentity(origId);
1855 return null;
1856 }
1857 }
1858
1859 public ComponentName getGlobalProxyAdmin() {
1860 synchronized(this) {
1861 // Scan through active admins and find if anyone has already
1862 // set the global proxy.
1863 final int N = mAdminList.size();
1864 for (int i = 0; i < N; i++) {
1865 ActiveAdmin ap = mAdminList.get(i);
1866 if (ap.specifiesGlobalProxy) {
1867 // Device admin sets the global proxy
1868 // Return it to the caller.
1869 return ap.info.getComponent();
1870 }
1871 }
1872 }
1873 // No device admin sets the global proxy.
1874 return null;
1875 }
1876
1877 private void resetGlobalProxy() {
1878 final int N = mAdminList.size();
1879 for (int i = 0; i < N; i++) {
1880 ActiveAdmin ap = mAdminList.get(i);
1881 if (ap.specifiesGlobalProxy) {
1882 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1883 return;
1884 }
1885 }
1886 // No device admins defining global proxies - reset global proxy settings to none
1887 saveGlobalProxy(null, null);
1888 }
1889
1890 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1891 if (exclusionList == null) {
1892 exclusionList = "";
1893 }
1894 if (proxySpec == null) {
1895 proxySpec = "";
1896 }
1897 // Remove white spaces
1898 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001899 String data[] = proxySpec.split(":");
1900 int proxyPort = 8080;
1901 if (data.length > 1) {
1902 try {
1903 proxyPort = Integer.parseInt(data[1]);
1904 } catch (NumberFormatException e) {}
1905 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001906 exclusionList = exclusionList.trim();
1907 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001908 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1909 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1910 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1911 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001912 }
1913
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001914 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001915 * Set the storage encryption request for a single admin. Returns the new total request
1916 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001917 */
1918 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1919 synchronized (this) {
1920 // Check for permissions
1921 if (who == null) {
1922 throw new NullPointerException("ComponentName is null");
1923 }
1924 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1925 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1926
Andy Stadler22dbfda2011-01-17 12:47:31 -08001927 // Quick exit: If the filesystem does not support encryption, we can exit early.
1928 if (!isEncryptionSupported()) {
1929 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1930 }
1931
1932 // (1) Record the value for the admin so it's sticky
1933 if (ap.encryptionRequested != encrypt) {
1934 ap.encryptionRequested = encrypt;
1935 saveSettingsLocked();
1936 }
1937
1938 // (2) Compute "max" for all admins
1939 boolean newRequested = false;
1940 final int N = mAdminList.size();
1941 for (int i = 0; i < N; i++) {
1942 newRequested |= mAdminList.get(i).encryptionRequested;
1943 }
1944
1945 // Notify OS of new request
1946 setEncryptionRequested(newRequested);
1947
1948 // Return the new global request status
1949 return newRequested
1950 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1951 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001952 }
1953 }
1954
1955 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001956 * Get the current storage encryption request status for a given admin, or aggregate of all
1957 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001958 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08001959 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001960 synchronized (this) {
1961 // Check for permissions if a particular caller is specified
1962 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08001963 // When checking for a single caller, status is based on caller's request
Andy Stadlerc994d692011-06-01 15:30:54 -07001964 ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
1965 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001966 }
1967
Andy Stadler22dbfda2011-01-17 12:47:31 -08001968 // If no particular caller is specified, return the aggregate set of requests.
1969 // This is short circuited by returning true on the first hit.
1970 final int N = mAdminList.size();
1971 for (int i = 0; i < N; i++) {
1972 if (mAdminList.get(i).encryptionRequested) {
1973 return true;
1974 }
1975 }
1976 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001977 }
1978 }
1979
Andy Stadler22dbfda2011-01-17 12:47:31 -08001980 /**
1981 * Get the current encryption status of the device.
1982 */
1983 public int getStorageEncryptionStatus() {
1984 return getEncryptionStatus();
1985 }
1986
1987 /**
1988 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
1989 */
1990 private boolean isEncryptionSupported() {
1991 // Note, this can be implemented as
1992 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1993 // But is provided as a separate internal method if there's a faster way to do a
1994 // simple check for supported-or-not.
1995 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1996 }
1997
1998 /**
1999 * Hook to low-levels: Reporting the current status of encryption.
2000 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2001 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2002 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2003 */
2004 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002005 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2006 if ("encrypted".equalsIgnoreCase(status)) {
2007 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2008 } else if ("unencrypted".equalsIgnoreCase(status)) {
2009 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2010 } else {
2011 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2012 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002013 }
2014
2015 /**
2016 * Hook to low-levels: If needed, record the new admin setting for encryption.
2017 */
2018 private void setEncryptionRequested(boolean encrypt) {
2019 }
2020
Ben Komalo2447edd2011-05-09 16:05:33 -07002021 /**
2022 * The system property used to share the state of the camera. The native camera service
2023 * is expected to read this property and act accordingly.
2024 */
2025 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2026
2027 /**
2028 * Disables all device cameras according to the specified admin.
2029 */
2030 public void setCameraDisabled(ComponentName who, boolean disabled) {
2031 synchronized (this) {
2032 if (who == null) {
2033 throw new NullPointerException("ComponentName is null");
2034 }
2035 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2036 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2037 if (ap.disableCamera != disabled) {
2038 ap.disableCamera = disabled;
2039 saveSettingsLocked();
2040 }
2041 syncDeviceCapabilitiesLocked();
2042 }
2043 }
2044
2045 /**
2046 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2047 * active admins.
2048 */
2049 public boolean getCameraDisabled(ComponentName who) {
2050 synchronized (this) {
2051 if (who != null) {
2052 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
2053 return (admin != null) ? admin.disableCamera : false;
2054 }
2055
2056 // Determine whether or not the device camera is disabled for any active admins.
2057 final int N = mAdminList.size();
2058 for (int i = 0; i < N; i++) {
2059 ActiveAdmin admin = mAdminList.get(i);
2060 if (admin.disableCamera) {
2061 return true;
2062 }
2063 }
2064 return false;
2065 }
2066 }
2067
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002068 @Override
2069 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2070 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2071 != PackageManager.PERMISSION_GRANTED) {
2072
2073 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2074 + Binder.getCallingPid()
2075 + ", uid=" + Binder.getCallingUid());
2076 return;
2077 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002078
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002079 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002080
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002081 synchronized (this) {
2082 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002083
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002084 p.println(" Enabled Device Admins:");
2085 final int N = mAdminList.size();
2086 for (int i=0; i<N; i++) {
2087 ActiveAdmin ap = mAdminList.get(i);
2088 if (ap != null) {
2089 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2090 pw.println(":");
2091 ap.dump(" ", pw);
2092 }
2093 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002094
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002095 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002096 pw.print(" mActivePasswordQuality=0x");
2097 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002098 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002099 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
2100 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
2101 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
2102 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
2103 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07002104 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002105 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
2106 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
2107 }
2108 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002109}