blob: d8e3d5963964628904f1952c0efd83eaf5d764a0 [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;
Jim Miller93c518e2012-01-17 15:55:31 -080063import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080064import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080065
66import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080067import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080068import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070069import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080070import java.io.FileOutputStream;
71import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080072import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080073import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080074import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080075import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080076import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070078import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080079
80/**
81 * Implementation of the device policy APIs.
82 */
83public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Jim Miller6b857682011-02-16 16:27:41 -080084 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080085
Jim Miller6b857682011-02-16 16:27:41 -080086 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070087
Jim Millera4e28d12010-11-08 16:15:47 -080088 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
89
90 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
91 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
92
93 private static final long MS_PER_DAY = 86400 * 1000;
Jim Millera4e28d12010-11-08 16:15:47 -080094
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080095 final Context mContext;
96 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070097 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080098
Dianne Hackborndf83afa2010-01-20 13:37:26 -080099 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800100 IWindowManager mIWindowManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700101
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800102 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800103 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700104 int mActivePasswordUpperCase = 0;
105 int mActivePasswordLowerCase = 0;
106 int mActivePasswordLetters = 0;
107 int mActivePasswordNumeric = 0;
108 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700109 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800110 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700111
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800112 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800113 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700114
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800115 final HashMap<ComponentName, ActiveAdmin> mAdminMap
116 = new HashMap<ComponentName, ActiveAdmin>();
117 final ArrayList<ActiveAdmin> mAdminList
118 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700119
Jim Millera4e28d12010-11-08 16:15:47 -0800120 BroadcastReceiver mReceiver = new BroadcastReceiver() {
121 @Override
122 public void onReceive(Context context, Intent intent) {
123 String action = intent.getAction();
124 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
125 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
126 Slog.v(TAG, "Sending password expiration notifications for action " + action);
127 mHandler.post(new Runnable() {
128 public void run() {
129 handlePasswordExpirationNotification();
130 }
131 });
132 }
133 }
134 };
135
Dianne Hackbornd6847842010-01-12 18:14:19 -0800136 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800137 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700138
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800139 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700140
141 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
142 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
143
144 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
145 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
146
147 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
148 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
149
150 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
151 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
152
153 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700154 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700155
156 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
157 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
158
159 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
160 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
161
162 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
163 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
164
165 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
166 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
167
168 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
169 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
170
171 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
172 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
173
174 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
175 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
176
Andy Stadler22dbfda2011-01-17 12:47:31 -0800177 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700178 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700179
Oscar Montemayor69238c62010-08-03 10:51:06 -0700180 // TODO: review implementation decisions with frameworks team
181 boolean specifiesGlobalProxy = false;
182 String globalProxySpec = null;
183 String globalProxyExclusionList = null;
184
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800185 ActiveAdmin(DeviceAdminInfo _info) {
186 info = _info;
187 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700188
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800189 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700190
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800191 void writeToXml(XmlSerializer out)
192 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800193 out.startTag(null, "policies");
194 info.writePoliciesToXml(out);
195 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800196 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
197 out.startTag(null, "password-quality");
198 out.attribute(null, "value", Integer.toString(passwordQuality));
199 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700200 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800201 out.startTag(null, "min-password-length");
202 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700203 out.endTag(null, "min-password-length");
204 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700205 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700206 out.startTag(null, "password-history-length");
207 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
208 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800209 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700210 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700211 out.startTag(null, "min-password-uppercase");
212 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
213 out.endTag(null, "min-password-uppercase");
214 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700215 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700216 out.startTag(null, "min-password-lowercase");
217 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
218 out.endTag(null, "min-password-lowercase");
219 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700220 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700221 out.startTag(null, "min-password-letters");
222 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
223 out.endTag(null, "min-password-letters");
224 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700225 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700226 out.startTag(null, "min-password-numeric");
227 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
228 out.endTag(null, "min-password-numeric");
229 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700230 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700231 out.startTag(null, "min-password-symbols");
232 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
233 out.endTag(null, "min-password-symbols");
234 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700235 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700236 out.startTag(null, "min-password-nonletter");
237 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
238 out.endTag(null, "min-password-nonletter");
239 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800240 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700241 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800242 out.startTag(null, "max-time-to-unlock");
243 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
244 out.endTag(null, "max-time-to-unlock");
245 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700246 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800247 out.startTag(null, "max-failed-password-wipe");
248 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
249 out.endTag(null, "max-failed-password-wipe");
250 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700251 if (specifiesGlobalProxy) {
252 out.startTag(null, "specifies-global-proxy");
253 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
254 out.endTag(null, "specifies_global_proxy");
255 if (globalProxySpec != null) {
256 out.startTag(null, "global-proxy-spec");
257 out.attribute(null, "value", globalProxySpec);
258 out.endTag(null, "global-proxy-spec");
259 }
260 if (globalProxyExclusionList != null) {
261 out.startTag(null, "global-proxy-exclusion-list");
262 out.attribute(null, "value", globalProxyExclusionList);
263 out.endTag(null, "global-proxy-exclusion-list");
264 }
265 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700266 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800267 out.startTag(null, "password-expiration-timeout");
268 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
269 out.endTag(null, "password-expiration-timeout");
270 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700271 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800272 out.startTag(null, "password-expiration-date");
273 out.attribute(null, "value", Long.toString(passwordExpirationDate));
274 out.endTag(null, "password-expiration-date");
275 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800276 if (encryptionRequested) {
277 out.startTag(null, "encryption-requested");
278 out.attribute(null, "value", Boolean.toString(encryptionRequested));
279 out.endTag(null, "encryption-requested");
280 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700281 if (disableCamera) {
282 out.startTag(null, "disable-camera");
283 out.attribute(null, "value", Boolean.toString(disableCamera));
284 out.endTag(null, "disable-camera");
285 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800286 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700287
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800288 void readFromXml(XmlPullParser parser)
289 throws XmlPullParserException, IOException {
290 int outerDepth = parser.getDepth();
291 int type;
292 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
293 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
294 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
295 continue;
296 }
297 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800298 if ("policies".equals(tag)) {
299 info.readPoliciesFromXml(parser);
300 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800301 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800302 parser.getAttributeValue(null, "value"));
303 } else if ("min-password-length".equals(tag)) {
304 minimumPasswordLength = Integer.parseInt(
305 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700306 } else if ("password-history-length".equals(tag)) {
307 passwordHistoryLength = Integer.parseInt(
308 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700309 } else if ("min-password-uppercase".equals(tag)) {
310 minimumPasswordUpperCase = Integer.parseInt(
311 parser.getAttributeValue(null, "value"));
312 } else if ("min-password-lowercase".equals(tag)) {
313 minimumPasswordLowerCase = Integer.parseInt(
314 parser.getAttributeValue(null, "value"));
315 } else if ("min-password-letters".equals(tag)) {
316 minimumPasswordLetters = Integer.parseInt(
317 parser.getAttributeValue(null, "value"));
318 } else if ("min-password-numeric".equals(tag)) {
319 minimumPasswordNumeric = Integer.parseInt(
320 parser.getAttributeValue(null, "value"));
321 } else if ("min-password-symbols".equals(tag)) {
322 minimumPasswordSymbols = Integer.parseInt(
323 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700324 } else if ("min-password-nonletter".equals(tag)) {
325 minimumPasswordNonLetter = Integer.parseInt(
326 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800327 } else if ("max-time-to-unlock".equals(tag)) {
328 maximumTimeToUnlock = Long.parseLong(
329 parser.getAttributeValue(null, "value"));
330 } else if ("max-failed-password-wipe".equals(tag)) {
331 maximumFailedPasswordsForWipe = Integer.parseInt(
332 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700333 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800334 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700335 parser.getAttributeValue(null, "value"));
336 } else if ("global-proxy-spec".equals(tag)) {
337 globalProxySpec =
338 parser.getAttributeValue(null, "value");
339 } else if ("global-proxy-exclusion-list".equals(tag)) {
340 globalProxyExclusionList =
341 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800342 } else if ("password-expiration-timeout".equals(tag)) {
343 passwordExpirationTimeout = Long.parseLong(
344 parser.getAttributeValue(null, "value"));
345 } else if ("password-expiration-date".equals(tag)) {
346 passwordExpirationDate = Long.parseLong(
347 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800348 } else if ("encryption-requested".equals(tag)) {
349 encryptionRequested = Boolean.parseBoolean(
350 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700351 } else if ("disable-camera".equals(tag)) {
352 disableCamera = Boolean.parseBoolean(
353 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800354 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700355 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800356 }
357 XmlUtils.skipCurrentTag(parser);
358 }
359 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700360
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800361 void dump(String prefix, PrintWriter pw) {
362 pw.print(prefix); pw.print("uid="); pw.println(getUid());
363 pw.print(prefix); pw.println("policies:");
364 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
365 if (pols != null) {
366 for (int i=0; i<pols.size(); i++) {
367 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
368 }
369 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700370 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700371 pw.println(Integer.toHexString(passwordQuality));
372 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800373 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700374 pw.print(prefix); pw.print("passwordHistoryLength=");
375 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700376 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
377 pw.println(minimumPasswordUpperCase);
378 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
379 pw.println(minimumPasswordLowerCase);
380 pw.print(prefix); pw.print("minimumPasswordLetters=");
381 pw.println(minimumPasswordLetters);
382 pw.print(prefix); pw.print("minimumPasswordNumeric=");
383 pw.println(minimumPasswordNumeric);
384 pw.print(prefix); pw.print("minimumPasswordSymbols=");
385 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700386 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
387 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800388 pw.print(prefix); pw.print("maximumTimeToUnlock=");
389 pw.println(maximumTimeToUnlock);
390 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
391 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700392 pw.print(prefix); pw.print("specifiesGlobalProxy=");
393 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800394 pw.print(prefix); pw.print("passwordExpirationTimeout=");
395 pw.println(passwordExpirationTimeout);
396 pw.print(prefix); pw.print("passwordExpirationDate=");
397 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700398 if (globalProxySpec != null) {
399 pw.print(prefix); pw.print("globalProxySpec=");
400 pw.println(globalProxySpec);
401 }
402 if (globalProxyExclusionList != null) {
403 pw.print(prefix); pw.print("globalProxyEclusionList=");
404 pw.println(globalProxyExclusionList);
405 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800406 pw.print(prefix); pw.print("encryptionRequested=");
407 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700408 pw.print(prefix); pw.print("disableCamera=");
409 pw.println(disableCamera);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800410 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800411 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700412
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800413 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800414 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800415 public void onSomePackagesChanged() {
416 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800417 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800418 for (int i=mAdminList.size()-1; i>=0; i--) {
419 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700420 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800421 if (change == PACKAGE_PERMANENT_CHANGE
422 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700423 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800424 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800425 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800426 mAdminList.remove(i);
427 } else if (isPackageModified(aa.info.getPackageName())) {
428 try {
429 mContext.getPackageManager().getReceiverInfo(
430 aa.info.getComponent(), 0);
431 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700432 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800433 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800434 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800435 mAdminList.remove(i);
436 }
437 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800438 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800439 if (removed) {
440 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700441 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700442 saveSettingsLocked();
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800443 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800444 }
445 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800446 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700447
Dianne Hackbornd6847842010-01-12 18:14:19 -0800448 /**
449 * Instantiates the service.
450 */
451 public DevicePolicyManagerService(Context context) {
452 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800453 mMonitor = new MyPackageMonitor();
454 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700455 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
456 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800457 IntentFilter filter = new IntentFilter();
458 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
459 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
460 context.registerReceiver(mReceiver, filter);
461 }
462
Andy Stadler043116a2010-11-29 17:43:32 -0800463 /**
464 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
465 * reminders. Clears alarm if no expirations are configured.
466 */
Jim Millera4e28d12010-11-08 16:15:47 -0800467 protected void setExpirationAlarmCheckLocked(Context context) {
468 final long expiration = getPasswordExpirationLocked(null);
469 final long now = System.currentTimeMillis();
470 final long timeToExpire = expiration - now;
471 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800472 if (expiration == 0) {
473 // No expirations are currently configured: Cancel alarm.
474 alarmTime = 0;
475 } else if (timeToExpire <= 0) {
476 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800477 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800478 } else {
479 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
480 // the expiration time.
481 long alarmInterval = timeToExpire % MS_PER_DAY;
482 if (alarmInterval == 0) {
483 alarmInterval = MS_PER_DAY;
484 }
485 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800486 }
487
Andy Stadler1f35d482010-11-19 15:39:41 -0800488 long token = Binder.clearCallingIdentity();
489 try {
490 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
491 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
492 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
493 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
494 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800495 if (alarmTime != 0) {
496 am.set(AlarmManager.RTC, alarmTime, pi);
497 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800498 } finally {
499 Binder.restoreCallingIdentity(token);
500 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800501 }
502
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800503 private IPowerManager getIPowerManager() {
504 if (mIPowerManager == null) {
505 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
506 mIPowerManager = IPowerManager.Stub.asInterface(b);
507 }
508 return mIPowerManager;
509 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700510
Jim Miller93c518e2012-01-17 15:55:31 -0800511 private IWindowManager getWindowManager() {
512 if (mIWindowManager == null) {
513 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
514 mIWindowManager = IWindowManager.Stub.asInterface(b);
515 }
516 return mIWindowManager;
517 }
518
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800519 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800520 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800521 if (admin != null
522 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
523 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
524 return admin;
525 }
526 return null;
527 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700528
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800529 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
530 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800531 final int callingUid = Binder.getCallingUid();
532 if (who != null) {
533 ActiveAdmin admin = mAdminMap.get(who);
534 if (admin == null) {
535 throw new SecurityException("No active admin " + who);
536 }
537 if (admin.getUid() != callingUid) {
538 throw new SecurityException("Admin " + who + " is not owned by uid "
539 + Binder.getCallingUid());
540 }
541 if (!admin.info.usesPolicy(reqPolicy)) {
542 throw new SecurityException("Admin " + admin.info.getComponent()
543 + " did not specify uses-policy for: "
544 + admin.info.getTagForPolicy(reqPolicy));
545 }
546 return admin;
547 } else {
548 final int N = mAdminList.size();
549 for (int i=0; i<N; i++) {
550 ActiveAdmin admin = mAdminList.get(i);
551 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
552 return admin;
553 }
554 }
555 throw new SecurityException("No active admin owned by uid "
556 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800557 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800558 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700559
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800560 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700561 sendAdminCommandLocked(admin, action, null);
562 }
563
564 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800565 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800566 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800567 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
568 intent.putExtra("expiration", admin.passwordExpirationDate);
569 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700570 if (result != null) {
571 mContext.sendOrderedBroadcast(intent, null, result, mHandler,
572 Activity.RESULT_OK, null, null);
573 } else {
574 mContext.sendBroadcast(intent);
575 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800576 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700577
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800578 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800579 final int N = mAdminList.size();
580 if (N > 0) {
581 for (int i=0; i<N; i++) {
582 ActiveAdmin admin = mAdminList.get(i);
583 if (admin.info.usesPolicy(reqPolicy)) {
584 sendAdminCommandLocked(admin, action);
585 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800586 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800587 }
588 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700589
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700590 void removeActiveAdminLocked(final ComponentName adminReceiver) {
591 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800592 if (admin != null) {
593 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700594 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
595 new BroadcastReceiver() {
596 @Override
597 public void onReceive(Context context, Intent intent) {
598 synchronized (this) {
599 boolean doProxyCleanup = admin.info.usesPolicy(
600 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
601 mAdminList.remove(admin);
602 mAdminMap.remove(adminReceiver);
603 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700604 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700605 if (doProxyCleanup) {
606 resetGlobalProxy();
607 }
608 saveSettingsLocked();
609 }
610 }
611 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800612 }
613 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700614
Dianne Hackbornd6847842010-01-12 18:14:19 -0800615 public DeviceAdminInfo findAdmin(ComponentName adminName) {
616 Intent resolveIntent = new Intent();
617 resolveIntent.setComponent(adminName);
618 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
619 resolveIntent, PackageManager.GET_META_DATA);
620 if (infos == null || infos.size() <= 0) {
621 throw new IllegalArgumentException("Unknown admin: " + adminName);
622 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700623
Dianne Hackbornd6847842010-01-12 18:14:19 -0800624 try {
625 return new DeviceAdminInfo(mContext, infos.get(0));
626 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700627 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800628 return null;
629 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700630 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800631 return null;
632 }
633 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700634
Dianne Hackbornd6847842010-01-12 18:14:19 -0800635 private static JournaledFile makeJournaledFile() {
636 final String base = "/data/system/device_policies.xml";
637 return new JournaledFile(new File(base), new File(base + ".tmp"));
638 }
639
640 private void saveSettingsLocked() {
641 JournaledFile journal = makeJournaledFile();
642 FileOutputStream stream = null;
643 try {
644 stream = new FileOutputStream(journal.chooseForWrite(), false);
645 XmlSerializer out = new FastXmlSerializer();
646 out.setOutput(stream, "utf-8");
647 out.startDocument(null, true);
648
649 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700650
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800651 final int N = mAdminList.size();
652 for (int i=0; i<N; i++) {
653 ActiveAdmin ap = mAdminList.get(i);
654 if (ap != null) {
655 out.startTag(null, "admin");
656 out.attribute(null, "name", ap.info.getComponent().flattenToString());
657 ap.writeToXml(out);
658 out.endTag(null, "admin");
659 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800660 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700661
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800662 if (mPasswordOwner >= 0) {
663 out.startTag(null, "password-owner");
664 out.attribute(null, "value", Integer.toString(mPasswordOwner));
665 out.endTag(null, "password-owner");
666 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700667
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800668 if (mFailedPasswordAttempts != 0) {
669 out.startTag(null, "failed-password-attempts");
670 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
671 out.endTag(null, "failed-password-attempts");
672 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700673
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700674 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
675 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
676 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700677 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700678 out.startTag(null, "active-password");
679 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
680 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700681 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
682 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
683 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
684 out.attribute(null, "numeric", Integer
685 .toString(mActivePasswordNumeric));
686 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700687 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700688 out.endTag(null, "active-password");
689 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700690
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700691 out.endTag(null, "policies");
692
Dianne Hackbornd6847842010-01-12 18:14:19 -0800693 out.endDocument();
694 stream.close();
695 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700696 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800697 } catch (IOException e) {
698 try {
699 if (stream != null) {
700 stream.close();
701 }
702 } catch (IOException ex) {
703 // Ignore
704 }
705 journal.rollback();
706 }
707 }
708
Jim Miller284b62e2010-06-08 14:27:42 -0700709 private void sendChangedNotification() {
710 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
711 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
712 mContext.sendBroadcast(intent);
713 }
714
Dianne Hackbornd6847842010-01-12 18:14:19 -0800715 private void loadSettingsLocked() {
716 JournaledFile journal = makeJournaledFile();
717 FileInputStream stream = null;
718 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800719 try {
720 stream = new FileInputStream(file);
721 XmlPullParser parser = Xml.newPullParser();
722 parser.setInput(stream, null);
723
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800724 int type;
725 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
726 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800727 }
728 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800729 if (!"policies".equals(tag)) {
730 throw new XmlPullParserException(
731 "Settings do not start with policies tag: found " + tag);
732 }
733 type = parser.next();
734 int outerDepth = parser.getDepth();
735 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
736 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
737 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
738 continue;
739 }
740 tag = parser.getName();
741 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800742 String name = parser.getAttributeValue(null, "name");
743 try {
744 DeviceAdminInfo dai = findAdmin(
745 ComponentName.unflattenFromString(name));
746 if (dai != null) {
747 ActiveAdmin ap = new ActiveAdmin(dai);
748 ap.readFromXml(parser);
749 mAdminMap.put(ap.info.getComponent(), ap);
750 mAdminList.add(ap);
751 }
752 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700753 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800754 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800755 } else if ("failed-password-attempts".equals(tag)) {
756 mFailedPasswordAttempts = Integer.parseInt(
757 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800758 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800759 } else if ("password-owner".equals(tag)) {
760 mPasswordOwner = Integer.parseInt(
761 parser.getAttributeValue(null, "value"));
762 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700763 } else if ("active-password".equals(tag)) {
764 mActivePasswordQuality = Integer.parseInt(
765 parser.getAttributeValue(null, "quality"));
766 mActivePasswordLength = Integer.parseInt(
767 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700768 mActivePasswordUpperCase = Integer.parseInt(
769 parser.getAttributeValue(null, "uppercase"));
770 mActivePasswordLowerCase = Integer.parseInt(
771 parser.getAttributeValue(null, "lowercase"));
772 mActivePasswordLetters = Integer.parseInt(
773 parser.getAttributeValue(null, "letters"));
774 mActivePasswordNumeric = Integer.parseInt(
775 parser.getAttributeValue(null, "numeric"));
776 mActivePasswordSymbols = Integer.parseInt(
777 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700778 mActivePasswordNonLetter = Integer.parseInt(
779 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700780 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800781 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700782 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800783 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800784 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800785 }
786 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700787 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800788 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700789 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800790 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700791 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700792 } catch (FileNotFoundException e) {
793 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800794 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700795 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800796 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700797 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800798 }
799 try {
800 if (stream != null) {
801 stream.close();
802 }
803 } catch (IOException e) {
804 // Ignore
805 }
806
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700807 // Validate that what we stored for the password quality matches
808 // sufficiently what is currently set. Note that this is only
809 // a sanity check in case the two get out of sync; this should
810 // never normally happen.
811 LockPatternUtils utils = new LockPatternUtils(mContext);
812 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
813 Slog.w(TAG, "Active password quality 0x"
814 + Integer.toHexString(mActivePasswordQuality)
815 + " does not match actual quality 0x"
816 + Integer.toHexString(utils.getActivePasswordQuality()));
817 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
818 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700819 mActivePasswordUpperCase = 0;
820 mActivePasswordLowerCase = 0;
821 mActivePasswordLetters = 0;
822 mActivePasswordNumeric = 0;
823 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700824 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700825 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700826
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800827 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700828 syncDeviceCapabilitiesLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700829
Dianne Hackborn254cb442010-01-27 19:23:59 -0800830 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800831 if (timeMs <= 0) {
832 timeMs = Integer.MAX_VALUE;
833 }
834 try {
835 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
836 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700837 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800838 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800839 }
840
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700841 static void validateQualityConstant(int quality) {
842 switch (quality) {
843 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500844 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700845 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
846 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
847 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
848 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700849 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700850 return;
851 }
852 throw new IllegalArgumentException("Invalid quality constant: 0x"
853 + Integer.toHexString(quality));
854 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700855
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800856 void validatePasswordOwnerLocked() {
857 if (mPasswordOwner >= 0) {
858 boolean haveOwner = false;
859 for (int i=mAdminList.size()-1; i>=0; i--) {
860 if (mAdminList.get(i).getUid() == mPasswordOwner) {
861 haveOwner = true;
862 break;
863 }
864 }
865 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700866 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800867 + " no longer active; disabling");
868 mPasswordOwner = -1;
869 }
870 }
871 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700872
Ben Komalo2447edd2011-05-09 16:05:33 -0700873 /**
874 * Pushes down policy information to the system for any policies related to general device
875 * capabilities that need to be enforced by lower level services (e.g. Camera services).
876 */
877 void syncDeviceCapabilitiesLocked() {
878 // Ensure the status of the camera is synced down to the system. Interested native services
879 // should monitor this value and act accordingly.
880 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
881 boolean cameraDisabled = getCameraDisabled(null);
882 if (cameraDisabled != systemState) {
883 long token = Binder.clearCallingIdentity();
884 try {
885 String value = cameraDisabled ? "1" : "0";
886 Slog.v(TAG, "Change in camera state ["
887 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
888 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
889 } finally {
890 Binder.restoreCallingIdentity(token);
891 }
892 }
893 }
894
Dianne Hackbornd6847842010-01-12 18:14:19 -0800895 public void systemReady() {
896 synchronized (this) {
897 loadSettingsLocked();
898 }
899 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700900
Jim Millera4e28d12010-11-08 16:15:47 -0800901 private void handlePasswordExpirationNotification() {
902 synchronized (this) {
903 final long now = System.currentTimeMillis();
904 final int N = mAdminList.size();
905 if (N <= 0) {
906 return;
907 }
908 for (int i=0; i < N; i++) {
909 ActiveAdmin admin = mAdminList.get(i);
910 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
911 && admin.passwordExpirationTimeout > 0L
912 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800913 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800914 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
915 }
916 }
917 setExpirationAlarmCheckLocked(mContext);
918 }
919 }
920
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800921 /**
922 * @param adminReceiver The admin to add
923 * @param refreshing true = update an active admin, no error
924 */
925 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800926 mContext.enforceCallingOrSelfPermission(
927 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700928
Dianne Hackbornd6847842010-01-12 18:14:19 -0800929 DeviceAdminInfo info = findAdmin(adminReceiver);
930 if (info == null) {
931 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
932 }
933 synchronized (this) {
934 long ident = Binder.clearCallingIdentity();
935 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800936 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800937 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800938 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800939 ActiveAdmin newAdmin = new ActiveAdmin(info);
940 mAdminMap.put(adminReceiver, newAdmin);
941 int replaceIndex = -1;
942 if (refreshing) {
943 final int N = mAdminList.size();
944 for (int i=0; i < N; i++) {
945 ActiveAdmin oldAdmin = mAdminList.get(i);
946 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
947 replaceIndex = i;
948 break;
949 }
950 }
951 }
952 if (replaceIndex == -1) {
953 mAdminList.add(newAdmin);
954 } else {
955 mAdminList.set(replaceIndex, newAdmin);
956 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800957 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800958 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800959 } finally {
960 Binder.restoreCallingIdentity(ident);
961 }
962 }
963 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700964
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800965 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800966 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800967 return getActiveAdminUncheckedLocked(adminReceiver) != null;
968 }
969 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700970
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800971 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
972 synchronized (this) {
973 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
974 if (administrator == null) {
975 throw new SecurityException("No active admin " + adminReceiver);
976 }
977 return administrator.info.usesPolicy(policyId);
978 }
979 }
980
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800981 public List<ComponentName> getActiveAdmins() {
982 synchronized (this) {
983 final int N = mAdminList.size();
984 if (N <= 0) {
985 return null;
986 }
987 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
988 for (int i=0; i<N; i++) {
989 res.add(mAdminList.get(i).info.getComponent());
990 }
991 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800992 }
993 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700994
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800995 public boolean packageHasActiveAdmins(String packageName) {
996 synchronized (this) {
997 final int N = mAdminList.size();
998 for (int i=0; i<N; i++) {
999 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
1000 return true;
1001 }
1002 }
1003 return false;
1004 }
1005 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001006
Dianne Hackbornd6847842010-01-12 18:14:19 -08001007 public void removeActiveAdmin(ComponentName adminReceiver) {
1008 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001009 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
1010 if (admin == null) {
1011 return;
1012 }
1013 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001014 mContext.enforceCallingOrSelfPermission(
1015 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1016 }
1017 long ident = Binder.clearCallingIdentity();
1018 try {
1019 removeActiveAdminLocked(adminReceiver);
1020 } finally {
1021 Binder.restoreCallingIdentity(ident);
1022 }
1023 }
1024 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001025
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001026 public void setPasswordQuality(ComponentName who, int quality) {
1027 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001028
Dianne Hackbornd6847842010-01-12 18:14:19 -08001029 synchronized (this) {
1030 if (who == null) {
1031 throw new NullPointerException("ComponentName is null");
1032 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001033 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1034 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001035 if (ap.passwordQuality != quality) {
1036 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001037 saveSettingsLocked();
1038 }
1039 }
1040 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001041
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001042 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001043 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001044 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001045
Dianne Hackborn254cb442010-01-27 19:23:59 -08001046 if (who != null) {
1047 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001048 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001049 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001050
Dianne Hackborn254cb442010-01-27 19:23:59 -08001051 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001052 for (int i=0; i<N; i++) {
1053 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001054 if (mode < admin.passwordQuality) {
1055 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001056 }
1057 }
1058 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001059 }
1060 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001061
Dianne Hackborn254cb442010-01-27 19:23:59 -08001062 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001063 synchronized (this) {
1064 if (who == null) {
1065 throw new NullPointerException("ComponentName is null");
1066 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001067 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1068 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001069 if (ap.minimumPasswordLength != length) {
1070 ap.minimumPasswordLength = length;
1071 saveSettingsLocked();
1072 }
1073 }
1074 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001075
Dianne Hackborn254cb442010-01-27 19:23:59 -08001076 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001077 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001078 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001079
Dianne Hackborn254cb442010-01-27 19:23:59 -08001080 if (who != null) {
1081 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1082 return admin != null ? admin.minimumPasswordLength : length;
1083 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001084
Dianne Hackborn254cb442010-01-27 19:23:59 -08001085 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001086 for (int i=0; i<N; i++) {
1087 ActiveAdmin admin = mAdminList.get(i);
1088 if (length < admin.minimumPasswordLength) {
1089 length = admin.minimumPasswordLength;
1090 }
1091 }
1092 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001093 }
1094 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001095
1096 public void setPasswordHistoryLength(ComponentName who, int length) {
1097 synchronized (this) {
1098 if (who == null) {
1099 throw new NullPointerException("ComponentName is null");
1100 }
1101 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1102 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1103 if (ap.passwordHistoryLength != length) {
1104 ap.passwordHistoryLength = length;
1105 saveSettingsLocked();
1106 }
1107 }
1108 }
1109
1110 public int getPasswordHistoryLength(ComponentName who) {
1111 synchronized (this) {
1112 int length = 0;
1113
1114 if (who != null) {
1115 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1116 return admin != null ? admin.passwordHistoryLength : length;
1117 }
1118
1119 final int N = mAdminList.size();
1120 for (int i = 0; i < N; i++) {
1121 ActiveAdmin admin = mAdminList.get(i);
1122 if (length < admin.passwordHistoryLength) {
1123 length = admin.passwordHistoryLength;
1124 }
1125 }
1126 return length;
1127 }
1128 }
1129
Jim Millera4e28d12010-11-08 16:15:47 -08001130 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1131 synchronized (this) {
1132 if (who == null) {
1133 throw new NullPointerException("ComponentName is null");
1134 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001135 if (timeout < 0) {
1136 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001137 }
1138 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1139 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1140 // Calling this API automatically bumps the expiration date
1141 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1142 ap.passwordExpirationDate = expiration;
1143 ap.passwordExpirationTimeout = timeout;
1144 if (timeout > 0L) {
1145 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1146 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1147 .format(new Date(expiration)));
1148 }
1149 saveSettingsLocked();
1150 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1151 }
1152 }
1153
Andy Stadler043116a2010-11-29 17:43:32 -08001154 /**
1155 * Return a single admin's expiration cycle time, or the min of all cycle times.
1156 * Returns 0 if not configured.
1157 */
Jim Millera4e28d12010-11-08 16:15:47 -08001158 public long getPasswordExpirationTimeout(ComponentName who) {
1159 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001160 if (who != null) {
1161 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001162 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001163 }
1164
Andy Stadler043116a2010-11-29 17:43:32 -08001165 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001166 final int N = mAdminList.size();
1167 for (int i = 0; i < N; i++) {
1168 ActiveAdmin admin = mAdminList.get(i);
1169 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1170 && timeout > admin.passwordExpirationTimeout)) {
1171 timeout = admin.passwordExpirationTimeout;
1172 }
1173 }
1174 return timeout;
1175 }
1176 }
1177
Andy Stadler043116a2010-11-29 17:43:32 -08001178 /**
1179 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1180 * Returns 0 if not configured.
1181 */
Jim Millera4e28d12010-11-08 16:15:47 -08001182 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001183 if (who != null) {
1184 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001185 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001186 }
1187
Andy Stadler043116a2010-11-29 17:43:32 -08001188 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001189 final int N = mAdminList.size();
1190 for (int i = 0; i < N; i++) {
1191 ActiveAdmin admin = mAdminList.get(i);
1192 if (timeout == 0L || (admin.passwordExpirationDate != 0
1193 && timeout > admin.passwordExpirationDate)) {
1194 timeout = admin.passwordExpirationDate;
1195 }
1196 }
1197 return timeout;
1198 }
1199
1200 public long getPasswordExpiration(ComponentName who) {
1201 synchronized (this) {
1202 return getPasswordExpirationLocked(who);
1203 }
1204 }
1205
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001206 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1207 synchronized (this) {
1208 if (who == null) {
1209 throw new NullPointerException("ComponentName is null");
1210 }
1211 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1212 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1213 if (ap.minimumPasswordUpperCase != length) {
1214 ap.minimumPasswordUpperCase = length;
1215 saveSettingsLocked();
1216 }
1217 }
1218 }
1219
1220 public int getPasswordMinimumUpperCase(ComponentName who) {
1221 synchronized (this) {
1222 int length = 0;
1223
1224 if (who != null) {
1225 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1226 return admin != null ? admin.minimumPasswordUpperCase : length;
1227 }
1228
1229 final int N = mAdminList.size();
1230 for (int i=0; i<N; i++) {
1231 ActiveAdmin admin = mAdminList.get(i);
1232 if (length < admin.minimumPasswordUpperCase) {
1233 length = admin.minimumPasswordUpperCase;
1234 }
1235 }
1236 return length;
1237 }
1238 }
1239
1240 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1241 synchronized (this) {
1242 if (who == null) {
1243 throw new NullPointerException("ComponentName is null");
1244 }
1245 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1246 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1247 if (ap.minimumPasswordLowerCase != length) {
1248 ap.minimumPasswordLowerCase = length;
1249 saveSettingsLocked();
1250 }
1251 }
1252 }
1253
1254 public int getPasswordMinimumLowerCase(ComponentName who) {
1255 synchronized (this) {
1256 int length = 0;
1257
1258 if (who != null) {
1259 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1260 return admin != null ? admin.minimumPasswordLowerCase : length;
1261 }
1262
1263 final int N = mAdminList.size();
1264 for (int i=0; i<N; i++) {
1265 ActiveAdmin admin = mAdminList.get(i);
1266 if (length < admin.minimumPasswordLowerCase) {
1267 length = admin.minimumPasswordLowerCase;
1268 }
1269 }
1270 return length;
1271 }
1272 }
1273
1274 public void setPasswordMinimumLetters(ComponentName who, int length) {
1275 synchronized (this) {
1276 if (who == null) {
1277 throw new NullPointerException("ComponentName is null");
1278 }
1279 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1280 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1281 if (ap.minimumPasswordLetters != length) {
1282 ap.minimumPasswordLetters = length;
1283 saveSettingsLocked();
1284 }
1285 }
1286 }
1287
1288 public int getPasswordMinimumLetters(ComponentName who) {
1289 synchronized (this) {
1290 int length = 0;
1291
1292 if (who != null) {
1293 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1294 return admin != null ? admin.minimumPasswordLetters : length;
1295 }
1296
1297 final int N = mAdminList.size();
1298 for (int i=0; i<N; i++) {
1299 ActiveAdmin admin = mAdminList.get(i);
1300 if (length < admin.minimumPasswordLetters) {
1301 length = admin.minimumPasswordLetters;
1302 }
1303 }
1304 return length;
1305 }
1306 }
1307
1308 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1309 synchronized (this) {
1310 if (who == null) {
1311 throw new NullPointerException("ComponentName is null");
1312 }
1313 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1314 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1315 if (ap.minimumPasswordNumeric != length) {
1316 ap.minimumPasswordNumeric = length;
1317 saveSettingsLocked();
1318 }
1319 }
1320 }
1321
1322 public int getPasswordMinimumNumeric(ComponentName who) {
1323 synchronized (this) {
1324 int length = 0;
1325
1326 if (who != null) {
1327 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1328 return admin != null ? admin.minimumPasswordNumeric : length;
1329 }
1330
1331 final int N = mAdminList.size();
1332 for (int i = 0; i < N; i++) {
1333 ActiveAdmin admin = mAdminList.get(i);
1334 if (length < admin.minimumPasswordNumeric) {
1335 length = admin.minimumPasswordNumeric;
1336 }
1337 }
1338 return length;
1339 }
1340 }
1341
1342 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1343 synchronized (this) {
1344 if (who == null) {
1345 throw new NullPointerException("ComponentName is null");
1346 }
1347 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1348 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1349 if (ap.minimumPasswordSymbols != length) {
1350 ap.minimumPasswordSymbols = length;
1351 saveSettingsLocked();
1352 }
1353 }
1354 }
1355
1356 public int getPasswordMinimumSymbols(ComponentName who) {
1357 synchronized (this) {
1358 int length = 0;
1359
1360 if (who != null) {
1361 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1362 return admin != null ? admin.minimumPasswordSymbols : length;
1363 }
1364
1365 final int N = mAdminList.size();
1366 for (int i=0; i<N; i++) {
1367 ActiveAdmin admin = mAdminList.get(i);
1368 if (length < admin.minimumPasswordSymbols) {
1369 length = admin.minimumPasswordSymbols;
1370 }
1371 }
1372 return length;
1373 }
1374 }
1375
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001376 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1377 synchronized (this) {
1378 if (who == null) {
1379 throw new NullPointerException("ComponentName is null");
1380 }
1381 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1382 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1383 if (ap.minimumPasswordNonLetter != length) {
1384 ap.minimumPasswordNonLetter = length;
1385 saveSettingsLocked();
1386 }
1387 }
1388 }
1389
1390 public int getPasswordMinimumNonLetter(ComponentName who) {
1391 synchronized (this) {
1392 int length = 0;
1393
1394 if (who != null) {
1395 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1396 return admin != null ? admin.minimumPasswordNonLetter : length;
1397 }
1398
1399 final int N = mAdminList.size();
1400 for (int i=0; i<N; i++) {
1401 ActiveAdmin admin = mAdminList.get(i);
1402 if (length < admin.minimumPasswordNonLetter) {
1403 length = admin.minimumPasswordNonLetter;
1404 }
1405 }
1406 return length;
1407 }
1408 }
1409
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001410 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001411 synchronized (this) {
1412 // This API can only be called by an active device admin,
1413 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001414 getActiveAdminForCallerLocked(null,
1415 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001416 if (mActivePasswordQuality < getPasswordQuality(null)
1417 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1418 return false;
1419 }
1420 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1421 return true;
1422 }
1423 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1424 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1425 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1426 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001427 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1428 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001429 }
1430 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001431
Dianne Hackbornd6847842010-01-12 18:14:19 -08001432 public int getCurrentFailedPasswordAttempts() {
1433 synchronized (this) {
1434 // This API can only be called by an active device admin,
1435 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001436 getActiveAdminForCallerLocked(null,
1437 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001438 return mFailedPasswordAttempts;
1439 }
1440 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001441
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001442 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1443 synchronized (this) {
1444 // This API can only be called by an active device admin,
1445 // so try to retrieve it to check that the caller is one.
1446 getActiveAdminForCallerLocked(who,
1447 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1448 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1449 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1450 if (ap.maximumFailedPasswordsForWipe != num) {
1451 ap.maximumFailedPasswordsForWipe = num;
1452 saveSettingsLocked();
1453 }
1454 }
1455 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001456
Dianne Hackborn254cb442010-01-27 19:23:59 -08001457 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001458 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001459 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001460
Dianne Hackborn254cb442010-01-27 19:23:59 -08001461 if (who != null) {
1462 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1463 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1464 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001465
Dianne Hackborn254cb442010-01-27 19:23:59 -08001466 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001467 for (int i=0; i<N; i++) {
1468 ActiveAdmin admin = mAdminList.get(i);
1469 if (count == 0) {
1470 count = admin.maximumFailedPasswordsForWipe;
1471 } else if (admin.maximumFailedPasswordsForWipe != 0
1472 && count > admin.maximumFailedPasswordsForWipe) {
1473 count = admin.maximumFailedPasswordsForWipe;
1474 }
1475 }
1476 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001477 }
1478 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001479
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001480 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001481 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001482 synchronized (this) {
1483 // This API can only be called by an active device admin,
1484 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001485 getActiveAdminForCallerLocked(null,
1486 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001487 quality = getPasswordQuality(null);
1488 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001489 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001490 if (realQuality < quality
1491 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001492 Slog.w(TAG, "resetPassword: password quality 0x"
1493 + Integer.toHexString(quality)
1494 + " does not meet required quality 0x"
1495 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001496 return false;
1497 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001498 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001499 }
1500 int length = getPasswordMinimumLength(null);
1501 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001502 Slog.w(TAG, "resetPassword: password length " + password.length()
1503 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001504 return false;
1505 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001506 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1507 int letters = 0;
1508 int uppercase = 0;
1509 int lowercase = 0;
1510 int numbers = 0;
1511 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001512 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001513 for (int i = 0; i < password.length(); i++) {
1514 char c = password.charAt(i);
1515 if (c >= 'A' && c <= 'Z') {
1516 letters++;
1517 uppercase++;
1518 } else if (c >= 'a' && c <= 'z') {
1519 letters++;
1520 lowercase++;
1521 } else if (c >= '0' && c <= '9') {
1522 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001523 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001524 } else {
1525 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001526 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001527 }
1528 }
1529 int neededLetters = getPasswordMinimumLetters(null);
1530 if(letters < neededLetters) {
1531 Slog.w(TAG, "resetPassword: number of letters " + letters
1532 + " does not meet required number of letters " + neededLetters);
1533 return false;
1534 }
1535 int neededNumbers = getPasswordMinimumNumeric(null);
1536 if (numbers < neededNumbers) {
1537 Slog
1538 .w(TAG, "resetPassword: number of numerical digits " + numbers
1539 + " does not meet required number of numerical digits "
1540 + neededNumbers);
1541 return false;
1542 }
1543 int neededLowerCase = getPasswordMinimumLowerCase(null);
1544 if (lowercase < neededLowerCase) {
1545 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1546 + " does not meet required number of lowercase letters "
1547 + neededLowerCase);
1548 return false;
1549 }
1550 int neededUpperCase = getPasswordMinimumUpperCase(null);
1551 if (uppercase < neededUpperCase) {
1552 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1553 + " does not meet required number of uppercase letters "
1554 + neededUpperCase);
1555 return false;
1556 }
1557 int neededSymbols = getPasswordMinimumSymbols(null);
1558 if (symbols < neededSymbols) {
1559 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1560 + " does not meet required number of special symbols " + neededSymbols);
1561 return false;
1562 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001563 int neededNonLetter = getPasswordMinimumNonLetter(null);
1564 if (nonletter < neededNonLetter) {
1565 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1566 + " does not meet required number of non-letter characters "
1567 + neededNonLetter);
1568 return false;
1569 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001570 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001571 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001572
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001573 int callingUid = Binder.getCallingUid();
1574 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001575 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001576 return false;
1577 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001578
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001579 // Don't do this with the lock held, because it is going to call
1580 // back in to the service.
1581 long ident = Binder.clearCallingIdentity();
1582 try {
1583 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001584 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001585 synchronized (this) {
1586 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1587 != 0 ? callingUid : -1;
1588 if (mPasswordOwner != newOwner) {
1589 mPasswordOwner = newOwner;
1590 saveSettingsLocked();
1591 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001592 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001593 } finally {
1594 Binder.restoreCallingIdentity(ident);
1595 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001596
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001597 return true;
1598 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001599
Dianne Hackbornd6847842010-01-12 18:14:19 -08001600 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1601 synchronized (this) {
1602 if (who == null) {
1603 throw new NullPointerException("ComponentName is null");
1604 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001605 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001606 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001607 if (ap.maximumTimeToUnlock != timeMs) {
1608 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001609
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001610 long ident = Binder.clearCallingIdentity();
1611 try {
1612 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001613
Dianne Hackborn254cb442010-01-27 19:23:59 -08001614 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001615 if (timeMs <= 0) {
1616 timeMs = Integer.MAX_VALUE;
1617 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001618
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001619 try {
1620 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1621 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001622 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001623 }
1624 } finally {
1625 Binder.restoreCallingIdentity(ident);
1626 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001627 }
1628 }
1629 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001630
Dianne Hackborn254cb442010-01-27 19:23:59 -08001631 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001632 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001633 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001634
Dianne Hackborn254cb442010-01-27 19:23:59 -08001635 if (who != null) {
1636 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1637 return admin != null ? admin.maximumTimeToUnlock : time;
1638 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001639
Dianne Hackborn254cb442010-01-27 19:23:59 -08001640 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001641 for (int i=0; i<N; i++) {
1642 ActiveAdmin admin = mAdminList.get(i);
1643 if (time == 0) {
1644 time = admin.maximumTimeToUnlock;
1645 } else if (admin.maximumTimeToUnlock != 0
1646 && time > admin.maximumTimeToUnlock) {
1647 time = admin.maximumTimeToUnlock;
1648 }
1649 }
1650 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001651 }
1652 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001653
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001654 public void lockNow() {
1655 synchronized (this) {
1656 // This API can only be called by an active device admin,
1657 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001658 getActiveAdminForCallerLocked(null,
1659 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001660 long ident = Binder.clearCallingIdentity();
1661 try {
Jim Miller93c518e2012-01-17 15:55:31 -08001662 // Power off the display
Dianne Hackborn254cb442010-01-27 19:23:59 -08001663 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1664 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
Jim Miller93c518e2012-01-17 15:55:31 -08001665 // Ensure the device is locked
1666 getWindowManager().lockNow();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001667 } catch (RemoteException e) {
1668 } finally {
1669 Binder.restoreCallingIdentity(ident);
1670 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001671 }
1672 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001673
Ben Komaloed48c8b2011-10-17 17:30:21 -07001674 private boolean isExtStorageEncrypted() {
1675 String state = SystemProperties.get("vold.decrypt");
1676 return !"".equals(state);
1677 }
1678
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001679 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001680 // If the SD card is encrypted and non-removable, we have to force a wipe.
1681 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1682 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1683
1684 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1685 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001686 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1687 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1688 mWakeLock.acquire(10000);
1689 mContext.startService(intent);
1690 } else {
1691 try {
1692 RecoverySystem.rebootWipeUserData(mContext);
1693 } catch (IOException e) {
1694 Slog.w(TAG, "Failed requesting data wipe", e);
1695 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001696 }
1697 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001698
Dianne Hackbornd6847842010-01-12 18:14:19 -08001699 public void wipeData(int flags) {
1700 synchronized (this) {
1701 // This API can only be called by an active device admin,
1702 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001703 getActiveAdminForCallerLocked(null,
1704 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001705 long ident = Binder.clearCallingIdentity();
1706 try {
1707 wipeDataLocked(flags);
1708 } finally {
1709 Binder.restoreCallingIdentity(ident);
1710 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001711 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001712 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001713
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001714 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1715 mContext.enforceCallingOrSelfPermission(
1716 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001717
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001718 synchronized (this) {
1719 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1720 if (admin == null) {
1721 try {
1722 result.sendResult(null);
1723 } catch (RemoteException e) {
1724 }
1725 return;
1726 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001727 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001728 intent.setComponent(admin.info.getComponent());
1729 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1730 @Override
1731 public void onReceive(Context context, Intent intent) {
1732 try {
1733 result.sendResult(getResultExtras(false));
1734 } catch (RemoteException e) {
1735 }
1736 }
1737 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001738 }
1739 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001740
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001741 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001742 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001743 mContext.enforceCallingOrSelfPermission(
1744 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001745
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001746 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001747
Dianne Hackbornd6847842010-01-12 18:14:19 -08001748 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001749 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001750 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1751 || mActivePasswordUpperCase != uppercase
1752 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001753 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001754 long ident = Binder.clearCallingIdentity();
1755 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001756 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001757 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001758 mActivePasswordLetters = letters;
1759 mActivePasswordLowerCase = lowercase;
1760 mActivePasswordUpperCase = uppercase;
1761 mActivePasswordNumeric = numbers;
1762 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001763 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001764 mFailedPasswordAttempts = 0;
1765 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001766 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001767 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001768 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001769 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001770 } finally {
1771 Binder.restoreCallingIdentity(ident);
1772 }
1773 }
1774 }
1775 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001776
Andy Stadler043116a2010-11-29 17:43:32 -08001777 /**
1778 * Called any time the device password is updated. Resets all password expiration clocks.
1779 */
Jim Millera4e28d12010-11-08 16:15:47 -08001780 private void updatePasswordExpirationsLocked() {
1781 final int N = mAdminList.size();
1782 if (N > 0) {
1783 for (int i=0; i<N; i++) {
1784 ActiveAdmin admin = mAdminList.get(i);
1785 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001786 long timeout = admin.passwordExpirationTimeout;
1787 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1788 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001789 }
1790 }
1791 saveSettingsLocked();
1792 }
1793 }
1794
Dianne Hackbornd6847842010-01-12 18:14:19 -08001795 public void reportFailedPasswordAttempt() {
1796 mContext.enforceCallingOrSelfPermission(
1797 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001798
Dianne Hackbornd6847842010-01-12 18:14:19 -08001799 synchronized (this) {
1800 long ident = Binder.clearCallingIdentity();
1801 try {
1802 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001803 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001804 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001805 if (max > 0 && mFailedPasswordAttempts >= max) {
1806 wipeDataLocked(0);
1807 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001808 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001809 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001810 } finally {
1811 Binder.restoreCallingIdentity(ident);
1812 }
1813 }
1814 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001815
Dianne Hackbornd6847842010-01-12 18:14:19 -08001816 public void reportSuccessfulPasswordAttempt() {
1817 mContext.enforceCallingOrSelfPermission(
1818 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001819
Dianne Hackbornd6847842010-01-12 18:14:19 -08001820 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001821 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001822 long ident = Binder.clearCallingIdentity();
1823 try {
1824 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001825 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001826 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001827 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001828 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001829 } finally {
1830 Binder.restoreCallingIdentity(ident);
1831 }
1832 }
1833 }
1834 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001835
Oscar Montemayor69238c62010-08-03 10:51:06 -07001836 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1837 String exclusionList) {
1838 synchronized(this) {
1839 if (who == null) {
1840 throw new NullPointerException("ComponentName is null");
1841 }
1842
1843 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1844 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1845
1846 // Scan through active admins and find if anyone has already
1847 // set the global proxy.
Oscar Montemayor69238c62010-08-03 10:51:06 -07001848 Set<ComponentName> compSet = mAdminMap.keySet();
1849 for (ComponentName component : compSet) {
1850 ActiveAdmin ap = mAdminMap.get(component);
1851 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1852 // Another admin already sets the global proxy
1853 // Return it to the caller.
1854 return component;
1855 }
1856 }
1857 if (proxySpec == null) {
1858 admin.specifiesGlobalProxy = false;
1859 admin.globalProxySpec = null;
1860 admin.globalProxyExclusionList = null;
1861 } else {
1862
1863 admin.specifiesGlobalProxy = true;
1864 admin.globalProxySpec = proxySpec;
1865 admin.globalProxyExclusionList = exclusionList;
1866 }
1867
1868 // Reset the global proxy accordingly
1869 // Do this using system permissions, as apps cannot write to secure settings
1870 long origId = Binder.clearCallingIdentity();
1871 resetGlobalProxy();
1872 Binder.restoreCallingIdentity(origId);
1873 return null;
1874 }
1875 }
1876
1877 public ComponentName getGlobalProxyAdmin() {
1878 synchronized(this) {
1879 // Scan through active admins and find if anyone has already
1880 // set the global proxy.
1881 final int N = mAdminList.size();
1882 for (int i = 0; i < N; i++) {
1883 ActiveAdmin ap = mAdminList.get(i);
1884 if (ap.specifiesGlobalProxy) {
1885 // Device admin sets the global proxy
1886 // Return it to the caller.
1887 return ap.info.getComponent();
1888 }
1889 }
1890 }
1891 // No device admin sets the global proxy.
1892 return null;
1893 }
1894
1895 private void resetGlobalProxy() {
1896 final int N = mAdminList.size();
1897 for (int i = 0; i < N; i++) {
1898 ActiveAdmin ap = mAdminList.get(i);
1899 if (ap.specifiesGlobalProxy) {
1900 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1901 return;
1902 }
1903 }
1904 // No device admins defining global proxies - reset global proxy settings to none
1905 saveGlobalProxy(null, null);
1906 }
1907
1908 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1909 if (exclusionList == null) {
1910 exclusionList = "";
1911 }
1912 if (proxySpec == null) {
1913 proxySpec = "";
1914 }
1915 // Remove white spaces
1916 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001917 String data[] = proxySpec.split(":");
1918 int proxyPort = 8080;
1919 if (data.length > 1) {
1920 try {
1921 proxyPort = Integer.parseInt(data[1]);
1922 } catch (NumberFormatException e) {}
1923 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001924 exclusionList = exclusionList.trim();
1925 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001926 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1927 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1928 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1929 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001930 }
1931
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001932 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001933 * Set the storage encryption request for a single admin. Returns the new total request
1934 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001935 */
1936 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1937 synchronized (this) {
1938 // Check for permissions
1939 if (who == null) {
1940 throw new NullPointerException("ComponentName is null");
1941 }
1942 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1943 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1944
Andy Stadler22dbfda2011-01-17 12:47:31 -08001945 // Quick exit: If the filesystem does not support encryption, we can exit early.
1946 if (!isEncryptionSupported()) {
1947 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1948 }
1949
1950 // (1) Record the value for the admin so it's sticky
1951 if (ap.encryptionRequested != encrypt) {
1952 ap.encryptionRequested = encrypt;
1953 saveSettingsLocked();
1954 }
1955
1956 // (2) Compute "max" for all admins
1957 boolean newRequested = false;
1958 final int N = mAdminList.size();
1959 for (int i = 0; i < N; i++) {
1960 newRequested |= mAdminList.get(i).encryptionRequested;
1961 }
1962
1963 // Notify OS of new request
1964 setEncryptionRequested(newRequested);
1965
1966 // Return the new global request status
1967 return newRequested
1968 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1969 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001970 }
1971 }
1972
1973 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001974 * Get the current storage encryption request status for a given admin, or aggregate of all
1975 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001976 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08001977 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001978 synchronized (this) {
1979 // Check for permissions if a particular caller is specified
1980 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08001981 // When checking for a single caller, status is based on caller's request
Andy Stadlerc994d692011-06-01 15:30:54 -07001982 ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
1983 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001984 }
1985
Andy Stadler22dbfda2011-01-17 12:47:31 -08001986 // If no particular caller is specified, return the aggregate set of requests.
1987 // This is short circuited by returning true on the first hit.
1988 final int N = mAdminList.size();
1989 for (int i = 0; i < N; i++) {
1990 if (mAdminList.get(i).encryptionRequested) {
1991 return true;
1992 }
1993 }
1994 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001995 }
1996 }
1997
Andy Stadler22dbfda2011-01-17 12:47:31 -08001998 /**
1999 * Get the current encryption status of the device.
2000 */
2001 public int getStorageEncryptionStatus() {
2002 return getEncryptionStatus();
2003 }
2004
2005 /**
2006 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2007 */
2008 private boolean isEncryptionSupported() {
2009 // Note, this can be implemented as
2010 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2011 // But is provided as a separate internal method if there's a faster way to do a
2012 // simple check for supported-or-not.
2013 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2014 }
2015
2016 /**
2017 * Hook to low-levels: Reporting the current status of encryption.
2018 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2019 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2020 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2021 */
2022 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002023 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2024 if ("encrypted".equalsIgnoreCase(status)) {
2025 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2026 } else if ("unencrypted".equalsIgnoreCase(status)) {
2027 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2028 } else {
2029 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2030 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002031 }
2032
2033 /**
2034 * Hook to low-levels: If needed, record the new admin setting for encryption.
2035 */
2036 private void setEncryptionRequested(boolean encrypt) {
2037 }
2038
Ben Komalo2447edd2011-05-09 16:05:33 -07002039 /**
2040 * The system property used to share the state of the camera. The native camera service
2041 * is expected to read this property and act accordingly.
2042 */
2043 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2044
2045 /**
2046 * Disables all device cameras according to the specified admin.
2047 */
2048 public void setCameraDisabled(ComponentName who, boolean disabled) {
2049 synchronized (this) {
2050 if (who == null) {
2051 throw new NullPointerException("ComponentName is null");
2052 }
2053 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2054 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2055 if (ap.disableCamera != disabled) {
2056 ap.disableCamera = disabled;
2057 saveSettingsLocked();
2058 }
2059 syncDeviceCapabilitiesLocked();
2060 }
2061 }
2062
2063 /**
2064 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2065 * active admins.
2066 */
2067 public boolean getCameraDisabled(ComponentName who) {
2068 synchronized (this) {
2069 if (who != null) {
2070 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
2071 return (admin != null) ? admin.disableCamera : false;
2072 }
2073
2074 // Determine whether or not the device camera is disabled for any active admins.
2075 final int N = mAdminList.size();
2076 for (int i = 0; i < N; i++) {
2077 ActiveAdmin admin = mAdminList.get(i);
2078 if (admin.disableCamera) {
2079 return true;
2080 }
2081 }
2082 return false;
2083 }
2084 }
2085
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002086 @Override
2087 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2088 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2089 != PackageManager.PERMISSION_GRANTED) {
2090
2091 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2092 + Binder.getCallingPid()
2093 + ", uid=" + Binder.getCallingUid());
2094 return;
2095 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002096
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002097 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002098
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002099 synchronized (this) {
2100 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002101
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002102 p.println(" Enabled Device Admins:");
2103 final int N = mAdminList.size();
2104 for (int i=0; i<N; i++) {
2105 ActiveAdmin ap = mAdminList.get(i);
2106 if (ap != null) {
2107 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2108 pw.println(":");
2109 ap.dump(" ", pw);
2110 }
2111 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002112
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002113 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002114 pw.print(" mActivePasswordQuality=0x");
2115 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002116 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002117 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
2118 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
2119 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
2120 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
2121 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07002122 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002123 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
2124 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
2125 }
2126 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002127}