blob: e8ca3ce8475d3e2fe43be5772c5c9d7675ea233e [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;
Ben Komaloed48c8b2011-10-17 17:30:21 -070047import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080048import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080049import android.os.IBinder;
50import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070051import android.os.PowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080052import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080053import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080054import android.os.RemoteException;
55import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080056import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080057import android.os.SystemProperties;
Oscar Montemayor69238c62010-08-03 10:51:06 -070058import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080059import android.util.PrintWriterPrinter;
60import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080061import android.util.Slog;
Dianne Hackbornd6847842010-01-12 18:14:19 -080062import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080063import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080064
65import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080066import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080067import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070068import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080069import java.io.FileOutputStream;
70import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080071import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080072import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080073import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080074import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080075import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080076import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070077import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080078
79/**
80 * Implementation of the device policy APIs.
81 */
82public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Jim Miller6b857682011-02-16 16:27:41 -080083 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080084
Jim Miller6b857682011-02-16 16:27:41 -080085 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070086
Jim Millera4e28d12010-11-08 16:15:47 -080087 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
88
89 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
90 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
91
92 private static final long MS_PER_DAY = 86400 * 1000;
Jim Millera4e28d12010-11-08 16:15:47 -080093
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080094 final Context mContext;
95 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070096 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080097
Dianne Hackborndf83afa2010-01-20 13:37:26 -080098 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070099
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800100 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800101 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700102 int mActivePasswordUpperCase = 0;
103 int mActivePasswordLowerCase = 0;
104 int mActivePasswordLetters = 0;
105 int mActivePasswordNumeric = 0;
106 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700107 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800108 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700109
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800110 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800111 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700112
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800113 final HashMap<ComponentName, ActiveAdmin> mAdminMap
114 = new HashMap<ComponentName, ActiveAdmin>();
115 final ArrayList<ActiveAdmin> mAdminList
116 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700117
Jim Millera4e28d12010-11-08 16:15:47 -0800118 BroadcastReceiver mReceiver = new BroadcastReceiver() {
119 @Override
120 public void onReceive(Context context, Intent intent) {
121 String action = intent.getAction();
122 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
123 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
124 Slog.v(TAG, "Sending password expiration notifications for action " + action);
125 mHandler.post(new Runnable() {
126 public void run() {
127 handlePasswordExpirationNotification();
128 }
129 });
130 }
131 }
132 };
133
Dianne Hackbornd6847842010-01-12 18:14:19 -0800134 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800135 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700136
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800137 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700138
139 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
140 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
141
142 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
143 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
144
145 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
146 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
147
148 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
149 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
150
151 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700152 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700153
154 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
155 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
156
157 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
158 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
159
160 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
161 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
162
163 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
164 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
165
166 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
167 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
168
169 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
170 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
171
172 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
173 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
174
Andy Stadler22dbfda2011-01-17 12:47:31 -0800175 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700176 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700177
Oscar Montemayor69238c62010-08-03 10:51:06 -0700178 // TODO: review implementation decisions with frameworks team
179 boolean specifiesGlobalProxy = false;
180 String globalProxySpec = null;
181 String globalProxyExclusionList = null;
182
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800183 ActiveAdmin(DeviceAdminInfo _info) {
184 info = _info;
185 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700186
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800187 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700188
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800189 void writeToXml(XmlSerializer out)
190 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800191 out.startTag(null, "policies");
192 info.writePoliciesToXml(out);
193 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800194 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
195 out.startTag(null, "password-quality");
196 out.attribute(null, "value", Integer.toString(passwordQuality));
197 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700198 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800199 out.startTag(null, "min-password-length");
200 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700201 out.endTag(null, "min-password-length");
202 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700203 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700204 out.startTag(null, "password-history-length");
205 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
206 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800207 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700208 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700209 out.startTag(null, "min-password-uppercase");
210 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
211 out.endTag(null, "min-password-uppercase");
212 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700213 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700214 out.startTag(null, "min-password-lowercase");
215 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
216 out.endTag(null, "min-password-lowercase");
217 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700218 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700219 out.startTag(null, "min-password-letters");
220 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
221 out.endTag(null, "min-password-letters");
222 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700223 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700224 out.startTag(null, "min-password-numeric");
225 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
226 out.endTag(null, "min-password-numeric");
227 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700228 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700229 out.startTag(null, "min-password-symbols");
230 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
231 out.endTag(null, "min-password-symbols");
232 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700233 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700234 out.startTag(null, "min-password-nonletter");
235 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
236 out.endTag(null, "min-password-nonletter");
237 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800238 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700239 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800240 out.startTag(null, "max-time-to-unlock");
241 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
242 out.endTag(null, "max-time-to-unlock");
243 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700244 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800245 out.startTag(null, "max-failed-password-wipe");
246 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
247 out.endTag(null, "max-failed-password-wipe");
248 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700249 if (specifiesGlobalProxy) {
250 out.startTag(null, "specifies-global-proxy");
251 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
252 out.endTag(null, "specifies_global_proxy");
253 if (globalProxySpec != null) {
254 out.startTag(null, "global-proxy-spec");
255 out.attribute(null, "value", globalProxySpec);
256 out.endTag(null, "global-proxy-spec");
257 }
258 if (globalProxyExclusionList != null) {
259 out.startTag(null, "global-proxy-exclusion-list");
260 out.attribute(null, "value", globalProxyExclusionList);
261 out.endTag(null, "global-proxy-exclusion-list");
262 }
263 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700264 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800265 out.startTag(null, "password-expiration-timeout");
266 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
267 out.endTag(null, "password-expiration-timeout");
268 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700269 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800270 out.startTag(null, "password-expiration-date");
271 out.attribute(null, "value", Long.toString(passwordExpirationDate));
272 out.endTag(null, "password-expiration-date");
273 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800274 if (encryptionRequested) {
275 out.startTag(null, "encryption-requested");
276 out.attribute(null, "value", Boolean.toString(encryptionRequested));
277 out.endTag(null, "encryption-requested");
278 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700279 if (disableCamera) {
280 out.startTag(null, "disable-camera");
281 out.attribute(null, "value", Boolean.toString(disableCamera));
282 out.endTag(null, "disable-camera");
283 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800284 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700285
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800286 void readFromXml(XmlPullParser parser)
287 throws XmlPullParserException, IOException {
288 int outerDepth = parser.getDepth();
289 int type;
290 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
291 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
292 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
293 continue;
294 }
295 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800296 if ("policies".equals(tag)) {
297 info.readPoliciesFromXml(parser);
298 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800299 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800300 parser.getAttributeValue(null, "value"));
301 } else if ("min-password-length".equals(tag)) {
302 minimumPasswordLength = Integer.parseInt(
303 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700304 } else if ("password-history-length".equals(tag)) {
305 passwordHistoryLength = Integer.parseInt(
306 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700307 } else if ("min-password-uppercase".equals(tag)) {
308 minimumPasswordUpperCase = Integer.parseInt(
309 parser.getAttributeValue(null, "value"));
310 } else if ("min-password-lowercase".equals(tag)) {
311 minimumPasswordLowerCase = Integer.parseInt(
312 parser.getAttributeValue(null, "value"));
313 } else if ("min-password-letters".equals(tag)) {
314 minimumPasswordLetters = Integer.parseInt(
315 parser.getAttributeValue(null, "value"));
316 } else if ("min-password-numeric".equals(tag)) {
317 minimumPasswordNumeric = Integer.parseInt(
318 parser.getAttributeValue(null, "value"));
319 } else if ("min-password-symbols".equals(tag)) {
320 minimumPasswordSymbols = Integer.parseInt(
321 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700322 } else if ("min-password-nonletter".equals(tag)) {
323 minimumPasswordNonLetter = Integer.parseInt(
324 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800325 } else if ("max-time-to-unlock".equals(tag)) {
326 maximumTimeToUnlock = Long.parseLong(
327 parser.getAttributeValue(null, "value"));
328 } else if ("max-failed-password-wipe".equals(tag)) {
329 maximumFailedPasswordsForWipe = Integer.parseInt(
330 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700331 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800332 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700333 parser.getAttributeValue(null, "value"));
334 } else if ("global-proxy-spec".equals(tag)) {
335 globalProxySpec =
336 parser.getAttributeValue(null, "value");
337 } else if ("global-proxy-exclusion-list".equals(tag)) {
338 globalProxyExclusionList =
339 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800340 } else if ("password-expiration-timeout".equals(tag)) {
341 passwordExpirationTimeout = Long.parseLong(
342 parser.getAttributeValue(null, "value"));
343 } else if ("password-expiration-date".equals(tag)) {
344 passwordExpirationDate = Long.parseLong(
345 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800346 } else if ("encryption-requested".equals(tag)) {
347 encryptionRequested = Boolean.parseBoolean(
348 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700349 } else if ("disable-camera".equals(tag)) {
350 disableCamera = Boolean.parseBoolean(
351 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800352 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700353 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800354 }
355 XmlUtils.skipCurrentTag(parser);
356 }
357 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700358
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800359 void dump(String prefix, PrintWriter pw) {
360 pw.print(prefix); pw.print("uid="); pw.println(getUid());
361 pw.print(prefix); pw.println("policies:");
362 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
363 if (pols != null) {
364 for (int i=0; i<pols.size(); i++) {
365 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
366 }
367 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700368 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700369 pw.println(Integer.toHexString(passwordQuality));
370 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800371 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700372 pw.print(prefix); pw.print("passwordHistoryLength=");
373 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700374 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
375 pw.println(minimumPasswordUpperCase);
376 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
377 pw.println(minimumPasswordLowerCase);
378 pw.print(prefix); pw.print("minimumPasswordLetters=");
379 pw.println(minimumPasswordLetters);
380 pw.print(prefix); pw.print("minimumPasswordNumeric=");
381 pw.println(minimumPasswordNumeric);
382 pw.print(prefix); pw.print("minimumPasswordSymbols=");
383 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700384 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
385 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800386 pw.print(prefix); pw.print("maximumTimeToUnlock=");
387 pw.println(maximumTimeToUnlock);
388 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
389 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700390 pw.print(prefix); pw.print("specifiesGlobalProxy=");
391 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800392 pw.print(prefix); pw.print("passwordExpirationTimeout=");
393 pw.println(passwordExpirationTimeout);
394 pw.print(prefix); pw.print("passwordExpirationDate=");
395 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700396 if (globalProxySpec != null) {
397 pw.print(prefix); pw.print("globalProxySpec=");
398 pw.println(globalProxySpec);
399 }
400 if (globalProxyExclusionList != null) {
401 pw.print(prefix); pw.print("globalProxyEclusionList=");
402 pw.println(globalProxyExclusionList);
403 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800404 pw.print(prefix); pw.print("encryptionRequested=");
405 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700406 pw.print(prefix); pw.print("disableCamera=");
407 pw.println(disableCamera);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800408 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800409 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700410
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800411 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800412 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800413 public void onSomePackagesChanged() {
414 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800415 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800416 for (int i=mAdminList.size()-1; i>=0; i--) {
417 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700418 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800419 if (change == PACKAGE_PERMANENT_CHANGE
420 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700421 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800422 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800423 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800424 mAdminList.remove(i);
425 } else if (isPackageModified(aa.info.getPackageName())) {
426 try {
427 mContext.getPackageManager().getReceiverInfo(
428 aa.info.getComponent(), 0);
429 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700430 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800431 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800432 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800433 mAdminList.remove(i);
434 }
435 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800436 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800437 if (removed) {
438 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700439 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700440 saveSettingsLocked();
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800441 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800442 }
443 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800444 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700445
Dianne Hackbornd6847842010-01-12 18:14:19 -0800446 /**
447 * Instantiates the service.
448 */
449 public DevicePolicyManagerService(Context context) {
450 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800451 mMonitor = new MyPackageMonitor();
452 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700453 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
454 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800455 IntentFilter filter = new IntentFilter();
456 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
457 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
458 context.registerReceiver(mReceiver, filter);
459 }
460
Andy Stadler043116a2010-11-29 17:43:32 -0800461 /**
462 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
463 * reminders. Clears alarm if no expirations are configured.
464 */
Jim Millera4e28d12010-11-08 16:15:47 -0800465 protected void setExpirationAlarmCheckLocked(Context context) {
466 final long expiration = getPasswordExpirationLocked(null);
467 final long now = System.currentTimeMillis();
468 final long timeToExpire = expiration - now;
469 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800470 if (expiration == 0) {
471 // No expirations are currently configured: Cancel alarm.
472 alarmTime = 0;
473 } else if (timeToExpire <= 0) {
474 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800475 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800476 } else {
477 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
478 // the expiration time.
479 long alarmInterval = timeToExpire % MS_PER_DAY;
480 if (alarmInterval == 0) {
481 alarmInterval = MS_PER_DAY;
482 }
483 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800484 }
485
Andy Stadler1f35d482010-11-19 15:39:41 -0800486 long token = Binder.clearCallingIdentity();
487 try {
488 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
489 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
490 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
491 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
492 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800493 if (alarmTime != 0) {
494 am.set(AlarmManager.RTC, alarmTime, pi);
495 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800496 } finally {
497 Binder.restoreCallingIdentity(token);
498 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800499 }
500
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800501 private IPowerManager getIPowerManager() {
502 if (mIPowerManager == null) {
503 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
504 mIPowerManager = IPowerManager.Stub.asInterface(b);
505 }
506 return mIPowerManager;
507 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700508
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800509 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800510 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800511 if (admin != null
512 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
513 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
514 return admin;
515 }
516 return null;
517 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700518
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800519 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
520 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800521 final int callingUid = Binder.getCallingUid();
522 if (who != null) {
523 ActiveAdmin admin = mAdminMap.get(who);
524 if (admin == null) {
525 throw new SecurityException("No active admin " + who);
526 }
527 if (admin.getUid() != callingUid) {
528 throw new SecurityException("Admin " + who + " is not owned by uid "
529 + Binder.getCallingUid());
530 }
531 if (!admin.info.usesPolicy(reqPolicy)) {
532 throw new SecurityException("Admin " + admin.info.getComponent()
533 + " did not specify uses-policy for: "
534 + admin.info.getTagForPolicy(reqPolicy));
535 }
536 return admin;
537 } else {
538 final int N = mAdminList.size();
539 for (int i=0; i<N; i++) {
540 ActiveAdmin admin = mAdminList.get(i);
541 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
542 return admin;
543 }
544 }
545 throw new SecurityException("No active admin owned by uid "
546 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800547 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800548 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700549
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800550 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700551 sendAdminCommandLocked(admin, action, null);
552 }
553
554 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800555 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800556 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800557 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
558 intent.putExtra("expiration", admin.passwordExpirationDate);
559 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700560 if (result != null) {
561 mContext.sendOrderedBroadcast(intent, null, result, mHandler,
562 Activity.RESULT_OK, null, null);
563 } else {
564 mContext.sendBroadcast(intent);
565 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800566 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700567
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800568 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800569 final int N = mAdminList.size();
570 if (N > 0) {
571 for (int i=0; i<N; i++) {
572 ActiveAdmin admin = mAdminList.get(i);
573 if (admin.info.usesPolicy(reqPolicy)) {
574 sendAdminCommandLocked(admin, action);
575 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800576 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800577 }
578 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700579
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700580 void removeActiveAdminLocked(final ComponentName adminReceiver) {
581 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800582 if (admin != null) {
583 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700584 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
585 new BroadcastReceiver() {
586 @Override
587 public void onReceive(Context context, Intent intent) {
588 synchronized (this) {
589 boolean doProxyCleanup = admin.info.usesPolicy(
590 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
591 mAdminList.remove(admin);
592 mAdminMap.remove(adminReceiver);
593 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700594 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700595 if (doProxyCleanup) {
596 resetGlobalProxy();
597 }
598 saveSettingsLocked();
599 }
600 }
601 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800602 }
603 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700604
Dianne Hackbornd6847842010-01-12 18:14:19 -0800605 public DeviceAdminInfo findAdmin(ComponentName adminName) {
606 Intent resolveIntent = new Intent();
607 resolveIntent.setComponent(adminName);
608 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
609 resolveIntent, PackageManager.GET_META_DATA);
610 if (infos == null || infos.size() <= 0) {
611 throw new IllegalArgumentException("Unknown admin: " + adminName);
612 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700613
Dianne Hackbornd6847842010-01-12 18:14:19 -0800614 try {
615 return new DeviceAdminInfo(mContext, infos.get(0));
616 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700617 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800618 return null;
619 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700620 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800621 return null;
622 }
623 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700624
Dianne Hackbornd6847842010-01-12 18:14:19 -0800625 private static JournaledFile makeJournaledFile() {
626 final String base = "/data/system/device_policies.xml";
627 return new JournaledFile(new File(base), new File(base + ".tmp"));
628 }
629
630 private void saveSettingsLocked() {
631 JournaledFile journal = makeJournaledFile();
632 FileOutputStream stream = null;
633 try {
634 stream = new FileOutputStream(journal.chooseForWrite(), false);
635 XmlSerializer out = new FastXmlSerializer();
636 out.setOutput(stream, "utf-8");
637 out.startDocument(null, true);
638
639 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700640
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800641 final int N = mAdminList.size();
642 for (int i=0; i<N; i++) {
643 ActiveAdmin ap = mAdminList.get(i);
644 if (ap != null) {
645 out.startTag(null, "admin");
646 out.attribute(null, "name", ap.info.getComponent().flattenToString());
647 ap.writeToXml(out);
648 out.endTag(null, "admin");
649 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800650 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700651
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800652 if (mPasswordOwner >= 0) {
653 out.startTag(null, "password-owner");
654 out.attribute(null, "value", Integer.toString(mPasswordOwner));
655 out.endTag(null, "password-owner");
656 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700657
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800658 if (mFailedPasswordAttempts != 0) {
659 out.startTag(null, "failed-password-attempts");
660 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
661 out.endTag(null, "failed-password-attempts");
662 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700663
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700664 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
665 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
666 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700667 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700668 out.startTag(null, "active-password");
669 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
670 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700671 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
672 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
673 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
674 out.attribute(null, "numeric", Integer
675 .toString(mActivePasswordNumeric));
676 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700677 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700678 out.endTag(null, "active-password");
679 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700680
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700681 out.endTag(null, "policies");
682
Dianne Hackbornd6847842010-01-12 18:14:19 -0800683 out.endDocument();
684 stream.close();
685 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700686 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800687 } catch (IOException e) {
688 try {
689 if (stream != null) {
690 stream.close();
691 }
692 } catch (IOException ex) {
693 // Ignore
694 }
695 journal.rollback();
696 }
697 }
698
Jim Miller284b62e2010-06-08 14:27:42 -0700699 private void sendChangedNotification() {
700 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
701 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
702 mContext.sendBroadcast(intent);
703 }
704
Dianne Hackbornd6847842010-01-12 18:14:19 -0800705 private void loadSettingsLocked() {
706 JournaledFile journal = makeJournaledFile();
707 FileInputStream stream = null;
708 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800709 try {
710 stream = new FileInputStream(file);
711 XmlPullParser parser = Xml.newPullParser();
712 parser.setInput(stream, null);
713
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800714 int type;
715 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
716 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800717 }
718 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800719 if (!"policies".equals(tag)) {
720 throw new XmlPullParserException(
721 "Settings do not start with policies tag: found " + tag);
722 }
723 type = parser.next();
724 int outerDepth = parser.getDepth();
725 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
726 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
727 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
728 continue;
729 }
730 tag = parser.getName();
731 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800732 String name = parser.getAttributeValue(null, "name");
733 try {
734 DeviceAdminInfo dai = findAdmin(
735 ComponentName.unflattenFromString(name));
736 if (dai != null) {
737 ActiveAdmin ap = new ActiveAdmin(dai);
738 ap.readFromXml(parser);
739 mAdminMap.put(ap.info.getComponent(), ap);
740 mAdminList.add(ap);
741 }
742 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700743 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800744 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800745 } else if ("failed-password-attempts".equals(tag)) {
746 mFailedPasswordAttempts = Integer.parseInt(
747 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800748 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800749 } else if ("password-owner".equals(tag)) {
750 mPasswordOwner = Integer.parseInt(
751 parser.getAttributeValue(null, "value"));
752 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700753 } else if ("active-password".equals(tag)) {
754 mActivePasswordQuality = Integer.parseInt(
755 parser.getAttributeValue(null, "quality"));
756 mActivePasswordLength = Integer.parseInt(
757 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700758 mActivePasswordUpperCase = Integer.parseInt(
759 parser.getAttributeValue(null, "uppercase"));
760 mActivePasswordLowerCase = Integer.parseInt(
761 parser.getAttributeValue(null, "lowercase"));
762 mActivePasswordLetters = Integer.parseInt(
763 parser.getAttributeValue(null, "letters"));
764 mActivePasswordNumeric = Integer.parseInt(
765 parser.getAttributeValue(null, "numeric"));
766 mActivePasswordSymbols = Integer.parseInt(
767 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700768 mActivePasswordNonLetter = Integer.parseInt(
769 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700770 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800771 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700772 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800773 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800774 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800775 }
776 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700777 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800778 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700779 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800780 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700781 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700782 } catch (FileNotFoundException e) {
783 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800784 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700785 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800786 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700787 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800788 }
789 try {
790 if (stream != null) {
791 stream.close();
792 }
793 } catch (IOException e) {
794 // Ignore
795 }
796
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700797 // Validate that what we stored for the password quality matches
798 // sufficiently what is currently set. Note that this is only
799 // a sanity check in case the two get out of sync; this should
800 // never normally happen.
801 LockPatternUtils utils = new LockPatternUtils(mContext);
802 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
803 Slog.w(TAG, "Active password quality 0x"
804 + Integer.toHexString(mActivePasswordQuality)
805 + " does not match actual quality 0x"
806 + Integer.toHexString(utils.getActivePasswordQuality()));
807 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
808 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700809 mActivePasswordUpperCase = 0;
810 mActivePasswordLowerCase = 0;
811 mActivePasswordLetters = 0;
812 mActivePasswordNumeric = 0;
813 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700814 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700815 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700816
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800817 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700818 syncDeviceCapabilitiesLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700819
Dianne Hackborn254cb442010-01-27 19:23:59 -0800820 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800821 if (timeMs <= 0) {
822 timeMs = Integer.MAX_VALUE;
823 }
824 try {
825 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
826 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700827 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800828 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800829 }
830
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700831 static void validateQualityConstant(int quality) {
832 switch (quality) {
833 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millett2364a222011-12-21 17:02:32 -0500834 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700835 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
836 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
837 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
838 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700839 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700840 return;
841 }
842 throw new IllegalArgumentException("Invalid quality constant: 0x"
843 + Integer.toHexString(quality));
844 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700845
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800846 void validatePasswordOwnerLocked() {
847 if (mPasswordOwner >= 0) {
848 boolean haveOwner = false;
849 for (int i=mAdminList.size()-1; i>=0; i--) {
850 if (mAdminList.get(i).getUid() == mPasswordOwner) {
851 haveOwner = true;
852 break;
853 }
854 }
855 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700856 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800857 + " no longer active; disabling");
858 mPasswordOwner = -1;
859 }
860 }
861 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700862
Ben Komalo2447edd2011-05-09 16:05:33 -0700863 /**
864 * Pushes down policy information to the system for any policies related to general device
865 * capabilities that need to be enforced by lower level services (e.g. Camera services).
866 */
867 void syncDeviceCapabilitiesLocked() {
868 // Ensure the status of the camera is synced down to the system. Interested native services
869 // should monitor this value and act accordingly.
870 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
871 boolean cameraDisabled = getCameraDisabled(null);
872 if (cameraDisabled != systemState) {
873 long token = Binder.clearCallingIdentity();
874 try {
875 String value = cameraDisabled ? "1" : "0";
876 Slog.v(TAG, "Change in camera state ["
877 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
878 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
879 } finally {
880 Binder.restoreCallingIdentity(token);
881 }
882 }
883 }
884
Dianne Hackbornd6847842010-01-12 18:14:19 -0800885 public void systemReady() {
886 synchronized (this) {
887 loadSettingsLocked();
888 }
889 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700890
Jim Millera4e28d12010-11-08 16:15:47 -0800891 private void handlePasswordExpirationNotification() {
892 synchronized (this) {
893 final long now = System.currentTimeMillis();
894 final int N = mAdminList.size();
895 if (N <= 0) {
896 return;
897 }
898 for (int i=0; i < N; i++) {
899 ActiveAdmin admin = mAdminList.get(i);
900 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
901 && admin.passwordExpirationTimeout > 0L
902 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800903 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800904 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
905 }
906 }
907 setExpirationAlarmCheckLocked(mContext);
908 }
909 }
910
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800911 /**
912 * @param adminReceiver The admin to add
913 * @param refreshing true = update an active admin, no error
914 */
915 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800916 mContext.enforceCallingOrSelfPermission(
917 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700918
Dianne Hackbornd6847842010-01-12 18:14:19 -0800919 DeviceAdminInfo info = findAdmin(adminReceiver);
920 if (info == null) {
921 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
922 }
923 synchronized (this) {
924 long ident = Binder.clearCallingIdentity();
925 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800926 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800927 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800928 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800929 ActiveAdmin newAdmin = new ActiveAdmin(info);
930 mAdminMap.put(adminReceiver, newAdmin);
931 int replaceIndex = -1;
932 if (refreshing) {
933 final int N = mAdminList.size();
934 for (int i=0; i < N; i++) {
935 ActiveAdmin oldAdmin = mAdminList.get(i);
936 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
937 replaceIndex = i;
938 break;
939 }
940 }
941 }
942 if (replaceIndex == -1) {
943 mAdminList.add(newAdmin);
944 } else {
945 mAdminList.set(replaceIndex, newAdmin);
946 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800947 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800948 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800949 } finally {
950 Binder.restoreCallingIdentity(ident);
951 }
952 }
953 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700954
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800955 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800956 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800957 return getActiveAdminUncheckedLocked(adminReceiver) != null;
958 }
959 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700960
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800961 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
962 synchronized (this) {
963 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
964 if (administrator == null) {
965 throw new SecurityException("No active admin " + adminReceiver);
966 }
967 return administrator.info.usesPolicy(policyId);
968 }
969 }
970
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800971 public List<ComponentName> getActiveAdmins() {
972 synchronized (this) {
973 final int N = mAdminList.size();
974 if (N <= 0) {
975 return null;
976 }
977 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
978 for (int i=0; i<N; i++) {
979 res.add(mAdminList.get(i).info.getComponent());
980 }
981 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800982 }
983 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700984
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800985 public boolean packageHasActiveAdmins(String packageName) {
986 synchronized (this) {
987 final int N = mAdminList.size();
988 for (int i=0; i<N; i++) {
989 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
990 return true;
991 }
992 }
993 return false;
994 }
995 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700996
Dianne Hackbornd6847842010-01-12 18:14:19 -0800997 public void removeActiveAdmin(ComponentName adminReceiver) {
998 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800999 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
1000 if (admin == null) {
1001 return;
1002 }
1003 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001004 mContext.enforceCallingOrSelfPermission(
1005 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1006 }
1007 long ident = Binder.clearCallingIdentity();
1008 try {
1009 removeActiveAdminLocked(adminReceiver);
1010 } finally {
1011 Binder.restoreCallingIdentity(ident);
1012 }
1013 }
1014 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001015
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001016 public void setPasswordQuality(ComponentName who, int quality) {
1017 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001018
Dianne Hackbornd6847842010-01-12 18:14:19 -08001019 synchronized (this) {
1020 if (who == null) {
1021 throw new NullPointerException("ComponentName is null");
1022 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001023 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1024 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001025 if (ap.passwordQuality != quality) {
1026 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001027 saveSettingsLocked();
1028 }
1029 }
1030 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001031
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001032 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001033 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001034 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001035
Dianne Hackborn254cb442010-01-27 19:23:59 -08001036 if (who != null) {
1037 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001038 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001039 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001040
Dianne Hackborn254cb442010-01-27 19:23:59 -08001041 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001042 for (int i=0; i<N; i++) {
1043 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001044 if (mode < admin.passwordQuality) {
1045 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001046 }
1047 }
1048 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001049 }
1050 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001051
Dianne Hackborn254cb442010-01-27 19:23:59 -08001052 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001053 synchronized (this) {
1054 if (who == null) {
1055 throw new NullPointerException("ComponentName is null");
1056 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001057 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1058 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001059 if (ap.minimumPasswordLength != length) {
1060 ap.minimumPasswordLength = length;
1061 saveSettingsLocked();
1062 }
1063 }
1064 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001065
Dianne Hackborn254cb442010-01-27 19:23:59 -08001066 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001067 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001068 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001069
Dianne Hackborn254cb442010-01-27 19:23:59 -08001070 if (who != null) {
1071 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1072 return admin != null ? admin.minimumPasswordLength : length;
1073 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001074
Dianne Hackborn254cb442010-01-27 19:23:59 -08001075 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001076 for (int i=0; i<N; i++) {
1077 ActiveAdmin admin = mAdminList.get(i);
1078 if (length < admin.minimumPasswordLength) {
1079 length = admin.minimumPasswordLength;
1080 }
1081 }
1082 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001083 }
1084 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001085
1086 public void setPasswordHistoryLength(ComponentName who, int length) {
1087 synchronized (this) {
1088 if (who == null) {
1089 throw new NullPointerException("ComponentName is null");
1090 }
1091 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1092 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1093 if (ap.passwordHistoryLength != length) {
1094 ap.passwordHistoryLength = length;
1095 saveSettingsLocked();
1096 }
1097 }
1098 }
1099
1100 public int getPasswordHistoryLength(ComponentName who) {
1101 synchronized (this) {
1102 int length = 0;
1103
1104 if (who != null) {
1105 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1106 return admin != null ? admin.passwordHistoryLength : length;
1107 }
1108
1109 final int N = mAdminList.size();
1110 for (int i = 0; i < N; i++) {
1111 ActiveAdmin admin = mAdminList.get(i);
1112 if (length < admin.passwordHistoryLength) {
1113 length = admin.passwordHistoryLength;
1114 }
1115 }
1116 return length;
1117 }
1118 }
1119
Jim Millera4e28d12010-11-08 16:15:47 -08001120 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1121 synchronized (this) {
1122 if (who == null) {
1123 throw new NullPointerException("ComponentName is null");
1124 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001125 if (timeout < 0) {
1126 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001127 }
1128 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1129 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1130 // Calling this API automatically bumps the expiration date
1131 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1132 ap.passwordExpirationDate = expiration;
1133 ap.passwordExpirationTimeout = timeout;
1134 if (timeout > 0L) {
1135 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1136 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1137 .format(new Date(expiration)));
1138 }
1139 saveSettingsLocked();
1140 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1141 }
1142 }
1143
Andy Stadler043116a2010-11-29 17:43:32 -08001144 /**
1145 * Return a single admin's expiration cycle time, or the min of all cycle times.
1146 * Returns 0 if not configured.
1147 */
Jim Millera4e28d12010-11-08 16:15:47 -08001148 public long getPasswordExpirationTimeout(ComponentName who) {
1149 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001150 if (who != null) {
1151 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001152 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001153 }
1154
Andy Stadler043116a2010-11-29 17:43:32 -08001155 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001156 final int N = mAdminList.size();
1157 for (int i = 0; i < N; i++) {
1158 ActiveAdmin admin = mAdminList.get(i);
1159 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1160 && timeout > admin.passwordExpirationTimeout)) {
1161 timeout = admin.passwordExpirationTimeout;
1162 }
1163 }
1164 return timeout;
1165 }
1166 }
1167
Andy Stadler043116a2010-11-29 17:43:32 -08001168 /**
1169 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1170 * Returns 0 if not configured.
1171 */
Jim Millera4e28d12010-11-08 16:15:47 -08001172 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001173 if (who != null) {
1174 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001175 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001176 }
1177
Andy Stadler043116a2010-11-29 17:43:32 -08001178 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001179 final int N = mAdminList.size();
1180 for (int i = 0; i < N; i++) {
1181 ActiveAdmin admin = mAdminList.get(i);
1182 if (timeout == 0L || (admin.passwordExpirationDate != 0
1183 && timeout > admin.passwordExpirationDate)) {
1184 timeout = admin.passwordExpirationDate;
1185 }
1186 }
1187 return timeout;
1188 }
1189
1190 public long getPasswordExpiration(ComponentName who) {
1191 synchronized (this) {
1192 return getPasswordExpirationLocked(who);
1193 }
1194 }
1195
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001196 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1197 synchronized (this) {
1198 if (who == null) {
1199 throw new NullPointerException("ComponentName is null");
1200 }
1201 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1202 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1203 if (ap.minimumPasswordUpperCase != length) {
1204 ap.minimumPasswordUpperCase = length;
1205 saveSettingsLocked();
1206 }
1207 }
1208 }
1209
1210 public int getPasswordMinimumUpperCase(ComponentName who) {
1211 synchronized (this) {
1212 int length = 0;
1213
1214 if (who != null) {
1215 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1216 return admin != null ? admin.minimumPasswordUpperCase : length;
1217 }
1218
1219 final int N = mAdminList.size();
1220 for (int i=0; i<N; i++) {
1221 ActiveAdmin admin = mAdminList.get(i);
1222 if (length < admin.minimumPasswordUpperCase) {
1223 length = admin.minimumPasswordUpperCase;
1224 }
1225 }
1226 return length;
1227 }
1228 }
1229
1230 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1231 synchronized (this) {
1232 if (who == null) {
1233 throw new NullPointerException("ComponentName is null");
1234 }
1235 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1236 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1237 if (ap.minimumPasswordLowerCase != length) {
1238 ap.minimumPasswordLowerCase = length;
1239 saveSettingsLocked();
1240 }
1241 }
1242 }
1243
1244 public int getPasswordMinimumLowerCase(ComponentName who) {
1245 synchronized (this) {
1246 int length = 0;
1247
1248 if (who != null) {
1249 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1250 return admin != null ? admin.minimumPasswordLowerCase : length;
1251 }
1252
1253 final int N = mAdminList.size();
1254 for (int i=0; i<N; i++) {
1255 ActiveAdmin admin = mAdminList.get(i);
1256 if (length < admin.minimumPasswordLowerCase) {
1257 length = admin.minimumPasswordLowerCase;
1258 }
1259 }
1260 return length;
1261 }
1262 }
1263
1264 public void setPasswordMinimumLetters(ComponentName who, int length) {
1265 synchronized (this) {
1266 if (who == null) {
1267 throw new NullPointerException("ComponentName is null");
1268 }
1269 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1270 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1271 if (ap.minimumPasswordLetters != length) {
1272 ap.minimumPasswordLetters = length;
1273 saveSettingsLocked();
1274 }
1275 }
1276 }
1277
1278 public int getPasswordMinimumLetters(ComponentName who) {
1279 synchronized (this) {
1280 int length = 0;
1281
1282 if (who != null) {
1283 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1284 return admin != null ? admin.minimumPasswordLetters : length;
1285 }
1286
1287 final int N = mAdminList.size();
1288 for (int i=0; i<N; i++) {
1289 ActiveAdmin admin = mAdminList.get(i);
1290 if (length < admin.minimumPasswordLetters) {
1291 length = admin.minimumPasswordLetters;
1292 }
1293 }
1294 return length;
1295 }
1296 }
1297
1298 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1299 synchronized (this) {
1300 if (who == null) {
1301 throw new NullPointerException("ComponentName is null");
1302 }
1303 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1304 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1305 if (ap.minimumPasswordNumeric != length) {
1306 ap.minimumPasswordNumeric = length;
1307 saveSettingsLocked();
1308 }
1309 }
1310 }
1311
1312 public int getPasswordMinimumNumeric(ComponentName who) {
1313 synchronized (this) {
1314 int length = 0;
1315
1316 if (who != null) {
1317 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1318 return admin != null ? admin.minimumPasswordNumeric : length;
1319 }
1320
1321 final int N = mAdminList.size();
1322 for (int i = 0; i < N; i++) {
1323 ActiveAdmin admin = mAdminList.get(i);
1324 if (length < admin.minimumPasswordNumeric) {
1325 length = admin.minimumPasswordNumeric;
1326 }
1327 }
1328 return length;
1329 }
1330 }
1331
1332 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1333 synchronized (this) {
1334 if (who == null) {
1335 throw new NullPointerException("ComponentName is null");
1336 }
1337 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1338 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1339 if (ap.minimumPasswordSymbols != length) {
1340 ap.minimumPasswordSymbols = length;
1341 saveSettingsLocked();
1342 }
1343 }
1344 }
1345
1346 public int getPasswordMinimumSymbols(ComponentName who) {
1347 synchronized (this) {
1348 int length = 0;
1349
1350 if (who != null) {
1351 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1352 return admin != null ? admin.minimumPasswordSymbols : length;
1353 }
1354
1355 final int N = mAdminList.size();
1356 for (int i=0; i<N; i++) {
1357 ActiveAdmin admin = mAdminList.get(i);
1358 if (length < admin.minimumPasswordSymbols) {
1359 length = admin.minimumPasswordSymbols;
1360 }
1361 }
1362 return length;
1363 }
1364 }
1365
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001366 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1367 synchronized (this) {
1368 if (who == null) {
1369 throw new NullPointerException("ComponentName is null");
1370 }
1371 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1372 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1373 if (ap.minimumPasswordNonLetter != length) {
1374 ap.minimumPasswordNonLetter = length;
1375 saveSettingsLocked();
1376 }
1377 }
1378 }
1379
1380 public int getPasswordMinimumNonLetter(ComponentName who) {
1381 synchronized (this) {
1382 int length = 0;
1383
1384 if (who != null) {
1385 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1386 return admin != null ? admin.minimumPasswordNonLetter : length;
1387 }
1388
1389 final int N = mAdminList.size();
1390 for (int i=0; i<N; i++) {
1391 ActiveAdmin admin = mAdminList.get(i);
1392 if (length < admin.minimumPasswordNonLetter) {
1393 length = admin.minimumPasswordNonLetter;
1394 }
1395 }
1396 return length;
1397 }
1398 }
1399
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001400 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001401 synchronized (this) {
1402 // This API can only be called by an active device admin,
1403 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001404 getActiveAdminForCallerLocked(null,
1405 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001406 if (mActivePasswordQuality < getPasswordQuality(null)
1407 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1408 return false;
1409 }
1410 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1411 return true;
1412 }
1413 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1414 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1415 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1416 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001417 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1418 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001419 }
1420 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001421
Dianne Hackbornd6847842010-01-12 18:14:19 -08001422 public int getCurrentFailedPasswordAttempts() {
1423 synchronized (this) {
1424 // This API can only be called by an active device admin,
1425 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001426 getActiveAdminForCallerLocked(null,
1427 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001428 return mFailedPasswordAttempts;
1429 }
1430 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001431
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001432 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1433 synchronized (this) {
1434 // This API can only be called by an active device admin,
1435 // so try to retrieve it to check that the caller is one.
1436 getActiveAdminForCallerLocked(who,
1437 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1438 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1439 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1440 if (ap.maximumFailedPasswordsForWipe != num) {
1441 ap.maximumFailedPasswordsForWipe = num;
1442 saveSettingsLocked();
1443 }
1444 }
1445 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001446
Dianne Hackborn254cb442010-01-27 19:23:59 -08001447 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001448 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001449 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001450
Dianne Hackborn254cb442010-01-27 19:23:59 -08001451 if (who != null) {
1452 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1453 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1454 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001455
Dianne Hackborn254cb442010-01-27 19:23:59 -08001456 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001457 for (int i=0; i<N; i++) {
1458 ActiveAdmin admin = mAdminList.get(i);
1459 if (count == 0) {
1460 count = admin.maximumFailedPasswordsForWipe;
1461 } else if (admin.maximumFailedPasswordsForWipe != 0
1462 && count > admin.maximumFailedPasswordsForWipe) {
1463 count = admin.maximumFailedPasswordsForWipe;
1464 }
1465 }
1466 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001467 }
1468 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001469
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001470 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001471 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001472 synchronized (this) {
1473 // This API can only be called by an active device admin,
1474 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001475 getActiveAdminForCallerLocked(null,
1476 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001477 quality = getPasswordQuality(null);
1478 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001479 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001480 if (realQuality < quality
1481 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001482 Slog.w(TAG, "resetPassword: password quality 0x"
1483 + Integer.toHexString(quality)
1484 + " does not meet required quality 0x"
1485 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001486 return false;
1487 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001488 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001489 }
1490 int length = getPasswordMinimumLength(null);
1491 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001492 Slog.w(TAG, "resetPassword: password length " + password.length()
1493 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001494 return false;
1495 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001496 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1497 int letters = 0;
1498 int uppercase = 0;
1499 int lowercase = 0;
1500 int numbers = 0;
1501 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001502 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001503 for (int i = 0; i < password.length(); i++) {
1504 char c = password.charAt(i);
1505 if (c >= 'A' && c <= 'Z') {
1506 letters++;
1507 uppercase++;
1508 } else if (c >= 'a' && c <= 'z') {
1509 letters++;
1510 lowercase++;
1511 } else if (c >= '0' && c <= '9') {
1512 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001513 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001514 } else {
1515 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001516 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001517 }
1518 }
1519 int neededLetters = getPasswordMinimumLetters(null);
1520 if(letters < neededLetters) {
1521 Slog.w(TAG, "resetPassword: number of letters " + letters
1522 + " does not meet required number of letters " + neededLetters);
1523 return false;
1524 }
1525 int neededNumbers = getPasswordMinimumNumeric(null);
1526 if (numbers < neededNumbers) {
1527 Slog
1528 .w(TAG, "resetPassword: number of numerical digits " + numbers
1529 + " does not meet required number of numerical digits "
1530 + neededNumbers);
1531 return false;
1532 }
1533 int neededLowerCase = getPasswordMinimumLowerCase(null);
1534 if (lowercase < neededLowerCase) {
1535 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1536 + " does not meet required number of lowercase letters "
1537 + neededLowerCase);
1538 return false;
1539 }
1540 int neededUpperCase = getPasswordMinimumUpperCase(null);
1541 if (uppercase < neededUpperCase) {
1542 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1543 + " does not meet required number of uppercase letters "
1544 + neededUpperCase);
1545 return false;
1546 }
1547 int neededSymbols = getPasswordMinimumSymbols(null);
1548 if (symbols < neededSymbols) {
1549 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1550 + " does not meet required number of special symbols " + neededSymbols);
1551 return false;
1552 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001553 int neededNonLetter = getPasswordMinimumNonLetter(null);
1554 if (nonletter < neededNonLetter) {
1555 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1556 + " does not meet required number of non-letter characters "
1557 + neededNonLetter);
1558 return false;
1559 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001560 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001561 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001562
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001563 int callingUid = Binder.getCallingUid();
1564 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001565 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001566 return false;
1567 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001568
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001569 // Don't do this with the lock held, because it is going to call
1570 // back in to the service.
1571 long ident = Binder.clearCallingIdentity();
1572 try {
1573 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001574 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001575 synchronized (this) {
1576 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1577 != 0 ? callingUid : -1;
1578 if (mPasswordOwner != newOwner) {
1579 mPasswordOwner = newOwner;
1580 saveSettingsLocked();
1581 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001582 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001583 } finally {
1584 Binder.restoreCallingIdentity(ident);
1585 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001586
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001587 return true;
1588 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001589
Dianne Hackbornd6847842010-01-12 18:14:19 -08001590 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1591 synchronized (this) {
1592 if (who == null) {
1593 throw new NullPointerException("ComponentName is null");
1594 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001595 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001596 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001597 if (ap.maximumTimeToUnlock != timeMs) {
1598 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001599
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001600 long ident = Binder.clearCallingIdentity();
1601 try {
1602 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001603
Dianne Hackborn254cb442010-01-27 19:23:59 -08001604 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001605 if (timeMs <= 0) {
1606 timeMs = Integer.MAX_VALUE;
1607 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001608
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001609 try {
1610 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1611 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001612 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001613 }
1614 } finally {
1615 Binder.restoreCallingIdentity(ident);
1616 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001617 }
1618 }
1619 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001620
Dianne Hackborn254cb442010-01-27 19:23:59 -08001621 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001622 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001623 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001624
Dianne Hackborn254cb442010-01-27 19:23:59 -08001625 if (who != null) {
1626 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1627 return admin != null ? admin.maximumTimeToUnlock : time;
1628 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001629
Dianne Hackborn254cb442010-01-27 19:23:59 -08001630 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001631 for (int i=0; i<N; i++) {
1632 ActiveAdmin admin = mAdminList.get(i);
1633 if (time == 0) {
1634 time = admin.maximumTimeToUnlock;
1635 } else if (admin.maximumTimeToUnlock != 0
1636 && time > admin.maximumTimeToUnlock) {
1637 time = admin.maximumTimeToUnlock;
1638 }
1639 }
1640 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001641 }
1642 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001643
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001644 public void lockNow() {
1645 synchronized (this) {
1646 // This API can only be called by an active device admin,
1647 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001648 getActiveAdminForCallerLocked(null,
1649 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001650 long ident = Binder.clearCallingIdentity();
1651 try {
1652 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1653 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1654 } catch (RemoteException e) {
1655 } finally {
1656 Binder.restoreCallingIdentity(ident);
1657 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001658 }
1659 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001660
Ben Komaloed48c8b2011-10-17 17:30:21 -07001661 private boolean isExtStorageEncrypted() {
1662 String state = SystemProperties.get("vold.decrypt");
1663 return !"".equals(state);
1664 }
1665
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001666 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001667 // If the SD card is encrypted and non-removable, we have to force a wipe.
1668 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1669 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1670
1671 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1672 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001673 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1674 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1675 mWakeLock.acquire(10000);
1676 mContext.startService(intent);
1677 } else {
1678 try {
1679 RecoverySystem.rebootWipeUserData(mContext);
1680 } catch (IOException e) {
1681 Slog.w(TAG, "Failed requesting data wipe", e);
1682 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001683 }
1684 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001685
Dianne Hackbornd6847842010-01-12 18:14:19 -08001686 public void wipeData(int flags) {
1687 synchronized (this) {
1688 // This API can only be called by an active device admin,
1689 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001690 getActiveAdminForCallerLocked(null,
1691 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001692 long ident = Binder.clearCallingIdentity();
1693 try {
1694 wipeDataLocked(flags);
1695 } finally {
1696 Binder.restoreCallingIdentity(ident);
1697 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001698 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001699 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001700
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001701 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1702 mContext.enforceCallingOrSelfPermission(
1703 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001704
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001705 synchronized (this) {
1706 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1707 if (admin == null) {
1708 try {
1709 result.sendResult(null);
1710 } catch (RemoteException e) {
1711 }
1712 return;
1713 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001714 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001715 intent.setComponent(admin.info.getComponent());
1716 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1717 @Override
1718 public void onReceive(Context context, Intent intent) {
1719 try {
1720 result.sendResult(getResultExtras(false));
1721 } catch (RemoteException e) {
1722 }
1723 }
1724 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001725 }
1726 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001727
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001728 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001729 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001730 mContext.enforceCallingOrSelfPermission(
1731 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001732
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001733 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001734
Dianne Hackbornd6847842010-01-12 18:14:19 -08001735 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001736 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001737 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1738 || mActivePasswordUpperCase != uppercase
1739 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001740 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001741 long ident = Binder.clearCallingIdentity();
1742 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001743 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001744 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001745 mActivePasswordLetters = letters;
1746 mActivePasswordLowerCase = lowercase;
1747 mActivePasswordUpperCase = uppercase;
1748 mActivePasswordNumeric = numbers;
1749 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001750 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001751 mFailedPasswordAttempts = 0;
1752 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001753 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001754 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001755 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001756 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001757 } finally {
1758 Binder.restoreCallingIdentity(ident);
1759 }
1760 }
1761 }
1762 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001763
Andy Stadler043116a2010-11-29 17:43:32 -08001764 /**
1765 * Called any time the device password is updated. Resets all password expiration clocks.
1766 */
Jim Millera4e28d12010-11-08 16:15:47 -08001767 private void updatePasswordExpirationsLocked() {
1768 final int N = mAdminList.size();
1769 if (N > 0) {
1770 for (int i=0; i<N; i++) {
1771 ActiveAdmin admin = mAdminList.get(i);
1772 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001773 long timeout = admin.passwordExpirationTimeout;
1774 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1775 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001776 }
1777 }
1778 saveSettingsLocked();
1779 }
1780 }
1781
Dianne Hackbornd6847842010-01-12 18:14:19 -08001782 public void reportFailedPasswordAttempt() {
1783 mContext.enforceCallingOrSelfPermission(
1784 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001785
Dianne Hackbornd6847842010-01-12 18:14:19 -08001786 synchronized (this) {
1787 long ident = Binder.clearCallingIdentity();
1788 try {
1789 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001790 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001791 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001792 if (max > 0 && mFailedPasswordAttempts >= max) {
1793 wipeDataLocked(0);
1794 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001795 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001796 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001797 } finally {
1798 Binder.restoreCallingIdentity(ident);
1799 }
1800 }
1801 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001802
Dianne Hackbornd6847842010-01-12 18:14:19 -08001803 public void reportSuccessfulPasswordAttempt() {
1804 mContext.enforceCallingOrSelfPermission(
1805 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001806
Dianne Hackbornd6847842010-01-12 18:14:19 -08001807 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001808 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001809 long ident = Binder.clearCallingIdentity();
1810 try {
1811 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001812 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001813 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001814 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001815 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001816 } finally {
1817 Binder.restoreCallingIdentity(ident);
1818 }
1819 }
1820 }
1821 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001822
Oscar Montemayor69238c62010-08-03 10:51:06 -07001823 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1824 String exclusionList) {
1825 synchronized(this) {
1826 if (who == null) {
1827 throw new NullPointerException("ComponentName is null");
1828 }
1829
1830 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1831 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1832
1833 // Scan through active admins and find if anyone has already
1834 // set the global proxy.
Oscar Montemayor69238c62010-08-03 10:51:06 -07001835 Set<ComponentName> compSet = mAdminMap.keySet();
1836 for (ComponentName component : compSet) {
1837 ActiveAdmin ap = mAdminMap.get(component);
1838 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1839 // Another admin already sets the global proxy
1840 // Return it to the caller.
1841 return component;
1842 }
1843 }
1844 if (proxySpec == null) {
1845 admin.specifiesGlobalProxy = false;
1846 admin.globalProxySpec = null;
1847 admin.globalProxyExclusionList = null;
1848 } else {
1849
1850 admin.specifiesGlobalProxy = true;
1851 admin.globalProxySpec = proxySpec;
1852 admin.globalProxyExclusionList = exclusionList;
1853 }
1854
1855 // Reset the global proxy accordingly
1856 // Do this using system permissions, as apps cannot write to secure settings
1857 long origId = Binder.clearCallingIdentity();
1858 resetGlobalProxy();
1859 Binder.restoreCallingIdentity(origId);
1860 return null;
1861 }
1862 }
1863
1864 public ComponentName getGlobalProxyAdmin() {
1865 synchronized(this) {
1866 // Scan through active admins and find if anyone has already
1867 // set the global proxy.
1868 final int N = mAdminList.size();
1869 for (int i = 0; i < N; i++) {
1870 ActiveAdmin ap = mAdminList.get(i);
1871 if (ap.specifiesGlobalProxy) {
1872 // Device admin sets the global proxy
1873 // Return it to the caller.
1874 return ap.info.getComponent();
1875 }
1876 }
1877 }
1878 // No device admin sets the global proxy.
1879 return null;
1880 }
1881
1882 private void resetGlobalProxy() {
1883 final int N = mAdminList.size();
1884 for (int i = 0; i < N; i++) {
1885 ActiveAdmin ap = mAdminList.get(i);
1886 if (ap.specifiesGlobalProxy) {
1887 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1888 return;
1889 }
1890 }
1891 // No device admins defining global proxies - reset global proxy settings to none
1892 saveGlobalProxy(null, null);
1893 }
1894
1895 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1896 if (exclusionList == null) {
1897 exclusionList = "";
1898 }
1899 if (proxySpec == null) {
1900 proxySpec = "";
1901 }
1902 // Remove white spaces
1903 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001904 String data[] = proxySpec.split(":");
1905 int proxyPort = 8080;
1906 if (data.length > 1) {
1907 try {
1908 proxyPort = Integer.parseInt(data[1]);
1909 } catch (NumberFormatException e) {}
1910 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001911 exclusionList = exclusionList.trim();
1912 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001913 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1914 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1915 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1916 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001917 }
1918
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001919 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001920 * Set the storage encryption request for a single admin. Returns the new total request
1921 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001922 */
1923 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1924 synchronized (this) {
1925 // Check for permissions
1926 if (who == null) {
1927 throw new NullPointerException("ComponentName is null");
1928 }
1929 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1930 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1931
Andy Stadler22dbfda2011-01-17 12:47:31 -08001932 // Quick exit: If the filesystem does not support encryption, we can exit early.
1933 if (!isEncryptionSupported()) {
1934 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1935 }
1936
1937 // (1) Record the value for the admin so it's sticky
1938 if (ap.encryptionRequested != encrypt) {
1939 ap.encryptionRequested = encrypt;
1940 saveSettingsLocked();
1941 }
1942
1943 // (2) Compute "max" for all admins
1944 boolean newRequested = false;
1945 final int N = mAdminList.size();
1946 for (int i = 0; i < N; i++) {
1947 newRequested |= mAdminList.get(i).encryptionRequested;
1948 }
1949
1950 // Notify OS of new request
1951 setEncryptionRequested(newRequested);
1952
1953 // Return the new global request status
1954 return newRequested
1955 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1956 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001957 }
1958 }
1959
1960 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001961 * Get the current storage encryption request status for a given admin, or aggregate of all
1962 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001963 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08001964 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001965 synchronized (this) {
1966 // Check for permissions if a particular caller is specified
1967 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08001968 // When checking for a single caller, status is based on caller's request
Andy Stadlerc994d692011-06-01 15:30:54 -07001969 ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
1970 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001971 }
1972
Andy Stadler22dbfda2011-01-17 12:47:31 -08001973 // If no particular caller is specified, return the aggregate set of requests.
1974 // This is short circuited by returning true on the first hit.
1975 final int N = mAdminList.size();
1976 for (int i = 0; i < N; i++) {
1977 if (mAdminList.get(i).encryptionRequested) {
1978 return true;
1979 }
1980 }
1981 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001982 }
1983 }
1984
Andy Stadler22dbfda2011-01-17 12:47:31 -08001985 /**
1986 * Get the current encryption status of the device.
1987 */
1988 public int getStorageEncryptionStatus() {
1989 return getEncryptionStatus();
1990 }
1991
1992 /**
1993 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
1994 */
1995 private boolean isEncryptionSupported() {
1996 // Note, this can be implemented as
1997 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1998 // But is provided as a separate internal method if there's a faster way to do a
1999 // simple check for supported-or-not.
2000 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2001 }
2002
2003 /**
2004 * Hook to low-levels: Reporting the current status of encryption.
2005 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2006 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2007 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2008 */
2009 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002010 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2011 if ("encrypted".equalsIgnoreCase(status)) {
2012 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2013 } else if ("unencrypted".equalsIgnoreCase(status)) {
2014 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2015 } else {
2016 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2017 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002018 }
2019
2020 /**
2021 * Hook to low-levels: If needed, record the new admin setting for encryption.
2022 */
2023 private void setEncryptionRequested(boolean encrypt) {
2024 }
2025
Ben Komalo2447edd2011-05-09 16:05:33 -07002026 /**
2027 * The system property used to share the state of the camera. The native camera service
2028 * is expected to read this property and act accordingly.
2029 */
2030 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2031
2032 /**
2033 * Disables all device cameras according to the specified admin.
2034 */
2035 public void setCameraDisabled(ComponentName who, boolean disabled) {
2036 synchronized (this) {
2037 if (who == null) {
2038 throw new NullPointerException("ComponentName is null");
2039 }
2040 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2041 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2042 if (ap.disableCamera != disabled) {
2043 ap.disableCamera = disabled;
2044 saveSettingsLocked();
2045 }
2046 syncDeviceCapabilitiesLocked();
2047 }
2048 }
2049
2050 /**
2051 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2052 * active admins.
2053 */
2054 public boolean getCameraDisabled(ComponentName who) {
2055 synchronized (this) {
2056 if (who != null) {
2057 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
2058 return (admin != null) ? admin.disableCamera : false;
2059 }
2060
2061 // Determine whether or not the device camera is disabled for any active admins.
2062 final int N = mAdminList.size();
2063 for (int i = 0; i < N; i++) {
2064 ActiveAdmin admin = mAdminList.get(i);
2065 if (admin.disableCamera) {
2066 return true;
2067 }
2068 }
2069 return false;
2070 }
2071 }
2072
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002073 @Override
2074 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2075 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2076 != PackageManager.PERMISSION_GRANTED) {
2077
2078 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2079 + Binder.getCallingPid()
2080 + ", uid=" + Binder.getCallingUid());
2081 return;
2082 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002083
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002084 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002085
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002086 synchronized (this) {
2087 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002088
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002089 p.println(" Enabled Device Admins:");
2090 final int N = mAdminList.size();
2091 for (int i=0; i<N; i++) {
2092 ActiveAdmin ap = mAdminList.get(i);
2093 if (ap != null) {
2094 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2095 pw.println(":");
2096 ap.dump(" ", pw);
2097 }
2098 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002099
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002100 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002101 pw.print(" mActivePasswordQuality=0x");
2102 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002103 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002104 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
2105 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
2106 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
2107 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
2108 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07002109 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002110 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
2111 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
2112 }
2113 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002114}