blob: f966a3387e73749d7e94edbbb7f7a5beffe9faca [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 Hackborn2fe8fb22012-06-15 17:05:25 -0700115 long mLastMaximumTimeToLock = -1;
116
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800117 final HashMap<ComponentName, ActiveAdmin> mAdminMap
118 = new HashMap<ComponentName, ActiveAdmin>();
119 final ArrayList<ActiveAdmin> mAdminList
120 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700121
Jim Millera4e28d12010-11-08 16:15:47 -0800122 BroadcastReceiver mReceiver = new BroadcastReceiver() {
123 @Override
124 public void onReceive(Context context, Intent intent) {
125 String action = intent.getAction();
126 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
127 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
128 Slog.v(TAG, "Sending password expiration notifications for action " + action);
129 mHandler.post(new Runnable() {
130 public void run() {
131 handlePasswordExpirationNotification();
132 }
133 });
134 }
135 }
136 };
137
Dianne Hackbornd6847842010-01-12 18:14:19 -0800138 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800139 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700140
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800141 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700142
143 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
144 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
145
146 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
147 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
148
149 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
150 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
151
152 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
153 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
154
155 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700156 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700157
158 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
159 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
160
161 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
162 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
163
164 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
165 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
166
167 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
168 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
169
170 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
171 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
172
173 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
174 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
175
176 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
177 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
178
Andy Stadler22dbfda2011-01-17 12:47:31 -0800179 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700180 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700181
Oscar Montemayor69238c62010-08-03 10:51:06 -0700182 // TODO: review implementation decisions with frameworks team
183 boolean specifiesGlobalProxy = false;
184 String globalProxySpec = null;
185 String globalProxyExclusionList = null;
186
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800187 ActiveAdmin(DeviceAdminInfo _info) {
188 info = _info;
189 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700190
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800191 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700192
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800193 void writeToXml(XmlSerializer out)
194 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800195 out.startTag(null, "policies");
196 info.writePoliciesToXml(out);
197 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800198 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
199 out.startTag(null, "password-quality");
200 out.attribute(null, "value", Integer.toString(passwordQuality));
201 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700202 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800203 out.startTag(null, "min-password-length");
204 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700205 out.endTag(null, "min-password-length");
206 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700207 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700208 out.startTag(null, "password-history-length");
209 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
210 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800211 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700212 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700213 out.startTag(null, "min-password-uppercase");
214 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
215 out.endTag(null, "min-password-uppercase");
216 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700217 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700218 out.startTag(null, "min-password-lowercase");
219 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
220 out.endTag(null, "min-password-lowercase");
221 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700222 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700223 out.startTag(null, "min-password-letters");
224 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
225 out.endTag(null, "min-password-letters");
226 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700227 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700228 out.startTag(null, "min-password-numeric");
229 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
230 out.endTag(null, "min-password-numeric");
231 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700232 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700233 out.startTag(null, "min-password-symbols");
234 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
235 out.endTag(null, "min-password-symbols");
236 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700237 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700238 out.startTag(null, "min-password-nonletter");
239 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
240 out.endTag(null, "min-password-nonletter");
241 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800242 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700243 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800244 out.startTag(null, "max-time-to-unlock");
245 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
246 out.endTag(null, "max-time-to-unlock");
247 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700248 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800249 out.startTag(null, "max-failed-password-wipe");
250 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
251 out.endTag(null, "max-failed-password-wipe");
252 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700253 if (specifiesGlobalProxy) {
254 out.startTag(null, "specifies-global-proxy");
255 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
256 out.endTag(null, "specifies_global_proxy");
257 if (globalProxySpec != null) {
258 out.startTag(null, "global-proxy-spec");
259 out.attribute(null, "value", globalProxySpec);
260 out.endTag(null, "global-proxy-spec");
261 }
262 if (globalProxyExclusionList != null) {
263 out.startTag(null, "global-proxy-exclusion-list");
264 out.attribute(null, "value", globalProxyExclusionList);
265 out.endTag(null, "global-proxy-exclusion-list");
266 }
267 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700268 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800269 out.startTag(null, "password-expiration-timeout");
270 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
271 out.endTag(null, "password-expiration-timeout");
272 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700273 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800274 out.startTag(null, "password-expiration-date");
275 out.attribute(null, "value", Long.toString(passwordExpirationDate));
276 out.endTag(null, "password-expiration-date");
277 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800278 if (encryptionRequested) {
279 out.startTag(null, "encryption-requested");
280 out.attribute(null, "value", Boolean.toString(encryptionRequested));
281 out.endTag(null, "encryption-requested");
282 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700283 if (disableCamera) {
284 out.startTag(null, "disable-camera");
285 out.attribute(null, "value", Boolean.toString(disableCamera));
286 out.endTag(null, "disable-camera");
287 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800288 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700289
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800290 void readFromXml(XmlPullParser parser)
291 throws XmlPullParserException, IOException {
292 int outerDepth = parser.getDepth();
293 int type;
294 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
295 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
296 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
297 continue;
298 }
299 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800300 if ("policies".equals(tag)) {
301 info.readPoliciesFromXml(parser);
302 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800303 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800304 parser.getAttributeValue(null, "value"));
305 } else if ("min-password-length".equals(tag)) {
306 minimumPasswordLength = Integer.parseInt(
307 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700308 } else if ("password-history-length".equals(tag)) {
309 passwordHistoryLength = Integer.parseInt(
310 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700311 } else if ("min-password-uppercase".equals(tag)) {
312 minimumPasswordUpperCase = Integer.parseInt(
313 parser.getAttributeValue(null, "value"));
314 } else if ("min-password-lowercase".equals(tag)) {
315 minimumPasswordLowerCase = Integer.parseInt(
316 parser.getAttributeValue(null, "value"));
317 } else if ("min-password-letters".equals(tag)) {
318 minimumPasswordLetters = Integer.parseInt(
319 parser.getAttributeValue(null, "value"));
320 } else if ("min-password-numeric".equals(tag)) {
321 minimumPasswordNumeric = Integer.parseInt(
322 parser.getAttributeValue(null, "value"));
323 } else if ("min-password-symbols".equals(tag)) {
324 minimumPasswordSymbols = Integer.parseInt(
325 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700326 } else if ("min-password-nonletter".equals(tag)) {
327 minimumPasswordNonLetter = Integer.parseInt(
328 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800329 } else if ("max-time-to-unlock".equals(tag)) {
330 maximumTimeToUnlock = Long.parseLong(
331 parser.getAttributeValue(null, "value"));
332 } else if ("max-failed-password-wipe".equals(tag)) {
333 maximumFailedPasswordsForWipe = Integer.parseInt(
334 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700335 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800336 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700337 parser.getAttributeValue(null, "value"));
338 } else if ("global-proxy-spec".equals(tag)) {
339 globalProxySpec =
340 parser.getAttributeValue(null, "value");
341 } else if ("global-proxy-exclusion-list".equals(tag)) {
342 globalProxyExclusionList =
343 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800344 } else if ("password-expiration-timeout".equals(tag)) {
345 passwordExpirationTimeout = Long.parseLong(
346 parser.getAttributeValue(null, "value"));
347 } else if ("password-expiration-date".equals(tag)) {
348 passwordExpirationDate = Long.parseLong(
349 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800350 } else if ("encryption-requested".equals(tag)) {
351 encryptionRequested = Boolean.parseBoolean(
352 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700353 } else if ("disable-camera".equals(tag)) {
354 disableCamera = Boolean.parseBoolean(
355 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800356 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700357 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800358 }
359 XmlUtils.skipCurrentTag(parser);
360 }
361 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700362
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800363 void dump(String prefix, PrintWriter pw) {
364 pw.print(prefix); pw.print("uid="); pw.println(getUid());
365 pw.print(prefix); pw.println("policies:");
366 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
367 if (pols != null) {
368 for (int i=0; i<pols.size(); i++) {
369 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
370 }
371 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700372 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700373 pw.println(Integer.toHexString(passwordQuality));
374 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800375 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700376 pw.print(prefix); pw.print("passwordHistoryLength=");
377 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700378 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
379 pw.println(minimumPasswordUpperCase);
380 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
381 pw.println(minimumPasswordLowerCase);
382 pw.print(prefix); pw.print("minimumPasswordLetters=");
383 pw.println(minimumPasswordLetters);
384 pw.print(prefix); pw.print("minimumPasswordNumeric=");
385 pw.println(minimumPasswordNumeric);
386 pw.print(prefix); pw.print("minimumPasswordSymbols=");
387 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700388 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
389 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800390 pw.print(prefix); pw.print("maximumTimeToUnlock=");
391 pw.println(maximumTimeToUnlock);
392 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
393 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700394 pw.print(prefix); pw.print("specifiesGlobalProxy=");
395 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800396 pw.print(prefix); pw.print("passwordExpirationTimeout=");
397 pw.println(passwordExpirationTimeout);
398 pw.print(prefix); pw.print("passwordExpirationDate=");
399 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700400 if (globalProxySpec != null) {
401 pw.print(prefix); pw.print("globalProxySpec=");
402 pw.println(globalProxySpec);
403 }
404 if (globalProxyExclusionList != null) {
405 pw.print(prefix); pw.print("globalProxyEclusionList=");
406 pw.println(globalProxyExclusionList);
407 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800408 pw.print(prefix); pw.print("encryptionRequested=");
409 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700410 pw.print(prefix); pw.print("disableCamera=");
411 pw.println(disableCamera);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800412 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800413 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700414
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800415 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800416 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800417 public void onSomePackagesChanged() {
418 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800419 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800420 for (int i=mAdminList.size()-1; i>=0; i--) {
421 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700422 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800423 if (change == PACKAGE_PERMANENT_CHANGE
424 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700425 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800426 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800427 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800428 mAdminList.remove(i);
429 } else if (isPackageModified(aa.info.getPackageName())) {
430 try {
431 mContext.getPackageManager().getReceiverInfo(
432 aa.info.getComponent(), 0);
433 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700434 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800435 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800436 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800437 mAdminList.remove(i);
438 }
439 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800440 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800441 if (removed) {
442 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700443 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700444 saveSettingsLocked();
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800445 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800446 }
447 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800448 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700449
Dianne Hackbornd6847842010-01-12 18:14:19 -0800450 /**
451 * Instantiates the service.
452 */
453 public DevicePolicyManagerService(Context context) {
454 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800455 mMonitor = new MyPackageMonitor();
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700456 mMonitor.register(context, null, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700457 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
458 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800459 IntentFilter filter = new IntentFilter();
460 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
461 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
462 context.registerReceiver(mReceiver, filter);
463 }
464
Andy Stadler043116a2010-11-29 17:43:32 -0800465 /**
466 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
467 * reminders. Clears alarm if no expirations are configured.
468 */
Jim Millera4e28d12010-11-08 16:15:47 -0800469 protected void setExpirationAlarmCheckLocked(Context context) {
470 final long expiration = getPasswordExpirationLocked(null);
471 final long now = System.currentTimeMillis();
472 final long timeToExpire = expiration - now;
473 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800474 if (expiration == 0) {
475 // No expirations are currently configured: Cancel alarm.
476 alarmTime = 0;
477 } else if (timeToExpire <= 0) {
478 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800479 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800480 } else {
481 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
482 // the expiration time.
483 long alarmInterval = timeToExpire % MS_PER_DAY;
484 if (alarmInterval == 0) {
485 alarmInterval = MS_PER_DAY;
486 }
487 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800488 }
489
Andy Stadler1f35d482010-11-19 15:39:41 -0800490 long token = Binder.clearCallingIdentity();
491 try {
492 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
493 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
494 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
495 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
496 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800497 if (alarmTime != 0) {
498 am.set(AlarmManager.RTC, alarmTime, pi);
499 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800500 } finally {
501 Binder.restoreCallingIdentity(token);
502 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800503 }
504
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800505 private IPowerManager getIPowerManager() {
506 if (mIPowerManager == null) {
507 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
508 mIPowerManager = IPowerManager.Stub.asInterface(b);
509 }
510 return mIPowerManager;
511 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700512
Jim Miller93c518e2012-01-17 15:55:31 -0800513 private IWindowManager getWindowManager() {
514 if (mIWindowManager == null) {
515 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
516 mIWindowManager = IWindowManager.Stub.asInterface(b);
517 }
518 return mIWindowManager;
519 }
520
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800521 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800522 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800523 if (admin != null
524 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
525 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
526 return admin;
527 }
528 return null;
529 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700530
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800531 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
532 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800533 final int callingUid = Binder.getCallingUid();
534 if (who != null) {
535 ActiveAdmin admin = mAdminMap.get(who);
536 if (admin == null) {
537 throw new SecurityException("No active admin " + who);
538 }
539 if (admin.getUid() != callingUid) {
540 throw new SecurityException("Admin " + who + " is not owned by uid "
541 + Binder.getCallingUid());
542 }
543 if (!admin.info.usesPolicy(reqPolicy)) {
544 throw new SecurityException("Admin " + admin.info.getComponent()
545 + " did not specify uses-policy for: "
546 + admin.info.getTagForPolicy(reqPolicy));
547 }
548 return admin;
549 } else {
550 final int N = mAdminList.size();
551 for (int i=0; i<N; i++) {
552 ActiveAdmin admin = mAdminList.get(i);
553 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
554 return admin;
555 }
556 }
557 throw new SecurityException("No active admin owned by uid "
558 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800559 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800560 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700561
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800562 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700563 sendAdminCommandLocked(admin, action, null);
564 }
565
566 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800567 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800568 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800569 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
570 intent.putExtra("expiration", admin.passwordExpirationDate);
571 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700572 if (result != null) {
573 mContext.sendOrderedBroadcast(intent, null, result, mHandler,
574 Activity.RESULT_OK, null, null);
575 } else {
576 mContext.sendBroadcast(intent);
577 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800578 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700579
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800580 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800581 final int N = mAdminList.size();
582 if (N > 0) {
583 for (int i=0; i<N; i++) {
584 ActiveAdmin admin = mAdminList.get(i);
585 if (admin.info.usesPolicy(reqPolicy)) {
586 sendAdminCommandLocked(admin, action);
587 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800588 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800589 }
590 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700591
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700592 void removeActiveAdminLocked(final ComponentName adminReceiver) {
593 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800594 if (admin != null) {
595 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700596 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
597 new BroadcastReceiver() {
598 @Override
599 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700600 synchronized (DevicePolicyManagerService.this) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700601 boolean doProxyCleanup = admin.info.usesPolicy(
602 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
603 mAdminList.remove(admin);
604 mAdminMap.remove(adminReceiver);
605 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700606 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700607 if (doProxyCleanup) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700608 resetGlobalProxyLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700609 }
610 saveSettingsLocked();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700611 updateMaximumTimeToLockLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700612 }
613 }
614 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800615 }
616 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700617
Dianne Hackbornd6847842010-01-12 18:14:19 -0800618 public DeviceAdminInfo findAdmin(ComponentName adminName) {
619 Intent resolveIntent = new Intent();
620 resolveIntent.setComponent(adminName);
621 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
622 resolveIntent, PackageManager.GET_META_DATA);
623 if (infos == null || infos.size() <= 0) {
624 throw new IllegalArgumentException("Unknown admin: " + adminName);
625 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700626
Dianne Hackbornd6847842010-01-12 18:14:19 -0800627 try {
628 return new DeviceAdminInfo(mContext, infos.get(0));
629 } catch (XmlPullParserException 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 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700633 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800634 return null;
635 }
636 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700637
Dianne Hackbornd6847842010-01-12 18:14:19 -0800638 private static JournaledFile makeJournaledFile() {
639 final String base = "/data/system/device_policies.xml";
640 return new JournaledFile(new File(base), new File(base + ".tmp"));
641 }
642
643 private void saveSettingsLocked() {
644 JournaledFile journal = makeJournaledFile();
645 FileOutputStream stream = null;
646 try {
647 stream = new FileOutputStream(journal.chooseForWrite(), false);
648 XmlSerializer out = new FastXmlSerializer();
649 out.setOutput(stream, "utf-8");
650 out.startDocument(null, true);
651
652 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700653
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800654 final int N = mAdminList.size();
655 for (int i=0; i<N; i++) {
656 ActiveAdmin ap = mAdminList.get(i);
657 if (ap != null) {
658 out.startTag(null, "admin");
659 out.attribute(null, "name", ap.info.getComponent().flattenToString());
660 ap.writeToXml(out);
661 out.endTag(null, "admin");
662 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800663 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700664
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800665 if (mPasswordOwner >= 0) {
666 out.startTag(null, "password-owner");
667 out.attribute(null, "value", Integer.toString(mPasswordOwner));
668 out.endTag(null, "password-owner");
669 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700670
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800671 if (mFailedPasswordAttempts != 0) {
672 out.startTag(null, "failed-password-attempts");
673 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
674 out.endTag(null, "failed-password-attempts");
675 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700676
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700677 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
678 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
679 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700680 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700681 out.startTag(null, "active-password");
682 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
683 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700684 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
685 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
686 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
687 out.attribute(null, "numeric", Integer
688 .toString(mActivePasswordNumeric));
689 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700690 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700691 out.endTag(null, "active-password");
692 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700693
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700694 out.endTag(null, "policies");
695
Dianne Hackbornd6847842010-01-12 18:14:19 -0800696 out.endDocument();
697 stream.close();
698 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700699 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800700 } catch (IOException e) {
701 try {
702 if (stream != null) {
703 stream.close();
704 }
705 } catch (IOException ex) {
706 // Ignore
707 }
708 journal.rollback();
709 }
710 }
711
Jim Miller284b62e2010-06-08 14:27:42 -0700712 private void sendChangedNotification() {
713 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
714 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
715 mContext.sendBroadcast(intent);
716 }
717
Dianne Hackbornd6847842010-01-12 18:14:19 -0800718 private void loadSettingsLocked() {
719 JournaledFile journal = makeJournaledFile();
720 FileInputStream stream = null;
721 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800722 try {
723 stream = new FileInputStream(file);
724 XmlPullParser parser = Xml.newPullParser();
725 parser.setInput(stream, null);
726
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800727 int type;
728 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
729 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800730 }
731 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800732 if (!"policies".equals(tag)) {
733 throw new XmlPullParserException(
734 "Settings do not start with policies tag: found " + tag);
735 }
736 type = parser.next();
737 int outerDepth = parser.getDepth();
738 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
739 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
740 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
741 continue;
742 }
743 tag = parser.getName();
744 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800745 String name = parser.getAttributeValue(null, "name");
746 try {
747 DeviceAdminInfo dai = findAdmin(
748 ComponentName.unflattenFromString(name));
749 if (dai != null) {
750 ActiveAdmin ap = new ActiveAdmin(dai);
751 ap.readFromXml(parser);
752 mAdminMap.put(ap.info.getComponent(), ap);
753 mAdminList.add(ap);
754 }
755 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700756 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800757 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800758 } else if ("failed-password-attempts".equals(tag)) {
759 mFailedPasswordAttempts = Integer.parseInt(
760 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800761 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800762 } else if ("password-owner".equals(tag)) {
763 mPasswordOwner = Integer.parseInt(
764 parser.getAttributeValue(null, "value"));
765 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700766 } else if ("active-password".equals(tag)) {
767 mActivePasswordQuality = Integer.parseInt(
768 parser.getAttributeValue(null, "quality"));
769 mActivePasswordLength = Integer.parseInt(
770 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700771 mActivePasswordUpperCase = Integer.parseInt(
772 parser.getAttributeValue(null, "uppercase"));
773 mActivePasswordLowerCase = Integer.parseInt(
774 parser.getAttributeValue(null, "lowercase"));
775 mActivePasswordLetters = Integer.parseInt(
776 parser.getAttributeValue(null, "letters"));
777 mActivePasswordNumeric = Integer.parseInt(
778 parser.getAttributeValue(null, "numeric"));
779 mActivePasswordSymbols = Integer.parseInt(
780 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700781 mActivePasswordNonLetter = Integer.parseInt(
782 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700783 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800784 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700785 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800786 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800787 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800788 }
789 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700790 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800791 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700792 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800793 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700794 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700795 } catch (FileNotFoundException e) {
796 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800797 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700798 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800799 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700800 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800801 }
802 try {
803 if (stream != null) {
804 stream.close();
805 }
806 } catch (IOException e) {
807 // Ignore
808 }
809
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700810 // Validate that what we stored for the password quality matches
811 // sufficiently what is currently set. Note that this is only
812 // a sanity check in case the two get out of sync; this should
813 // never normally happen.
814 LockPatternUtils utils = new LockPatternUtils(mContext);
815 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
816 Slog.w(TAG, "Active password quality 0x"
817 + Integer.toHexString(mActivePasswordQuality)
818 + " does not match actual quality 0x"
819 + Integer.toHexString(utils.getActivePasswordQuality()));
820 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
821 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700822 mActivePasswordUpperCase = 0;
823 mActivePasswordLowerCase = 0;
824 mActivePasswordLetters = 0;
825 mActivePasswordNumeric = 0;
826 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700827 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700828 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700829
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800830 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700831 syncDeviceCapabilitiesLocked();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700832 updateMaximumTimeToLockLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800833 }
834
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700835 static void validateQualityConstant(int quality) {
836 switch (quality) {
837 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500838 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700839 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
840 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
841 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
842 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700843 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700844 return;
845 }
846 throw new IllegalArgumentException("Invalid quality constant: 0x"
847 + Integer.toHexString(quality));
848 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700849
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800850 void validatePasswordOwnerLocked() {
851 if (mPasswordOwner >= 0) {
852 boolean haveOwner = false;
853 for (int i=mAdminList.size()-1; i>=0; i--) {
854 if (mAdminList.get(i).getUid() == mPasswordOwner) {
855 haveOwner = true;
856 break;
857 }
858 }
859 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700860 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800861 + " no longer active; disabling");
862 mPasswordOwner = -1;
863 }
864 }
865 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700866
Ben Komalo2447edd2011-05-09 16:05:33 -0700867 /**
868 * Pushes down policy information to the system for any policies related to general device
869 * capabilities that need to be enforced by lower level services (e.g. Camera services).
870 */
871 void syncDeviceCapabilitiesLocked() {
872 // Ensure the status of the camera is synced down to the system. Interested native services
873 // should monitor this value and act accordingly.
874 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
875 boolean cameraDisabled = getCameraDisabled(null);
876 if (cameraDisabled != systemState) {
877 long token = Binder.clearCallingIdentity();
878 try {
879 String value = cameraDisabled ? "1" : "0";
880 Slog.v(TAG, "Change in camera state ["
881 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
882 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
883 } finally {
884 Binder.restoreCallingIdentity(token);
885 }
886 }
887 }
888
Dianne Hackbornd6847842010-01-12 18:14:19 -0800889 public void systemReady() {
890 synchronized (this) {
891 loadSettingsLocked();
892 }
893 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700894
Jim Millera4e28d12010-11-08 16:15:47 -0800895 private void handlePasswordExpirationNotification() {
896 synchronized (this) {
897 final long now = System.currentTimeMillis();
898 final int N = mAdminList.size();
899 if (N <= 0) {
900 return;
901 }
902 for (int i=0; i < N; i++) {
903 ActiveAdmin admin = mAdminList.get(i);
904 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
905 && admin.passwordExpirationTimeout > 0L
906 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800907 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800908 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
909 }
910 }
911 setExpirationAlarmCheckLocked(mContext);
912 }
913 }
914
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800915 /**
916 * @param adminReceiver The admin to add
917 * @param refreshing true = update an active admin, no error
918 */
919 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800920 mContext.enforceCallingOrSelfPermission(
921 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700922
Dianne Hackbornd6847842010-01-12 18:14:19 -0800923 DeviceAdminInfo info = findAdmin(adminReceiver);
924 if (info == null) {
925 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
926 }
927 synchronized (this) {
928 long ident = Binder.clearCallingIdentity();
929 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800930 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800931 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800932 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800933 ActiveAdmin newAdmin = new ActiveAdmin(info);
934 mAdminMap.put(adminReceiver, newAdmin);
935 int replaceIndex = -1;
936 if (refreshing) {
937 final int N = mAdminList.size();
938 for (int i=0; i < N; i++) {
939 ActiveAdmin oldAdmin = mAdminList.get(i);
940 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
941 replaceIndex = i;
942 break;
943 }
944 }
945 }
946 if (replaceIndex == -1) {
947 mAdminList.add(newAdmin);
948 } else {
949 mAdminList.set(replaceIndex, newAdmin);
950 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800951 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800952 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800953 } finally {
954 Binder.restoreCallingIdentity(ident);
955 }
956 }
957 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700958
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800959 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800960 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800961 return getActiveAdminUncheckedLocked(adminReceiver) != null;
962 }
963 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700964
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800965 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
966 synchronized (this) {
967 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
968 if (administrator == null) {
969 throw new SecurityException("No active admin " + adminReceiver);
970 }
971 return administrator.info.usesPolicy(policyId);
972 }
973 }
974
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800975 public List<ComponentName> getActiveAdmins() {
976 synchronized (this) {
977 final int N = mAdminList.size();
978 if (N <= 0) {
979 return null;
980 }
981 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
982 for (int i=0; i<N; i++) {
983 res.add(mAdminList.get(i).info.getComponent());
984 }
985 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800986 }
987 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700988
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800989 public boolean packageHasActiveAdmins(String packageName) {
990 synchronized (this) {
991 final int N = mAdminList.size();
992 for (int i=0; i<N; i++) {
993 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
994 return true;
995 }
996 }
997 return false;
998 }
999 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001000
Dianne Hackbornd6847842010-01-12 18:14:19 -08001001 public void removeActiveAdmin(ComponentName adminReceiver) {
1002 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001003 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
1004 if (admin == null) {
1005 return;
1006 }
1007 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001008 mContext.enforceCallingOrSelfPermission(
1009 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1010 }
1011 long ident = Binder.clearCallingIdentity();
1012 try {
1013 removeActiveAdminLocked(adminReceiver);
1014 } finally {
1015 Binder.restoreCallingIdentity(ident);
1016 }
1017 }
1018 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001019
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001020 public void setPasswordQuality(ComponentName who, int quality) {
1021 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001022
Dianne Hackbornd6847842010-01-12 18:14:19 -08001023 synchronized (this) {
1024 if (who == null) {
1025 throw new NullPointerException("ComponentName is null");
1026 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001027 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1028 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001029 if (ap.passwordQuality != quality) {
1030 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001031 saveSettingsLocked();
1032 }
1033 }
1034 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001035
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001036 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001037 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001038 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001039
Dianne Hackborn254cb442010-01-27 19:23:59 -08001040 if (who != null) {
1041 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001042 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001043 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001044
Dianne Hackborn254cb442010-01-27 19:23:59 -08001045 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001046 for (int i=0; i<N; i++) {
1047 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001048 if (mode < admin.passwordQuality) {
1049 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001050 }
1051 }
1052 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001053 }
1054 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001055
Dianne Hackborn254cb442010-01-27 19:23:59 -08001056 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001057 synchronized (this) {
1058 if (who == null) {
1059 throw new NullPointerException("ComponentName is null");
1060 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001061 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1062 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001063 if (ap.minimumPasswordLength != length) {
1064 ap.minimumPasswordLength = length;
1065 saveSettingsLocked();
1066 }
1067 }
1068 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001069
Dianne Hackborn254cb442010-01-27 19:23:59 -08001070 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001071 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001072 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001073
Dianne Hackborn254cb442010-01-27 19:23:59 -08001074 if (who != null) {
1075 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1076 return admin != null ? admin.minimumPasswordLength : length;
1077 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001078
Dianne Hackborn254cb442010-01-27 19:23:59 -08001079 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001080 for (int i=0; i<N; i++) {
1081 ActiveAdmin admin = mAdminList.get(i);
1082 if (length < admin.minimumPasswordLength) {
1083 length = admin.minimumPasswordLength;
1084 }
1085 }
1086 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001087 }
1088 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001089
1090 public void setPasswordHistoryLength(ComponentName who, int length) {
1091 synchronized (this) {
1092 if (who == null) {
1093 throw new NullPointerException("ComponentName is null");
1094 }
1095 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1096 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1097 if (ap.passwordHistoryLength != length) {
1098 ap.passwordHistoryLength = length;
1099 saveSettingsLocked();
1100 }
1101 }
1102 }
1103
1104 public int getPasswordHistoryLength(ComponentName who) {
1105 synchronized (this) {
1106 int length = 0;
1107
1108 if (who != null) {
1109 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1110 return admin != null ? admin.passwordHistoryLength : length;
1111 }
1112
1113 final int N = mAdminList.size();
1114 for (int i = 0; i < N; i++) {
1115 ActiveAdmin admin = mAdminList.get(i);
1116 if (length < admin.passwordHistoryLength) {
1117 length = admin.passwordHistoryLength;
1118 }
1119 }
1120 return length;
1121 }
1122 }
1123
Jim Millera4e28d12010-11-08 16:15:47 -08001124 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1125 synchronized (this) {
1126 if (who == null) {
1127 throw new NullPointerException("ComponentName is null");
1128 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001129 if (timeout < 0) {
1130 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001131 }
1132 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1133 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1134 // Calling this API automatically bumps the expiration date
1135 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1136 ap.passwordExpirationDate = expiration;
1137 ap.passwordExpirationTimeout = timeout;
1138 if (timeout > 0L) {
1139 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1140 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1141 .format(new Date(expiration)));
1142 }
1143 saveSettingsLocked();
1144 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1145 }
1146 }
1147
Andy Stadler043116a2010-11-29 17:43:32 -08001148 /**
1149 * Return a single admin's expiration cycle time, or the min of all cycle times.
1150 * Returns 0 if not configured.
1151 */
Jim Millera4e28d12010-11-08 16:15:47 -08001152 public long getPasswordExpirationTimeout(ComponentName who) {
1153 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001154 if (who != null) {
1155 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001156 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001157 }
1158
Andy Stadler043116a2010-11-29 17:43:32 -08001159 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001160 final int N = mAdminList.size();
1161 for (int i = 0; i < N; i++) {
1162 ActiveAdmin admin = mAdminList.get(i);
1163 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1164 && timeout > admin.passwordExpirationTimeout)) {
1165 timeout = admin.passwordExpirationTimeout;
1166 }
1167 }
1168 return timeout;
1169 }
1170 }
1171
Andy Stadler043116a2010-11-29 17:43:32 -08001172 /**
1173 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1174 * Returns 0 if not configured.
1175 */
Jim Millera4e28d12010-11-08 16:15:47 -08001176 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001177 if (who != null) {
1178 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001179 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001180 }
1181
Andy Stadler043116a2010-11-29 17:43:32 -08001182 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001183 final int N = mAdminList.size();
1184 for (int i = 0; i < N; i++) {
1185 ActiveAdmin admin = mAdminList.get(i);
1186 if (timeout == 0L || (admin.passwordExpirationDate != 0
1187 && timeout > admin.passwordExpirationDate)) {
1188 timeout = admin.passwordExpirationDate;
1189 }
1190 }
1191 return timeout;
1192 }
1193
1194 public long getPasswordExpiration(ComponentName who) {
1195 synchronized (this) {
1196 return getPasswordExpirationLocked(who);
1197 }
1198 }
1199
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001200 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1201 synchronized (this) {
1202 if (who == null) {
1203 throw new NullPointerException("ComponentName is null");
1204 }
1205 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1206 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1207 if (ap.minimumPasswordUpperCase != length) {
1208 ap.minimumPasswordUpperCase = length;
1209 saveSettingsLocked();
1210 }
1211 }
1212 }
1213
1214 public int getPasswordMinimumUpperCase(ComponentName who) {
1215 synchronized (this) {
1216 int length = 0;
1217
1218 if (who != null) {
1219 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1220 return admin != null ? admin.minimumPasswordUpperCase : length;
1221 }
1222
1223 final int N = mAdminList.size();
1224 for (int i=0; i<N; i++) {
1225 ActiveAdmin admin = mAdminList.get(i);
1226 if (length < admin.minimumPasswordUpperCase) {
1227 length = admin.minimumPasswordUpperCase;
1228 }
1229 }
1230 return length;
1231 }
1232 }
1233
1234 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1235 synchronized (this) {
1236 if (who == null) {
1237 throw new NullPointerException("ComponentName is null");
1238 }
1239 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1240 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1241 if (ap.minimumPasswordLowerCase != length) {
1242 ap.minimumPasswordLowerCase = length;
1243 saveSettingsLocked();
1244 }
1245 }
1246 }
1247
1248 public int getPasswordMinimumLowerCase(ComponentName who) {
1249 synchronized (this) {
1250 int length = 0;
1251
1252 if (who != null) {
1253 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1254 return admin != null ? admin.minimumPasswordLowerCase : length;
1255 }
1256
1257 final int N = mAdminList.size();
1258 for (int i=0; i<N; i++) {
1259 ActiveAdmin admin = mAdminList.get(i);
1260 if (length < admin.minimumPasswordLowerCase) {
1261 length = admin.minimumPasswordLowerCase;
1262 }
1263 }
1264 return length;
1265 }
1266 }
1267
1268 public void setPasswordMinimumLetters(ComponentName who, int length) {
1269 synchronized (this) {
1270 if (who == null) {
1271 throw new NullPointerException("ComponentName is null");
1272 }
1273 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1274 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1275 if (ap.minimumPasswordLetters != length) {
1276 ap.minimumPasswordLetters = length;
1277 saveSettingsLocked();
1278 }
1279 }
1280 }
1281
1282 public int getPasswordMinimumLetters(ComponentName who) {
1283 synchronized (this) {
1284 int length = 0;
1285
1286 if (who != null) {
1287 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1288 return admin != null ? admin.minimumPasswordLetters : length;
1289 }
1290
1291 final int N = mAdminList.size();
1292 for (int i=0; i<N; i++) {
1293 ActiveAdmin admin = mAdminList.get(i);
1294 if (length < admin.minimumPasswordLetters) {
1295 length = admin.minimumPasswordLetters;
1296 }
1297 }
1298 return length;
1299 }
1300 }
1301
1302 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1303 synchronized (this) {
1304 if (who == null) {
1305 throw new NullPointerException("ComponentName is null");
1306 }
1307 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1308 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1309 if (ap.minimumPasswordNumeric != length) {
1310 ap.minimumPasswordNumeric = length;
1311 saveSettingsLocked();
1312 }
1313 }
1314 }
1315
1316 public int getPasswordMinimumNumeric(ComponentName who) {
1317 synchronized (this) {
1318 int length = 0;
1319
1320 if (who != null) {
1321 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1322 return admin != null ? admin.minimumPasswordNumeric : length;
1323 }
1324
1325 final int N = mAdminList.size();
1326 for (int i = 0; i < N; i++) {
1327 ActiveAdmin admin = mAdminList.get(i);
1328 if (length < admin.minimumPasswordNumeric) {
1329 length = admin.minimumPasswordNumeric;
1330 }
1331 }
1332 return length;
1333 }
1334 }
1335
1336 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1337 synchronized (this) {
1338 if (who == null) {
1339 throw new NullPointerException("ComponentName is null");
1340 }
1341 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1342 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1343 if (ap.minimumPasswordSymbols != length) {
1344 ap.minimumPasswordSymbols = length;
1345 saveSettingsLocked();
1346 }
1347 }
1348 }
1349
1350 public int getPasswordMinimumSymbols(ComponentName who) {
1351 synchronized (this) {
1352 int length = 0;
1353
1354 if (who != null) {
1355 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1356 return admin != null ? admin.minimumPasswordSymbols : length;
1357 }
1358
1359 final int N = mAdminList.size();
1360 for (int i=0; i<N; i++) {
1361 ActiveAdmin admin = mAdminList.get(i);
1362 if (length < admin.minimumPasswordSymbols) {
1363 length = admin.minimumPasswordSymbols;
1364 }
1365 }
1366 return length;
1367 }
1368 }
1369
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001370 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1371 synchronized (this) {
1372 if (who == null) {
1373 throw new NullPointerException("ComponentName is null");
1374 }
1375 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1376 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1377 if (ap.minimumPasswordNonLetter != length) {
1378 ap.minimumPasswordNonLetter = length;
1379 saveSettingsLocked();
1380 }
1381 }
1382 }
1383
1384 public int getPasswordMinimumNonLetter(ComponentName who) {
1385 synchronized (this) {
1386 int length = 0;
1387
1388 if (who != null) {
1389 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1390 return admin != null ? admin.minimumPasswordNonLetter : length;
1391 }
1392
1393 final int N = mAdminList.size();
1394 for (int i=0; i<N; i++) {
1395 ActiveAdmin admin = mAdminList.get(i);
1396 if (length < admin.minimumPasswordNonLetter) {
1397 length = admin.minimumPasswordNonLetter;
1398 }
1399 }
1400 return length;
1401 }
1402 }
1403
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001404 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001405 synchronized (this) {
1406 // This API can only be called by an active device admin,
1407 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001408 getActiveAdminForCallerLocked(null,
1409 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001410 if (mActivePasswordQuality < getPasswordQuality(null)
1411 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1412 return false;
1413 }
1414 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1415 return true;
1416 }
1417 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1418 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1419 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1420 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001421 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1422 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001423 }
1424 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001425
Dianne Hackbornd6847842010-01-12 18:14:19 -08001426 public int getCurrentFailedPasswordAttempts() {
1427 synchronized (this) {
1428 // This API can only be called by an active device admin,
1429 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001430 getActiveAdminForCallerLocked(null,
1431 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001432 return mFailedPasswordAttempts;
1433 }
1434 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001435
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001436 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1437 synchronized (this) {
1438 // This API can only be called by an active device admin,
1439 // so try to retrieve it to check that the caller is one.
1440 getActiveAdminForCallerLocked(who,
1441 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1442 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1443 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1444 if (ap.maximumFailedPasswordsForWipe != num) {
1445 ap.maximumFailedPasswordsForWipe = num;
1446 saveSettingsLocked();
1447 }
1448 }
1449 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001450
Dianne Hackborn254cb442010-01-27 19:23:59 -08001451 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001452 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001453 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001454
Dianne Hackborn254cb442010-01-27 19:23:59 -08001455 if (who != null) {
1456 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1457 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1458 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001459
Dianne Hackborn254cb442010-01-27 19:23:59 -08001460 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001461 for (int i=0; i<N; i++) {
1462 ActiveAdmin admin = mAdminList.get(i);
1463 if (count == 0) {
1464 count = admin.maximumFailedPasswordsForWipe;
1465 } else if (admin.maximumFailedPasswordsForWipe != 0
1466 && count > admin.maximumFailedPasswordsForWipe) {
1467 count = admin.maximumFailedPasswordsForWipe;
1468 }
1469 }
1470 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001471 }
1472 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001473
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001474 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001475 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001476 synchronized (this) {
1477 // This API can only be called by an active device admin,
1478 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001479 getActiveAdminForCallerLocked(null,
1480 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001481 quality = getPasswordQuality(null);
1482 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001483 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001484 if (realQuality < quality
1485 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001486 Slog.w(TAG, "resetPassword: password quality 0x"
1487 + Integer.toHexString(quality)
1488 + " does not meet required quality 0x"
1489 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001490 return false;
1491 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001492 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001493 }
1494 int length = getPasswordMinimumLength(null);
1495 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001496 Slog.w(TAG, "resetPassword: password length " + password.length()
1497 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001498 return false;
1499 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001500 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1501 int letters = 0;
1502 int uppercase = 0;
1503 int lowercase = 0;
1504 int numbers = 0;
1505 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001506 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001507 for (int i = 0; i < password.length(); i++) {
1508 char c = password.charAt(i);
1509 if (c >= 'A' && c <= 'Z') {
1510 letters++;
1511 uppercase++;
1512 } else if (c >= 'a' && c <= 'z') {
1513 letters++;
1514 lowercase++;
1515 } else if (c >= '0' && c <= '9') {
1516 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001517 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001518 } else {
1519 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001520 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001521 }
1522 }
1523 int neededLetters = getPasswordMinimumLetters(null);
1524 if(letters < neededLetters) {
1525 Slog.w(TAG, "resetPassword: number of letters " + letters
1526 + " does not meet required number of letters " + neededLetters);
1527 return false;
1528 }
1529 int neededNumbers = getPasswordMinimumNumeric(null);
1530 if (numbers < neededNumbers) {
1531 Slog
1532 .w(TAG, "resetPassword: number of numerical digits " + numbers
1533 + " does not meet required number of numerical digits "
1534 + neededNumbers);
1535 return false;
1536 }
1537 int neededLowerCase = getPasswordMinimumLowerCase(null);
1538 if (lowercase < neededLowerCase) {
1539 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1540 + " does not meet required number of lowercase letters "
1541 + neededLowerCase);
1542 return false;
1543 }
1544 int neededUpperCase = getPasswordMinimumUpperCase(null);
1545 if (uppercase < neededUpperCase) {
1546 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1547 + " does not meet required number of uppercase letters "
1548 + neededUpperCase);
1549 return false;
1550 }
1551 int neededSymbols = getPasswordMinimumSymbols(null);
1552 if (symbols < neededSymbols) {
1553 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1554 + " does not meet required number of special symbols " + neededSymbols);
1555 return false;
1556 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001557 int neededNonLetter = getPasswordMinimumNonLetter(null);
1558 if (nonletter < neededNonLetter) {
1559 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1560 + " does not meet required number of non-letter characters "
1561 + neededNonLetter);
1562 return false;
1563 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001564 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001565 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001566
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001567 int callingUid = Binder.getCallingUid();
1568 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001569 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001570 return false;
1571 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001572
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001573 // Don't do this with the lock held, because it is going to call
1574 // back in to the service.
1575 long ident = Binder.clearCallingIdentity();
1576 try {
1577 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001578 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001579 synchronized (this) {
1580 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1581 != 0 ? callingUid : -1;
1582 if (mPasswordOwner != newOwner) {
1583 mPasswordOwner = newOwner;
1584 saveSettingsLocked();
1585 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001586 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001587 } finally {
1588 Binder.restoreCallingIdentity(ident);
1589 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001590
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001591 return true;
1592 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001593
Dianne Hackbornd6847842010-01-12 18:14:19 -08001594 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1595 synchronized (this) {
1596 if (who == null) {
1597 throw new NullPointerException("ComponentName is null");
1598 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001599 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001600 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001601 if (ap.maximumTimeToUnlock != timeMs) {
1602 ap.maximumTimeToUnlock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001603 saveSettingsLocked();
1604 updateMaximumTimeToLockLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001605 }
1606 }
1607 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001608
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001609 void updateMaximumTimeToLockLocked() {
1610 long timeMs = getMaximumTimeToLock(null);
1611 if (mLastMaximumTimeToLock == timeMs) {
1612 return;
1613 }
1614
1615 long ident = Binder.clearCallingIdentity();
1616 try {
1617 if (timeMs <= 0) {
1618 timeMs = Integer.MAX_VALUE;
1619 } else {
1620 // Make sure KEEP_SCREEN_ON is disabled, since that
1621 // would allow bypassing of the maximum time to lock.
1622 Settings.System.putInt(mContext.getContentResolver(),
1623 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
1624 }
1625
1626 mLastMaximumTimeToLock = timeMs;
1627
1628 try {
Jeff Brown96307042012-07-27 15:51:34 -07001629 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001630 } catch (RemoteException e) {
1631 Slog.w(TAG, "Failure talking with power manager", e);
1632 }
1633 } finally {
1634 Binder.restoreCallingIdentity(ident);
1635 }
1636 }
1637
Dianne Hackborn254cb442010-01-27 19:23:59 -08001638 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001639 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001640 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001641
Dianne Hackborn254cb442010-01-27 19:23:59 -08001642 if (who != null) {
1643 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1644 return admin != null ? admin.maximumTimeToUnlock : time;
1645 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001646
Dianne Hackborn254cb442010-01-27 19:23:59 -08001647 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001648 for (int i=0; i<N; i++) {
1649 ActiveAdmin admin = mAdminList.get(i);
1650 if (time == 0) {
1651 time = admin.maximumTimeToUnlock;
1652 } else if (admin.maximumTimeToUnlock != 0
1653 && time > admin.maximumTimeToUnlock) {
1654 time = admin.maximumTimeToUnlock;
1655 }
1656 }
1657 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001658 }
1659 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001660
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001661 public void lockNow() {
1662 synchronized (this) {
1663 // This API can only be called by an active device admin,
1664 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001665 getActiveAdminForCallerLocked(null,
1666 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001667 long ident = Binder.clearCallingIdentity();
1668 try {
Jim Miller93c518e2012-01-17 15:55:31 -08001669 // Power off the display
Jeff Brown96307042012-07-27 15:51:34 -07001670 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1671 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
Jim Miller93c518e2012-01-17 15:55:31 -08001672 // Ensure the device is locked
1673 getWindowManager().lockNow();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001674 } catch (RemoteException e) {
1675 } finally {
1676 Binder.restoreCallingIdentity(ident);
1677 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001678 }
1679 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001680
Ben Komaloed48c8b2011-10-17 17:30:21 -07001681 private boolean isExtStorageEncrypted() {
1682 String state = SystemProperties.get("vold.decrypt");
1683 return !"".equals(state);
1684 }
1685
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001686 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001687 // If the SD card is encrypted and non-removable, we have to force a wipe.
1688 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1689 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1690
1691 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1692 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001693 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001694 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001695 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1696 mWakeLock.acquire(10000);
1697 mContext.startService(intent);
1698 } else {
1699 try {
1700 RecoverySystem.rebootWipeUserData(mContext);
1701 } catch (IOException e) {
1702 Slog.w(TAG, "Failed requesting data wipe", e);
1703 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001704 }
1705 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001706
Dianne Hackbornd6847842010-01-12 18:14:19 -08001707 public void wipeData(int flags) {
1708 synchronized (this) {
1709 // This API can only be called by an active device admin,
1710 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001711 getActiveAdminForCallerLocked(null,
1712 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001713 long ident = Binder.clearCallingIdentity();
1714 try {
1715 wipeDataLocked(flags);
1716 } finally {
1717 Binder.restoreCallingIdentity(ident);
1718 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001719 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001720 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001721
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001722 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1723 mContext.enforceCallingOrSelfPermission(
1724 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001725
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001726 synchronized (this) {
1727 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1728 if (admin == null) {
1729 try {
1730 result.sendResult(null);
1731 } catch (RemoteException e) {
1732 }
1733 return;
1734 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001735 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001736 intent.setComponent(admin.info.getComponent());
1737 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1738 @Override
1739 public void onReceive(Context context, Intent intent) {
1740 try {
1741 result.sendResult(getResultExtras(false));
1742 } catch (RemoteException e) {
1743 }
1744 }
1745 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001746 }
1747 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001748
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001749 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001750 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001751 mContext.enforceCallingOrSelfPermission(
1752 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001753
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001754 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001755
Dianne Hackbornd6847842010-01-12 18:14:19 -08001756 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001757 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001758 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1759 || mActivePasswordUpperCase != uppercase
1760 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001761 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001762 long ident = Binder.clearCallingIdentity();
1763 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001764 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001765 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001766 mActivePasswordLetters = letters;
1767 mActivePasswordLowerCase = lowercase;
1768 mActivePasswordUpperCase = uppercase;
1769 mActivePasswordNumeric = numbers;
1770 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001771 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001772 mFailedPasswordAttempts = 0;
1773 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001774 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001775 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001776 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001777 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001778 } finally {
1779 Binder.restoreCallingIdentity(ident);
1780 }
1781 }
1782 }
1783 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001784
Andy Stadler043116a2010-11-29 17:43:32 -08001785 /**
1786 * Called any time the device password is updated. Resets all password expiration clocks.
1787 */
Jim Millera4e28d12010-11-08 16:15:47 -08001788 private void updatePasswordExpirationsLocked() {
1789 final int N = mAdminList.size();
1790 if (N > 0) {
1791 for (int i=0; i<N; i++) {
1792 ActiveAdmin admin = mAdminList.get(i);
1793 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001794 long timeout = admin.passwordExpirationTimeout;
1795 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1796 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001797 }
1798 }
1799 saveSettingsLocked();
1800 }
1801 }
1802
Dianne Hackbornd6847842010-01-12 18:14:19 -08001803 public void reportFailedPasswordAttempt() {
1804 mContext.enforceCallingOrSelfPermission(
1805 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001806
Dianne Hackbornd6847842010-01-12 18:14:19 -08001807 synchronized (this) {
1808 long ident = Binder.clearCallingIdentity();
1809 try {
1810 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001811 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001812 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001813 if (max > 0 && mFailedPasswordAttempts >= max) {
1814 wipeDataLocked(0);
1815 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001816 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001817 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001818 } finally {
1819 Binder.restoreCallingIdentity(ident);
1820 }
1821 }
1822 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001823
Dianne Hackbornd6847842010-01-12 18:14:19 -08001824 public void reportSuccessfulPasswordAttempt() {
1825 mContext.enforceCallingOrSelfPermission(
1826 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001827
Dianne Hackbornd6847842010-01-12 18:14:19 -08001828 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001829 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001830 long ident = Binder.clearCallingIdentity();
1831 try {
1832 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001833 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001834 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001835 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001836 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001837 } finally {
1838 Binder.restoreCallingIdentity(ident);
1839 }
1840 }
1841 }
1842 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001843
Oscar Montemayor69238c62010-08-03 10:51:06 -07001844 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1845 String exclusionList) {
1846 synchronized(this) {
1847 if (who == null) {
1848 throw new NullPointerException("ComponentName is null");
1849 }
1850
1851 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1852 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1853
1854 // Scan through active admins and find if anyone has already
1855 // set the global proxy.
Oscar Montemayor69238c62010-08-03 10:51:06 -07001856 Set<ComponentName> compSet = mAdminMap.keySet();
1857 for (ComponentName component : compSet) {
1858 ActiveAdmin ap = mAdminMap.get(component);
1859 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1860 // Another admin already sets the global proxy
1861 // Return it to the caller.
1862 return component;
1863 }
1864 }
1865 if (proxySpec == null) {
1866 admin.specifiesGlobalProxy = false;
1867 admin.globalProxySpec = null;
1868 admin.globalProxyExclusionList = null;
1869 } else {
1870
1871 admin.specifiesGlobalProxy = true;
1872 admin.globalProxySpec = proxySpec;
1873 admin.globalProxyExclusionList = exclusionList;
1874 }
1875
1876 // Reset the global proxy accordingly
1877 // Do this using system permissions, as apps cannot write to secure settings
1878 long origId = Binder.clearCallingIdentity();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001879 resetGlobalProxyLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -07001880 Binder.restoreCallingIdentity(origId);
1881 return null;
1882 }
1883 }
1884
1885 public ComponentName getGlobalProxyAdmin() {
1886 synchronized(this) {
1887 // Scan through active admins and find if anyone has already
1888 // set the global proxy.
1889 final int N = mAdminList.size();
1890 for (int i = 0; i < N; i++) {
1891 ActiveAdmin ap = mAdminList.get(i);
1892 if (ap.specifiesGlobalProxy) {
1893 // Device admin sets the global proxy
1894 // Return it to the caller.
1895 return ap.info.getComponent();
1896 }
1897 }
1898 }
1899 // No device admin sets the global proxy.
1900 return null;
1901 }
1902
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001903 private void resetGlobalProxyLocked() {
Oscar Montemayor69238c62010-08-03 10:51:06 -07001904 final int N = mAdminList.size();
1905 for (int i = 0; i < N; i++) {
1906 ActiveAdmin ap = mAdminList.get(i);
1907 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001908 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001909 return;
1910 }
1911 }
1912 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001913 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001914 }
1915
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001916 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07001917 if (exclusionList == null) {
1918 exclusionList = "";
1919 }
1920 if (proxySpec == null) {
1921 proxySpec = "";
1922 }
1923 // Remove white spaces
1924 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001925 String data[] = proxySpec.split(":");
1926 int proxyPort = 8080;
1927 if (data.length > 1) {
1928 try {
1929 proxyPort = Integer.parseInt(data[1]);
1930 } catch (NumberFormatException e) {}
1931 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001932 exclusionList = exclusionList.trim();
1933 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001934 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1935 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1936 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1937 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001938 }
1939
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001940 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001941 * Set the storage encryption request for a single admin. Returns the new total request
1942 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001943 */
1944 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1945 synchronized (this) {
1946 // Check for permissions
1947 if (who == null) {
1948 throw new NullPointerException("ComponentName is null");
1949 }
1950 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1951 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1952
Andy Stadler22dbfda2011-01-17 12:47:31 -08001953 // Quick exit: If the filesystem does not support encryption, we can exit early.
1954 if (!isEncryptionSupported()) {
1955 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1956 }
1957
1958 // (1) Record the value for the admin so it's sticky
1959 if (ap.encryptionRequested != encrypt) {
1960 ap.encryptionRequested = encrypt;
1961 saveSettingsLocked();
1962 }
1963
1964 // (2) Compute "max" for all admins
1965 boolean newRequested = false;
1966 final int N = mAdminList.size();
1967 for (int i = 0; i < N; i++) {
1968 newRequested |= mAdminList.get(i).encryptionRequested;
1969 }
1970
1971 // Notify OS of new request
1972 setEncryptionRequested(newRequested);
1973
1974 // Return the new global request status
1975 return newRequested
1976 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1977 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001978 }
1979 }
1980
1981 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001982 * Get the current storage encryption request status for a given admin, or aggregate of all
1983 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001984 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08001985 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001986 synchronized (this) {
1987 // Check for permissions if a particular caller is specified
1988 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08001989 // When checking for a single caller, status is based on caller's request
Andy Stadlerc994d692011-06-01 15:30:54 -07001990 ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
1991 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001992 }
1993
Andy Stadler22dbfda2011-01-17 12:47:31 -08001994 // If no particular caller is specified, return the aggregate set of requests.
1995 // This is short circuited by returning true on the first hit.
1996 final int N = mAdminList.size();
1997 for (int i = 0; i < N; i++) {
1998 if (mAdminList.get(i).encryptionRequested) {
1999 return true;
2000 }
2001 }
2002 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002003 }
2004 }
2005
Andy Stadler22dbfda2011-01-17 12:47:31 -08002006 /**
2007 * Get the current encryption status of the device.
2008 */
2009 public int getStorageEncryptionStatus() {
2010 return getEncryptionStatus();
2011 }
2012
2013 /**
2014 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2015 */
2016 private boolean isEncryptionSupported() {
2017 // Note, this can be implemented as
2018 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2019 // But is provided as a separate internal method if there's a faster way to do a
2020 // simple check for supported-or-not.
2021 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2022 }
2023
2024 /**
2025 * Hook to low-levels: Reporting the current status of encryption.
2026 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2027 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2028 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2029 */
2030 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002031 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2032 if ("encrypted".equalsIgnoreCase(status)) {
2033 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2034 } else if ("unencrypted".equalsIgnoreCase(status)) {
2035 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2036 } else {
2037 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2038 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002039 }
2040
2041 /**
2042 * Hook to low-levels: If needed, record the new admin setting for encryption.
2043 */
2044 private void setEncryptionRequested(boolean encrypt) {
2045 }
2046
Ben Komalo2447edd2011-05-09 16:05:33 -07002047 /**
2048 * The system property used to share the state of the camera. The native camera service
2049 * is expected to read this property and act accordingly.
2050 */
2051 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2052
2053 /**
2054 * Disables all device cameras according to the specified admin.
2055 */
2056 public void setCameraDisabled(ComponentName who, boolean disabled) {
2057 synchronized (this) {
2058 if (who == null) {
2059 throw new NullPointerException("ComponentName is null");
2060 }
2061 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2062 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2063 if (ap.disableCamera != disabled) {
2064 ap.disableCamera = disabled;
2065 saveSettingsLocked();
2066 }
2067 syncDeviceCapabilitiesLocked();
2068 }
2069 }
2070
2071 /**
2072 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2073 * active admins.
2074 */
2075 public boolean getCameraDisabled(ComponentName who) {
2076 synchronized (this) {
2077 if (who != null) {
2078 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
2079 return (admin != null) ? admin.disableCamera : false;
2080 }
2081
2082 // Determine whether or not the device camera is disabled for any active admins.
2083 final int N = mAdminList.size();
2084 for (int i = 0; i < N; i++) {
2085 ActiveAdmin admin = mAdminList.get(i);
2086 if (admin.disableCamera) {
2087 return true;
2088 }
2089 }
2090 return false;
2091 }
2092 }
2093
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002094 @Override
2095 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2096 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2097 != PackageManager.PERMISSION_GRANTED) {
2098
2099 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2100 + Binder.getCallingPid()
2101 + ", uid=" + Binder.getCallingUid());
2102 return;
2103 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002104
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002105 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002106
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002107 synchronized (this) {
2108 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002109
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002110 p.println(" Enabled Device Admins:");
2111 final int N = mAdminList.size();
2112 for (int i=0; i<N; i++) {
2113 ActiveAdmin ap = mAdminList.get(i);
2114 if (ap != null) {
2115 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2116 pw.println(":");
2117 ap.dump(" ", pw);
2118 }
2119 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002120
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002121 pw.println(" ");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002122 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
2123 }
2124 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002125}