blob: 03f73b73db0f20ee041cb193944d2834a5f9719c [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:
834 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
835 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
836 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
837 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700838 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700839 return;
840 }
841 throw new IllegalArgumentException("Invalid quality constant: 0x"
842 + Integer.toHexString(quality));
843 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700844
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800845 void validatePasswordOwnerLocked() {
846 if (mPasswordOwner >= 0) {
847 boolean haveOwner = false;
848 for (int i=mAdminList.size()-1; i>=0; i--) {
849 if (mAdminList.get(i).getUid() == mPasswordOwner) {
850 haveOwner = true;
851 break;
852 }
853 }
854 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700855 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800856 + " no longer active; disabling");
857 mPasswordOwner = -1;
858 }
859 }
860 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700861
Ben Komalo2447edd2011-05-09 16:05:33 -0700862 /**
863 * Pushes down policy information to the system for any policies related to general device
864 * capabilities that need to be enforced by lower level services (e.g. Camera services).
865 */
866 void syncDeviceCapabilitiesLocked() {
867 // Ensure the status of the camera is synced down to the system. Interested native services
868 // should monitor this value and act accordingly.
869 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
870 boolean cameraDisabled = getCameraDisabled(null);
871 if (cameraDisabled != systemState) {
872 long token = Binder.clearCallingIdentity();
873 try {
874 String value = cameraDisabled ? "1" : "0";
875 Slog.v(TAG, "Change in camera state ["
876 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
877 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
878 } finally {
879 Binder.restoreCallingIdentity(token);
880 }
881 }
882 }
883
Dianne Hackbornd6847842010-01-12 18:14:19 -0800884 public void systemReady() {
885 synchronized (this) {
886 loadSettingsLocked();
887 }
888 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700889
Jim Millera4e28d12010-11-08 16:15:47 -0800890 private void handlePasswordExpirationNotification() {
891 synchronized (this) {
892 final long now = System.currentTimeMillis();
893 final int N = mAdminList.size();
894 if (N <= 0) {
895 return;
896 }
897 for (int i=0; i < N; i++) {
898 ActiveAdmin admin = mAdminList.get(i);
899 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
900 && admin.passwordExpirationTimeout > 0L
901 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800902 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800903 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
904 }
905 }
906 setExpirationAlarmCheckLocked(mContext);
907 }
908 }
909
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800910 /**
911 * @param adminReceiver The admin to add
912 * @param refreshing true = update an active admin, no error
913 */
914 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800915 mContext.enforceCallingOrSelfPermission(
916 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700917
Dianne Hackbornd6847842010-01-12 18:14:19 -0800918 DeviceAdminInfo info = findAdmin(adminReceiver);
919 if (info == null) {
920 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
921 }
922 synchronized (this) {
923 long ident = Binder.clearCallingIdentity();
924 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800925 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800926 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800927 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800928 ActiveAdmin newAdmin = new ActiveAdmin(info);
929 mAdminMap.put(adminReceiver, newAdmin);
930 int replaceIndex = -1;
931 if (refreshing) {
932 final int N = mAdminList.size();
933 for (int i=0; i < N; i++) {
934 ActiveAdmin oldAdmin = mAdminList.get(i);
935 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
936 replaceIndex = i;
937 break;
938 }
939 }
940 }
941 if (replaceIndex == -1) {
942 mAdminList.add(newAdmin);
943 } else {
944 mAdminList.set(replaceIndex, newAdmin);
945 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800946 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800947 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800948 } finally {
949 Binder.restoreCallingIdentity(ident);
950 }
951 }
952 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700953
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800954 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800955 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800956 return getActiveAdminUncheckedLocked(adminReceiver) != null;
957 }
958 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700959
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800960 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
961 synchronized (this) {
962 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
963 if (administrator == null) {
964 throw new SecurityException("No active admin " + adminReceiver);
965 }
966 return administrator.info.usesPolicy(policyId);
967 }
968 }
969
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800970 public List<ComponentName> getActiveAdmins() {
971 synchronized (this) {
972 final int N = mAdminList.size();
973 if (N <= 0) {
974 return null;
975 }
976 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
977 for (int i=0; i<N; i++) {
978 res.add(mAdminList.get(i).info.getComponent());
979 }
980 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800981 }
982 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700983
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800984 public boolean packageHasActiveAdmins(String packageName) {
985 synchronized (this) {
986 final int N = mAdminList.size();
987 for (int i=0; i<N; i++) {
988 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
989 return true;
990 }
991 }
992 return false;
993 }
994 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700995
Dianne Hackbornd6847842010-01-12 18:14:19 -0800996 public void removeActiveAdmin(ComponentName adminReceiver) {
997 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800998 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
999 if (admin == null) {
1000 return;
1001 }
1002 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001003 mContext.enforceCallingOrSelfPermission(
1004 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1005 }
1006 long ident = Binder.clearCallingIdentity();
1007 try {
1008 removeActiveAdminLocked(adminReceiver);
1009 } finally {
1010 Binder.restoreCallingIdentity(ident);
1011 }
1012 }
1013 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001014
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001015 public void setPasswordQuality(ComponentName who, int quality) {
1016 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001017
Dianne Hackbornd6847842010-01-12 18:14:19 -08001018 synchronized (this) {
1019 if (who == null) {
1020 throw new NullPointerException("ComponentName is null");
1021 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001022 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1023 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001024 if (ap.passwordQuality != quality) {
1025 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001026 saveSettingsLocked();
1027 }
1028 }
1029 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001030
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001031 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001032 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001033 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001034
Dianne Hackborn254cb442010-01-27 19:23:59 -08001035 if (who != null) {
1036 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001037 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001038 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001039
Dianne Hackborn254cb442010-01-27 19:23:59 -08001040 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001041 for (int i=0; i<N; i++) {
1042 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001043 if (mode < admin.passwordQuality) {
1044 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001045 }
1046 }
1047 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001048 }
1049 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001050
Dianne Hackborn254cb442010-01-27 19:23:59 -08001051 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001052 synchronized (this) {
1053 if (who == null) {
1054 throw new NullPointerException("ComponentName is null");
1055 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001056 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1057 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001058 if (ap.minimumPasswordLength != length) {
1059 ap.minimumPasswordLength = length;
1060 saveSettingsLocked();
1061 }
1062 }
1063 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001064
Dianne Hackborn254cb442010-01-27 19:23:59 -08001065 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001066 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001067 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001068
Dianne Hackborn254cb442010-01-27 19:23:59 -08001069 if (who != null) {
1070 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1071 return admin != null ? admin.minimumPasswordLength : length;
1072 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001073
Dianne Hackborn254cb442010-01-27 19:23:59 -08001074 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001075 for (int i=0; i<N; i++) {
1076 ActiveAdmin admin = mAdminList.get(i);
1077 if (length < admin.minimumPasswordLength) {
1078 length = admin.minimumPasswordLength;
1079 }
1080 }
1081 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001082 }
1083 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001084
1085 public void setPasswordHistoryLength(ComponentName who, int length) {
1086 synchronized (this) {
1087 if (who == null) {
1088 throw new NullPointerException("ComponentName is null");
1089 }
1090 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1091 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1092 if (ap.passwordHistoryLength != length) {
1093 ap.passwordHistoryLength = length;
1094 saveSettingsLocked();
1095 }
1096 }
1097 }
1098
1099 public int getPasswordHistoryLength(ComponentName who) {
1100 synchronized (this) {
1101 int length = 0;
1102
1103 if (who != null) {
1104 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1105 return admin != null ? admin.passwordHistoryLength : length;
1106 }
1107
1108 final int N = mAdminList.size();
1109 for (int i = 0; i < N; i++) {
1110 ActiveAdmin admin = mAdminList.get(i);
1111 if (length < admin.passwordHistoryLength) {
1112 length = admin.passwordHistoryLength;
1113 }
1114 }
1115 return length;
1116 }
1117 }
1118
Jim Millera4e28d12010-11-08 16:15:47 -08001119 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1120 synchronized (this) {
1121 if (who == null) {
1122 throw new NullPointerException("ComponentName is null");
1123 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001124 if (timeout < 0) {
1125 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001126 }
1127 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1128 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1129 // Calling this API automatically bumps the expiration date
1130 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1131 ap.passwordExpirationDate = expiration;
1132 ap.passwordExpirationTimeout = timeout;
1133 if (timeout > 0L) {
1134 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1135 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1136 .format(new Date(expiration)));
1137 }
1138 saveSettingsLocked();
1139 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1140 }
1141 }
1142
Andy Stadler043116a2010-11-29 17:43:32 -08001143 /**
1144 * Return a single admin's expiration cycle time, or the min of all cycle times.
1145 * Returns 0 if not configured.
1146 */
Jim Millera4e28d12010-11-08 16:15:47 -08001147 public long getPasswordExpirationTimeout(ComponentName who) {
1148 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001149 if (who != null) {
1150 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001151 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001152 }
1153
Andy Stadler043116a2010-11-29 17:43:32 -08001154 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001155 final int N = mAdminList.size();
1156 for (int i = 0; i < N; i++) {
1157 ActiveAdmin admin = mAdminList.get(i);
1158 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1159 && timeout > admin.passwordExpirationTimeout)) {
1160 timeout = admin.passwordExpirationTimeout;
1161 }
1162 }
1163 return timeout;
1164 }
1165 }
1166
Andy Stadler043116a2010-11-29 17:43:32 -08001167 /**
1168 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1169 * Returns 0 if not configured.
1170 */
Jim Millera4e28d12010-11-08 16:15:47 -08001171 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001172 if (who != null) {
1173 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001174 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001175 }
1176
Andy Stadler043116a2010-11-29 17:43:32 -08001177 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001178 final int N = mAdminList.size();
1179 for (int i = 0; i < N; i++) {
1180 ActiveAdmin admin = mAdminList.get(i);
1181 if (timeout == 0L || (admin.passwordExpirationDate != 0
1182 && timeout > admin.passwordExpirationDate)) {
1183 timeout = admin.passwordExpirationDate;
1184 }
1185 }
1186 return timeout;
1187 }
1188
1189 public long getPasswordExpiration(ComponentName who) {
1190 synchronized (this) {
1191 return getPasswordExpirationLocked(who);
1192 }
1193 }
1194
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001195 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1196 synchronized (this) {
1197 if (who == null) {
1198 throw new NullPointerException("ComponentName is null");
1199 }
1200 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1201 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1202 if (ap.minimumPasswordUpperCase != length) {
1203 ap.minimumPasswordUpperCase = length;
1204 saveSettingsLocked();
1205 }
1206 }
1207 }
1208
1209 public int getPasswordMinimumUpperCase(ComponentName who) {
1210 synchronized (this) {
1211 int length = 0;
1212
1213 if (who != null) {
1214 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1215 return admin != null ? admin.minimumPasswordUpperCase : length;
1216 }
1217
1218 final int N = mAdminList.size();
1219 for (int i=0; i<N; i++) {
1220 ActiveAdmin admin = mAdminList.get(i);
1221 if (length < admin.minimumPasswordUpperCase) {
1222 length = admin.minimumPasswordUpperCase;
1223 }
1224 }
1225 return length;
1226 }
1227 }
1228
1229 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1230 synchronized (this) {
1231 if (who == null) {
1232 throw new NullPointerException("ComponentName is null");
1233 }
1234 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1235 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1236 if (ap.minimumPasswordLowerCase != length) {
1237 ap.minimumPasswordLowerCase = length;
1238 saveSettingsLocked();
1239 }
1240 }
1241 }
1242
1243 public int getPasswordMinimumLowerCase(ComponentName who) {
1244 synchronized (this) {
1245 int length = 0;
1246
1247 if (who != null) {
1248 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1249 return admin != null ? admin.minimumPasswordLowerCase : length;
1250 }
1251
1252 final int N = mAdminList.size();
1253 for (int i=0; i<N; i++) {
1254 ActiveAdmin admin = mAdminList.get(i);
1255 if (length < admin.minimumPasswordLowerCase) {
1256 length = admin.minimumPasswordLowerCase;
1257 }
1258 }
1259 return length;
1260 }
1261 }
1262
1263 public void setPasswordMinimumLetters(ComponentName who, int length) {
1264 synchronized (this) {
1265 if (who == null) {
1266 throw new NullPointerException("ComponentName is null");
1267 }
1268 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1269 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1270 if (ap.minimumPasswordLetters != length) {
1271 ap.minimumPasswordLetters = length;
1272 saveSettingsLocked();
1273 }
1274 }
1275 }
1276
1277 public int getPasswordMinimumLetters(ComponentName who) {
1278 synchronized (this) {
1279 int length = 0;
1280
1281 if (who != null) {
1282 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1283 return admin != null ? admin.minimumPasswordLetters : length;
1284 }
1285
1286 final int N = mAdminList.size();
1287 for (int i=0; i<N; i++) {
1288 ActiveAdmin admin = mAdminList.get(i);
1289 if (length < admin.minimumPasswordLetters) {
1290 length = admin.minimumPasswordLetters;
1291 }
1292 }
1293 return length;
1294 }
1295 }
1296
1297 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1298 synchronized (this) {
1299 if (who == null) {
1300 throw new NullPointerException("ComponentName is null");
1301 }
1302 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1303 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1304 if (ap.minimumPasswordNumeric != length) {
1305 ap.minimumPasswordNumeric = length;
1306 saveSettingsLocked();
1307 }
1308 }
1309 }
1310
1311 public int getPasswordMinimumNumeric(ComponentName who) {
1312 synchronized (this) {
1313 int length = 0;
1314
1315 if (who != null) {
1316 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1317 return admin != null ? admin.minimumPasswordNumeric : length;
1318 }
1319
1320 final int N = mAdminList.size();
1321 for (int i = 0; i < N; i++) {
1322 ActiveAdmin admin = mAdminList.get(i);
1323 if (length < admin.minimumPasswordNumeric) {
1324 length = admin.minimumPasswordNumeric;
1325 }
1326 }
1327 return length;
1328 }
1329 }
1330
1331 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1332 synchronized (this) {
1333 if (who == null) {
1334 throw new NullPointerException("ComponentName is null");
1335 }
1336 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1337 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1338 if (ap.minimumPasswordSymbols != length) {
1339 ap.minimumPasswordSymbols = length;
1340 saveSettingsLocked();
1341 }
1342 }
1343 }
1344
1345 public int getPasswordMinimumSymbols(ComponentName who) {
1346 synchronized (this) {
1347 int length = 0;
1348
1349 if (who != null) {
1350 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1351 return admin != null ? admin.minimumPasswordSymbols : length;
1352 }
1353
1354 final int N = mAdminList.size();
1355 for (int i=0; i<N; i++) {
1356 ActiveAdmin admin = mAdminList.get(i);
1357 if (length < admin.minimumPasswordSymbols) {
1358 length = admin.minimumPasswordSymbols;
1359 }
1360 }
1361 return length;
1362 }
1363 }
1364
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001365 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1366 synchronized (this) {
1367 if (who == null) {
1368 throw new NullPointerException("ComponentName is null");
1369 }
1370 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1371 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1372 if (ap.minimumPasswordNonLetter != length) {
1373 ap.minimumPasswordNonLetter = length;
1374 saveSettingsLocked();
1375 }
1376 }
1377 }
1378
1379 public int getPasswordMinimumNonLetter(ComponentName who) {
1380 synchronized (this) {
1381 int length = 0;
1382
1383 if (who != null) {
1384 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1385 return admin != null ? admin.minimumPasswordNonLetter : length;
1386 }
1387
1388 final int N = mAdminList.size();
1389 for (int i=0; i<N; i++) {
1390 ActiveAdmin admin = mAdminList.get(i);
1391 if (length < admin.minimumPasswordNonLetter) {
1392 length = admin.minimumPasswordNonLetter;
1393 }
1394 }
1395 return length;
1396 }
1397 }
1398
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001399 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001400 synchronized (this) {
1401 // This API can only be called by an active device admin,
1402 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001403 getActiveAdminForCallerLocked(null,
1404 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001405 if (mActivePasswordQuality < getPasswordQuality(null)
1406 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1407 return false;
1408 }
1409 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1410 return true;
1411 }
1412 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1413 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1414 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1415 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001416 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1417 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001418 }
1419 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001420
Dianne Hackbornd6847842010-01-12 18:14:19 -08001421 public int getCurrentFailedPasswordAttempts() {
1422 synchronized (this) {
1423 // This API can only be called by an active device admin,
1424 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001425 getActiveAdminForCallerLocked(null,
1426 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001427 return mFailedPasswordAttempts;
1428 }
1429 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001430
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001431 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1432 synchronized (this) {
1433 // This API can only be called by an active device admin,
1434 // so try to retrieve it to check that the caller is one.
1435 getActiveAdminForCallerLocked(who,
1436 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1437 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1438 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1439 if (ap.maximumFailedPasswordsForWipe != num) {
1440 ap.maximumFailedPasswordsForWipe = num;
1441 saveSettingsLocked();
1442 }
1443 }
1444 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001445
Dianne Hackborn254cb442010-01-27 19:23:59 -08001446 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001447 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001448 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001449
Dianne Hackborn254cb442010-01-27 19:23:59 -08001450 if (who != null) {
1451 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1452 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1453 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001454
Dianne Hackborn254cb442010-01-27 19:23:59 -08001455 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001456 for (int i=0; i<N; i++) {
1457 ActiveAdmin admin = mAdminList.get(i);
1458 if (count == 0) {
1459 count = admin.maximumFailedPasswordsForWipe;
1460 } else if (admin.maximumFailedPasswordsForWipe != 0
1461 && count > admin.maximumFailedPasswordsForWipe) {
1462 count = admin.maximumFailedPasswordsForWipe;
1463 }
1464 }
1465 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001466 }
1467 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001468
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001469 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001470 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001471 synchronized (this) {
1472 // This API can only be called by an active device admin,
1473 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001474 getActiveAdminForCallerLocked(null,
1475 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001476 quality = getPasswordQuality(null);
1477 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001478 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001479 if (realQuality < quality
1480 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001481 Slog.w(TAG, "resetPassword: password quality 0x"
1482 + Integer.toHexString(quality)
1483 + " does not meet required quality 0x"
1484 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001485 return false;
1486 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001487 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001488 }
1489 int length = getPasswordMinimumLength(null);
1490 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001491 Slog.w(TAG, "resetPassword: password length " + password.length()
1492 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001493 return false;
1494 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001495 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1496 int letters = 0;
1497 int uppercase = 0;
1498 int lowercase = 0;
1499 int numbers = 0;
1500 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001501 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001502 for (int i = 0; i < password.length(); i++) {
1503 char c = password.charAt(i);
1504 if (c >= 'A' && c <= 'Z') {
1505 letters++;
1506 uppercase++;
1507 } else if (c >= 'a' && c <= 'z') {
1508 letters++;
1509 lowercase++;
1510 } else if (c >= '0' && c <= '9') {
1511 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001512 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001513 } else {
1514 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001515 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001516 }
1517 }
1518 int neededLetters = getPasswordMinimumLetters(null);
1519 if(letters < neededLetters) {
1520 Slog.w(TAG, "resetPassword: number of letters " + letters
1521 + " does not meet required number of letters " + neededLetters);
1522 return false;
1523 }
1524 int neededNumbers = getPasswordMinimumNumeric(null);
1525 if (numbers < neededNumbers) {
1526 Slog
1527 .w(TAG, "resetPassword: number of numerical digits " + numbers
1528 + " does not meet required number of numerical digits "
1529 + neededNumbers);
1530 return false;
1531 }
1532 int neededLowerCase = getPasswordMinimumLowerCase(null);
1533 if (lowercase < neededLowerCase) {
1534 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1535 + " does not meet required number of lowercase letters "
1536 + neededLowerCase);
1537 return false;
1538 }
1539 int neededUpperCase = getPasswordMinimumUpperCase(null);
1540 if (uppercase < neededUpperCase) {
1541 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1542 + " does not meet required number of uppercase letters "
1543 + neededUpperCase);
1544 return false;
1545 }
1546 int neededSymbols = getPasswordMinimumSymbols(null);
1547 if (symbols < neededSymbols) {
1548 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1549 + " does not meet required number of special symbols " + neededSymbols);
1550 return false;
1551 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001552 int neededNonLetter = getPasswordMinimumNonLetter(null);
1553 if (nonletter < neededNonLetter) {
1554 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1555 + " does not meet required number of non-letter characters "
1556 + neededNonLetter);
1557 return false;
1558 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001559 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001560 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001561
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001562 int callingUid = Binder.getCallingUid();
1563 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001564 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001565 return false;
1566 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001567
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001568 // Don't do this with the lock held, because it is going to call
1569 // back in to the service.
1570 long ident = Binder.clearCallingIdentity();
1571 try {
1572 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001573 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001574 synchronized (this) {
1575 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1576 != 0 ? callingUid : -1;
1577 if (mPasswordOwner != newOwner) {
1578 mPasswordOwner = newOwner;
1579 saveSettingsLocked();
1580 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001581 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001582 } finally {
1583 Binder.restoreCallingIdentity(ident);
1584 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001585
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001586 return true;
1587 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001588
Dianne Hackbornd6847842010-01-12 18:14:19 -08001589 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1590 synchronized (this) {
1591 if (who == null) {
1592 throw new NullPointerException("ComponentName is null");
1593 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001594 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001595 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001596 if (ap.maximumTimeToUnlock != timeMs) {
1597 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001598
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001599 long ident = Binder.clearCallingIdentity();
1600 try {
1601 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001602
Dianne Hackborn254cb442010-01-27 19:23:59 -08001603 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001604 if (timeMs <= 0) {
1605 timeMs = Integer.MAX_VALUE;
1606 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001607
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001608 try {
1609 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1610 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001611 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001612 }
1613 } finally {
1614 Binder.restoreCallingIdentity(ident);
1615 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001616 }
1617 }
1618 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001619
Dianne Hackborn254cb442010-01-27 19:23:59 -08001620 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001621 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001622 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001623
Dianne Hackborn254cb442010-01-27 19:23:59 -08001624 if (who != null) {
1625 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1626 return admin != null ? admin.maximumTimeToUnlock : time;
1627 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001628
Dianne Hackborn254cb442010-01-27 19:23:59 -08001629 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001630 for (int i=0; i<N; i++) {
1631 ActiveAdmin admin = mAdminList.get(i);
1632 if (time == 0) {
1633 time = admin.maximumTimeToUnlock;
1634 } else if (admin.maximumTimeToUnlock != 0
1635 && time > admin.maximumTimeToUnlock) {
1636 time = admin.maximumTimeToUnlock;
1637 }
1638 }
1639 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001640 }
1641 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001642
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001643 public void lockNow() {
1644 synchronized (this) {
1645 // This API can only be called by an active device admin,
1646 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001647 getActiveAdminForCallerLocked(null,
1648 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001649 long ident = Binder.clearCallingIdentity();
1650 try {
1651 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1652 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1653 } catch (RemoteException e) {
1654 } finally {
1655 Binder.restoreCallingIdentity(ident);
1656 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001657 }
1658 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001659
Ben Komaloed48c8b2011-10-17 17:30:21 -07001660 private boolean isExtStorageEncrypted() {
1661 String state = SystemProperties.get("vold.decrypt");
1662 return !"".equals(state);
1663 }
1664
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001665 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001666 // If the SD card is encrypted and non-removable, we have to force a wipe.
1667 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1668 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1669
1670 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1671 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001672 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001673 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001674 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}