blob: 28a4310734c518c5640306849a1e16bf0861e185 [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;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070058import android.os.UserHandle;
Oscar Montemayor69238c62010-08-03 10:51:06 -070059import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080060import android.util.PrintWriterPrinter;
61import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080062import android.util.Slog;
Dianne Hackbornd6847842010-01-12 18:14:19 -080063import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080064import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080065import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080066
67import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080068import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080069import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070070import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080071import java.io.FileOutputStream;
72import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080073import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080074import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080075import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080076import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080077import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080078import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070079import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080080
81/**
82 * Implementation of the device policy APIs.
83 */
84public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Jim Miller6b857682011-02-16 16:27:41 -080085 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080086
Jim Miller6b857682011-02-16 16:27:41 -080087 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070088
Jim Millera4e28d12010-11-08 16:15:47 -080089 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
90
91 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
92 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
93
94 private static final long MS_PER_DAY = 86400 * 1000;
Jim Millera4e28d12010-11-08 16:15:47 -080095
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080096 final Context mContext;
97 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070098 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080099
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800100 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800101 IWindowManager mIWindowManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700102
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800103 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800104 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700105 int mActivePasswordUpperCase = 0;
106 int mActivePasswordLowerCase = 0;
107 int mActivePasswordLetters = 0;
108 int mActivePasswordNumeric = 0;
109 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700110 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800111 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700112
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800113 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800114 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700115
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700116 long mLastMaximumTimeToLock = -1;
117
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800118 final HashMap<ComponentName, ActiveAdmin> mAdminMap
119 = new HashMap<ComponentName, ActiveAdmin>();
120 final ArrayList<ActiveAdmin> mAdminList
121 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700122
Jim Millera4e28d12010-11-08 16:15:47 -0800123 BroadcastReceiver mReceiver = new BroadcastReceiver() {
124 @Override
125 public void onReceive(Context context, Intent intent) {
126 String action = intent.getAction();
127 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
128 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
129 Slog.v(TAG, "Sending password expiration notifications for action " + action);
130 mHandler.post(new Runnable() {
131 public void run() {
132 handlePasswordExpirationNotification();
133 }
134 });
135 }
136 }
137 };
138
Dianne Hackbornd6847842010-01-12 18:14:19 -0800139 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800140 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700141
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800142 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700143
144 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
145 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
146
147 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
148 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
149
150 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
151 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
152
153 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
154 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
155
156 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700157 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700158
159 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
160 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
161
162 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
163 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
164
165 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
166 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
167
168 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
169 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
170
171 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
172 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
173
174 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
175 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
176
177 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
178 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
179
Jim Millerb8ec4702012-08-31 17:19:10 -0700180 static final int DEF_KEYGUARD_WIDGET_DISABLED = 0; // none
181 int disableKeyguardWidgets = DEF_KEYGUARD_WIDGET_DISABLED;
182
Andy Stadler22dbfda2011-01-17 12:47:31 -0800183 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700184 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700185
Oscar Montemayor69238c62010-08-03 10:51:06 -0700186 // TODO: review implementation decisions with frameworks team
187 boolean specifiesGlobalProxy = false;
188 String globalProxySpec = null;
189 String globalProxyExclusionList = null;
190
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800191 ActiveAdmin(DeviceAdminInfo _info) {
192 info = _info;
193 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700194
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800195 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700196
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800197 void writeToXml(XmlSerializer out)
198 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800199 out.startTag(null, "policies");
200 info.writePoliciesToXml(out);
201 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800202 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
203 out.startTag(null, "password-quality");
204 out.attribute(null, "value", Integer.toString(passwordQuality));
205 out.endTag(null, "password-quality");
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700206 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800207 out.startTag(null, "min-password-length");
208 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700209 out.endTag(null, "min-password-length");
210 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700211 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700212 out.startTag(null, "password-history-length");
213 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
214 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800215 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700216 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700217 out.startTag(null, "min-password-uppercase");
218 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
219 out.endTag(null, "min-password-uppercase");
220 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700221 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700222 out.startTag(null, "min-password-lowercase");
223 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
224 out.endTag(null, "min-password-lowercase");
225 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700226 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700227 out.startTag(null, "min-password-letters");
228 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
229 out.endTag(null, "min-password-letters");
230 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700231 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700232 out.startTag(null, "min-password-numeric");
233 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
234 out.endTag(null, "min-password-numeric");
235 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700236 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700237 out.startTag(null, "min-password-symbols");
238 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
239 out.endTag(null, "min-password-symbols");
240 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700241 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700242 out.startTag(null, "min-password-nonletter");
243 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
244 out.endTag(null, "min-password-nonletter");
245 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800246 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700247 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800248 out.startTag(null, "max-time-to-unlock");
249 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
250 out.endTag(null, "max-time-to-unlock");
251 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700252 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800253 out.startTag(null, "max-failed-password-wipe");
254 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
255 out.endTag(null, "max-failed-password-wipe");
256 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700257 if (specifiesGlobalProxy) {
258 out.startTag(null, "specifies-global-proxy");
259 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
260 out.endTag(null, "specifies_global_proxy");
261 if (globalProxySpec != null) {
262 out.startTag(null, "global-proxy-spec");
263 out.attribute(null, "value", globalProxySpec);
264 out.endTag(null, "global-proxy-spec");
265 }
266 if (globalProxyExclusionList != null) {
267 out.startTag(null, "global-proxy-exclusion-list");
268 out.attribute(null, "value", globalProxyExclusionList);
269 out.endTag(null, "global-proxy-exclusion-list");
270 }
271 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700272 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800273 out.startTag(null, "password-expiration-timeout");
274 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
275 out.endTag(null, "password-expiration-timeout");
276 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700277 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800278 out.startTag(null, "password-expiration-date");
279 out.attribute(null, "value", Long.toString(passwordExpirationDate));
280 out.endTag(null, "password-expiration-date");
281 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800282 if (encryptionRequested) {
283 out.startTag(null, "encryption-requested");
284 out.attribute(null, "value", Boolean.toString(encryptionRequested));
285 out.endTag(null, "encryption-requested");
286 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700287 if (disableCamera) {
288 out.startTag(null, "disable-camera");
289 out.attribute(null, "value", Boolean.toString(disableCamera));
290 out.endTag(null, "disable-camera");
291 }
Jim Millerb8ec4702012-08-31 17:19:10 -0700292 if (disableKeyguardWidgets != DEF_KEYGUARD_WIDGET_DISABLED) {
293 out.startTag(null, "disable-keyguard-widgets");
294 out.attribute(null, "value", Integer.toString(disableKeyguardWidgets));
295 out.endTag(null, "disable-keyguard-widgets");
296 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800297 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700298
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800299 void readFromXml(XmlPullParser parser)
300 throws XmlPullParserException, IOException {
301 int outerDepth = parser.getDepth();
302 int type;
303 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
304 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
305 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
306 continue;
307 }
308 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800309 if ("policies".equals(tag)) {
310 info.readPoliciesFromXml(parser);
311 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800312 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800313 parser.getAttributeValue(null, "value"));
314 } else if ("min-password-length".equals(tag)) {
315 minimumPasswordLength = Integer.parseInt(
316 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700317 } else if ("password-history-length".equals(tag)) {
318 passwordHistoryLength = Integer.parseInt(
319 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700320 } else if ("min-password-uppercase".equals(tag)) {
321 minimumPasswordUpperCase = Integer.parseInt(
322 parser.getAttributeValue(null, "value"));
323 } else if ("min-password-lowercase".equals(tag)) {
324 minimumPasswordLowerCase = Integer.parseInt(
325 parser.getAttributeValue(null, "value"));
326 } else if ("min-password-letters".equals(tag)) {
327 minimumPasswordLetters = Integer.parseInt(
328 parser.getAttributeValue(null, "value"));
329 } else if ("min-password-numeric".equals(tag)) {
330 minimumPasswordNumeric = Integer.parseInt(
331 parser.getAttributeValue(null, "value"));
332 } else if ("min-password-symbols".equals(tag)) {
333 minimumPasswordSymbols = Integer.parseInt(
334 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700335 } else if ("min-password-nonletter".equals(tag)) {
336 minimumPasswordNonLetter = Integer.parseInt(
337 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800338 } else if ("max-time-to-unlock".equals(tag)) {
339 maximumTimeToUnlock = Long.parseLong(
340 parser.getAttributeValue(null, "value"));
341 } else if ("max-failed-password-wipe".equals(tag)) {
342 maximumFailedPasswordsForWipe = Integer.parseInt(
343 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700344 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800345 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700346 parser.getAttributeValue(null, "value"));
347 } else if ("global-proxy-spec".equals(tag)) {
348 globalProxySpec =
349 parser.getAttributeValue(null, "value");
350 } else if ("global-proxy-exclusion-list".equals(tag)) {
351 globalProxyExclusionList =
352 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800353 } else if ("password-expiration-timeout".equals(tag)) {
354 passwordExpirationTimeout = Long.parseLong(
355 parser.getAttributeValue(null, "value"));
356 } else if ("password-expiration-date".equals(tag)) {
357 passwordExpirationDate = Long.parseLong(
358 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800359 } else if ("encryption-requested".equals(tag)) {
360 encryptionRequested = Boolean.parseBoolean(
361 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700362 } else if ("disable-camera".equals(tag)) {
363 disableCamera = Boolean.parseBoolean(
364 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800365 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700366 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800367 }
368 XmlUtils.skipCurrentTag(parser);
369 }
370 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700371
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800372 void dump(String prefix, PrintWriter pw) {
373 pw.print(prefix); pw.print("uid="); pw.println(getUid());
374 pw.print(prefix); pw.println("policies:");
375 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
376 if (pols != null) {
377 for (int i=0; i<pols.size(); i++) {
378 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
379 }
380 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700381 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700382 pw.println(Integer.toHexString(passwordQuality));
383 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800384 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700385 pw.print(prefix); pw.print("passwordHistoryLength=");
386 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700387 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
388 pw.println(minimumPasswordUpperCase);
389 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
390 pw.println(minimumPasswordLowerCase);
391 pw.print(prefix); pw.print("minimumPasswordLetters=");
392 pw.println(minimumPasswordLetters);
393 pw.print(prefix); pw.print("minimumPasswordNumeric=");
394 pw.println(minimumPasswordNumeric);
395 pw.print(prefix); pw.print("minimumPasswordSymbols=");
396 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700397 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
398 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800399 pw.print(prefix); pw.print("maximumTimeToUnlock=");
400 pw.println(maximumTimeToUnlock);
401 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
402 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700403 pw.print(prefix); pw.print("specifiesGlobalProxy=");
404 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800405 pw.print(prefix); pw.print("passwordExpirationTimeout=");
406 pw.println(passwordExpirationTimeout);
407 pw.print(prefix); pw.print("passwordExpirationDate=");
408 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700409 if (globalProxySpec != null) {
410 pw.print(prefix); pw.print("globalProxySpec=");
411 pw.println(globalProxySpec);
412 }
413 if (globalProxyExclusionList != null) {
414 pw.print(prefix); pw.print("globalProxyEclusionList=");
415 pw.println(globalProxyExclusionList);
416 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800417 pw.print(prefix); pw.print("encryptionRequested=");
418 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700419 pw.print(prefix); pw.print("disableCamera=");
420 pw.println(disableCamera);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800421 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800422 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700423
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800424 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800425 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800426 public void onSomePackagesChanged() {
427 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800428 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800429 for (int i=mAdminList.size()-1; i>=0; i--) {
430 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700431 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800432 if (change == PACKAGE_PERMANENT_CHANGE
433 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700434 Slog.w(TAG, "Admin unexpectedly uninstalled: "
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 } else if (isPackageModified(aa.info.getPackageName())) {
439 try {
440 mContext.getPackageManager().getReceiverInfo(
441 aa.info.getComponent(), 0);
442 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700443 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800444 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800445 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800446 mAdminList.remove(i);
447 }
448 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800449 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800450 if (removed) {
451 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700452 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700453 saveSettingsLocked();
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800454 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800455 }
456 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800457 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700458
Dianne Hackbornd6847842010-01-12 18:14:19 -0800459 /**
460 * Instantiates the service.
461 */
462 public DevicePolicyManagerService(Context context) {
463 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800464 mMonitor = new MyPackageMonitor();
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700465 mMonitor.register(context, null, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700466 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
467 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800468 IntentFilter filter = new IntentFilter();
469 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
470 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
471 context.registerReceiver(mReceiver, filter);
472 }
473
Andy Stadler043116a2010-11-29 17:43:32 -0800474 /**
475 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
476 * reminders. Clears alarm if no expirations are configured.
477 */
Jim Millera4e28d12010-11-08 16:15:47 -0800478 protected void setExpirationAlarmCheckLocked(Context context) {
479 final long expiration = getPasswordExpirationLocked(null);
480 final long now = System.currentTimeMillis();
481 final long timeToExpire = expiration - now;
482 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800483 if (expiration == 0) {
484 // No expirations are currently configured: Cancel alarm.
485 alarmTime = 0;
486 } else if (timeToExpire <= 0) {
487 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800488 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800489 } else {
490 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
491 // the expiration time.
492 long alarmInterval = timeToExpire % MS_PER_DAY;
493 if (alarmInterval == 0) {
494 alarmInterval = MS_PER_DAY;
495 }
496 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800497 }
498
Andy Stadler1f35d482010-11-19 15:39:41 -0800499 long token = Binder.clearCallingIdentity();
500 try {
501 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
502 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
503 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
504 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
505 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800506 if (alarmTime != 0) {
507 am.set(AlarmManager.RTC, alarmTime, pi);
508 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800509 } finally {
510 Binder.restoreCallingIdentity(token);
511 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800512 }
513
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800514 private IPowerManager getIPowerManager() {
515 if (mIPowerManager == null) {
516 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
517 mIPowerManager = IPowerManager.Stub.asInterface(b);
518 }
519 return mIPowerManager;
520 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700521
Jim Miller93c518e2012-01-17 15:55:31 -0800522 private IWindowManager getWindowManager() {
523 if (mIWindowManager == null) {
524 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
525 mIWindowManager = IWindowManager.Stub.asInterface(b);
526 }
527 return mIWindowManager;
528 }
529
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800530 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800531 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800532 if (admin != null
533 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
534 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
535 return admin;
536 }
537 return null;
538 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700539
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800540 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
541 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800542 final int callingUid = Binder.getCallingUid();
543 if (who != null) {
544 ActiveAdmin admin = mAdminMap.get(who);
545 if (admin == null) {
546 throw new SecurityException("No active admin " + who);
547 }
548 if (admin.getUid() != callingUid) {
549 throw new SecurityException("Admin " + who + " is not owned by uid "
550 + Binder.getCallingUid());
551 }
552 if (!admin.info.usesPolicy(reqPolicy)) {
553 throw new SecurityException("Admin " + admin.info.getComponent()
554 + " did not specify uses-policy for: "
555 + admin.info.getTagForPolicy(reqPolicy));
556 }
557 return admin;
558 } else {
559 final int N = mAdminList.size();
560 for (int i=0; i<N; i++) {
561 ActiveAdmin admin = mAdminList.get(i);
562 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
563 return admin;
564 }
565 }
566 throw new SecurityException("No active admin owned by uid "
567 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800568 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800569 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700570
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800571 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700572 sendAdminCommandLocked(admin, action, null);
573 }
574
575 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800576 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800577 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800578 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
579 intent.putExtra("expiration", admin.passwordExpirationDate);
580 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700581 if (result != null) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700582 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
583 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700584 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700585 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700586 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800587 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700588
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800589 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800590 final int N = mAdminList.size();
591 if (N > 0) {
592 for (int i=0; i<N; i++) {
593 ActiveAdmin admin = mAdminList.get(i);
594 if (admin.info.usesPolicy(reqPolicy)) {
595 sendAdminCommandLocked(admin, action);
596 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800597 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800598 }
599 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700600
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700601 void removeActiveAdminLocked(final ComponentName adminReceiver) {
602 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800603 if (admin != null) {
604 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700605 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
606 new BroadcastReceiver() {
607 @Override
608 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700609 synchronized (DevicePolicyManagerService.this) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700610 boolean doProxyCleanup = admin.info.usesPolicy(
611 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
612 mAdminList.remove(admin);
613 mAdminMap.remove(adminReceiver);
614 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700615 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700616 if (doProxyCleanup) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700617 resetGlobalProxyLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700618 }
619 saveSettingsLocked();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700620 updateMaximumTimeToLockLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700621 }
622 }
623 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800624 }
625 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700626
Dianne Hackbornd6847842010-01-12 18:14:19 -0800627 public DeviceAdminInfo findAdmin(ComponentName adminName) {
628 Intent resolveIntent = new Intent();
629 resolveIntent.setComponent(adminName);
630 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
631 resolveIntent, PackageManager.GET_META_DATA);
632 if (infos == null || infos.size() <= 0) {
633 throw new IllegalArgumentException("Unknown admin: " + adminName);
634 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700635
Dianne Hackbornd6847842010-01-12 18:14:19 -0800636 try {
637 return new DeviceAdminInfo(mContext, infos.get(0));
638 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700639 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800640 return null;
641 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700642 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800643 return null;
644 }
645 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700646
Dianne Hackbornd6847842010-01-12 18:14:19 -0800647 private static JournaledFile makeJournaledFile() {
648 final String base = "/data/system/device_policies.xml";
649 return new JournaledFile(new File(base), new File(base + ".tmp"));
650 }
651
652 private void saveSettingsLocked() {
653 JournaledFile journal = makeJournaledFile();
654 FileOutputStream stream = null;
655 try {
656 stream = new FileOutputStream(journal.chooseForWrite(), false);
657 XmlSerializer out = new FastXmlSerializer();
658 out.setOutput(stream, "utf-8");
659 out.startDocument(null, true);
660
661 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700662
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800663 final int N = mAdminList.size();
664 for (int i=0; i<N; i++) {
665 ActiveAdmin ap = mAdminList.get(i);
666 if (ap != null) {
667 out.startTag(null, "admin");
668 out.attribute(null, "name", ap.info.getComponent().flattenToString());
669 ap.writeToXml(out);
670 out.endTag(null, "admin");
671 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800672 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700673
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800674 if (mPasswordOwner >= 0) {
675 out.startTag(null, "password-owner");
676 out.attribute(null, "value", Integer.toString(mPasswordOwner));
677 out.endTag(null, "password-owner");
678 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700679
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800680 if (mFailedPasswordAttempts != 0) {
681 out.startTag(null, "failed-password-attempts");
682 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
683 out.endTag(null, "failed-password-attempts");
684 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700685
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700686 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
687 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
688 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700689 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700690 out.startTag(null, "active-password");
691 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
692 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700693 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
694 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
695 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
696 out.attribute(null, "numeric", Integer
697 .toString(mActivePasswordNumeric));
698 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700699 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700700 out.endTag(null, "active-password");
701 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700702
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700703 out.endTag(null, "policies");
704
Dianne Hackbornd6847842010-01-12 18:14:19 -0800705 out.endDocument();
706 stream.close();
707 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700708 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800709 } catch (IOException e) {
710 try {
711 if (stream != null) {
712 stream.close();
713 }
714 } catch (IOException ex) {
715 // Ignore
716 }
717 journal.rollback();
718 }
719 }
720
Jim Miller284b62e2010-06-08 14:27:42 -0700721 private void sendChangedNotification() {
722 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
723 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700724 long ident = Binder.clearCallingIdentity();
725 try {
726 // TODO: This shouldn't be sent to all users, if DPM is per user.
727 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
728 } finally {
729 Binder.restoreCallingIdentity(ident);
730 }
Jim Miller284b62e2010-06-08 14:27:42 -0700731 }
732
Dianne Hackbornd6847842010-01-12 18:14:19 -0800733 private void loadSettingsLocked() {
734 JournaledFile journal = makeJournaledFile();
735 FileInputStream stream = null;
736 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800737 try {
738 stream = new FileInputStream(file);
739 XmlPullParser parser = Xml.newPullParser();
740 parser.setInput(stream, null);
741
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800742 int type;
743 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
744 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800745 }
746 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800747 if (!"policies".equals(tag)) {
748 throw new XmlPullParserException(
749 "Settings do not start with policies tag: found " + tag);
750 }
751 type = parser.next();
752 int outerDepth = parser.getDepth();
753 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
754 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
755 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
756 continue;
757 }
758 tag = parser.getName();
759 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800760 String name = parser.getAttributeValue(null, "name");
761 try {
762 DeviceAdminInfo dai = findAdmin(
763 ComponentName.unflattenFromString(name));
764 if (dai != null) {
765 ActiveAdmin ap = new ActiveAdmin(dai);
766 ap.readFromXml(parser);
767 mAdminMap.put(ap.info.getComponent(), ap);
768 mAdminList.add(ap);
769 }
770 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700771 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800772 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800773 } else if ("failed-password-attempts".equals(tag)) {
774 mFailedPasswordAttempts = Integer.parseInt(
775 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800776 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800777 } else if ("password-owner".equals(tag)) {
778 mPasswordOwner = Integer.parseInt(
779 parser.getAttributeValue(null, "value"));
780 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700781 } else if ("active-password".equals(tag)) {
782 mActivePasswordQuality = Integer.parseInt(
783 parser.getAttributeValue(null, "quality"));
784 mActivePasswordLength = Integer.parseInt(
785 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700786 mActivePasswordUpperCase = Integer.parseInt(
787 parser.getAttributeValue(null, "uppercase"));
788 mActivePasswordLowerCase = Integer.parseInt(
789 parser.getAttributeValue(null, "lowercase"));
790 mActivePasswordLetters = Integer.parseInt(
791 parser.getAttributeValue(null, "letters"));
792 mActivePasswordNumeric = Integer.parseInt(
793 parser.getAttributeValue(null, "numeric"));
794 mActivePasswordSymbols = Integer.parseInt(
795 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700796 mActivePasswordNonLetter = Integer.parseInt(
797 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700798 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800799 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700800 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800801 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800802 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800803 }
804 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700805 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800806 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700807 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800808 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700809 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700810 } catch (FileNotFoundException e) {
811 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800812 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700813 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800814 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700815 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800816 }
817 try {
818 if (stream != null) {
819 stream.close();
820 }
821 } catch (IOException e) {
822 // Ignore
823 }
824
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700825 // Validate that what we stored for the password quality matches
826 // sufficiently what is currently set. Note that this is only
827 // a sanity check in case the two get out of sync; this should
828 // never normally happen.
829 LockPatternUtils utils = new LockPatternUtils(mContext);
830 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
831 Slog.w(TAG, "Active password quality 0x"
832 + Integer.toHexString(mActivePasswordQuality)
833 + " does not match actual quality 0x"
834 + Integer.toHexString(utils.getActivePasswordQuality()));
835 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
836 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700837 mActivePasswordUpperCase = 0;
838 mActivePasswordLowerCase = 0;
839 mActivePasswordLetters = 0;
840 mActivePasswordNumeric = 0;
841 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700842 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700843 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700844
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800845 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700846 syncDeviceCapabilitiesLocked();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700847 updateMaximumTimeToLockLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800848 }
849
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700850 static void validateQualityConstant(int quality) {
851 switch (quality) {
852 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500853 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700854 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
855 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
856 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
857 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700858 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700859 return;
860 }
861 throw new IllegalArgumentException("Invalid quality constant: 0x"
862 + Integer.toHexString(quality));
863 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700864
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800865 void validatePasswordOwnerLocked() {
866 if (mPasswordOwner >= 0) {
867 boolean haveOwner = false;
868 for (int i=mAdminList.size()-1; i>=0; i--) {
869 if (mAdminList.get(i).getUid() == mPasswordOwner) {
870 haveOwner = true;
871 break;
872 }
873 }
874 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700875 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800876 + " no longer active; disabling");
877 mPasswordOwner = -1;
878 }
879 }
880 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700881
Ben Komalo2447edd2011-05-09 16:05:33 -0700882 /**
883 * Pushes down policy information to the system for any policies related to general device
884 * capabilities that need to be enforced by lower level services (e.g. Camera services).
885 */
886 void syncDeviceCapabilitiesLocked() {
887 // Ensure the status of the camera is synced down to the system. Interested native services
888 // should monitor this value and act accordingly.
889 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
890 boolean cameraDisabled = getCameraDisabled(null);
891 if (cameraDisabled != systemState) {
892 long token = Binder.clearCallingIdentity();
893 try {
894 String value = cameraDisabled ? "1" : "0";
895 Slog.v(TAG, "Change in camera state ["
896 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
897 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
898 } finally {
899 Binder.restoreCallingIdentity(token);
900 }
901 }
902 }
903
Dianne Hackbornd6847842010-01-12 18:14:19 -0800904 public void systemReady() {
905 synchronized (this) {
906 loadSettingsLocked();
907 }
908 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700909
Jim Millera4e28d12010-11-08 16:15:47 -0800910 private void handlePasswordExpirationNotification() {
911 synchronized (this) {
912 final long now = System.currentTimeMillis();
913 final int N = mAdminList.size();
914 if (N <= 0) {
915 return;
916 }
917 for (int i=0; i < N; i++) {
918 ActiveAdmin admin = mAdminList.get(i);
919 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
920 && admin.passwordExpirationTimeout > 0L
921 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800922 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800923 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
924 }
925 }
926 setExpirationAlarmCheckLocked(mContext);
927 }
928 }
929
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800930 /**
931 * @param adminReceiver The admin to add
932 * @param refreshing true = update an active admin, no error
933 */
934 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800935 mContext.enforceCallingOrSelfPermission(
936 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700937
Dianne Hackbornd6847842010-01-12 18:14:19 -0800938 DeviceAdminInfo info = findAdmin(adminReceiver);
939 if (info == null) {
940 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
941 }
942 synchronized (this) {
943 long ident = Binder.clearCallingIdentity();
944 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800945 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800946 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800947 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800948 ActiveAdmin newAdmin = new ActiveAdmin(info);
949 mAdminMap.put(adminReceiver, newAdmin);
950 int replaceIndex = -1;
951 if (refreshing) {
952 final int N = mAdminList.size();
953 for (int i=0; i < N; i++) {
954 ActiveAdmin oldAdmin = mAdminList.get(i);
955 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
956 replaceIndex = i;
957 break;
958 }
959 }
960 }
961 if (replaceIndex == -1) {
962 mAdminList.add(newAdmin);
963 } else {
964 mAdminList.set(replaceIndex, newAdmin);
965 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800966 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800967 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800968 } finally {
969 Binder.restoreCallingIdentity(ident);
970 }
971 }
972 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700973
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800974 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800975 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800976 return getActiveAdminUncheckedLocked(adminReceiver) != null;
977 }
978 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700979
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800980 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
981 synchronized (this) {
982 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
983 if (administrator == null) {
984 throw new SecurityException("No active admin " + adminReceiver);
985 }
986 return administrator.info.usesPolicy(policyId);
987 }
988 }
989
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800990 public List<ComponentName> getActiveAdmins() {
991 synchronized (this) {
992 final int N = mAdminList.size();
993 if (N <= 0) {
994 return null;
995 }
996 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
997 for (int i=0; i<N; i++) {
998 res.add(mAdminList.get(i).info.getComponent());
999 }
1000 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001001 }
1002 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001003
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001004 public boolean packageHasActiveAdmins(String packageName) {
1005 synchronized (this) {
1006 final int N = mAdminList.size();
1007 for (int i=0; i<N; i++) {
1008 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
1009 return true;
1010 }
1011 }
1012 return false;
1013 }
1014 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001015
Dianne Hackbornd6847842010-01-12 18:14:19 -08001016 public void removeActiveAdmin(ComponentName adminReceiver) {
1017 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001018 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
1019 if (admin == null) {
1020 return;
1021 }
1022 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001023 mContext.enforceCallingOrSelfPermission(
1024 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1025 }
1026 long ident = Binder.clearCallingIdentity();
1027 try {
1028 removeActiveAdminLocked(adminReceiver);
1029 } finally {
1030 Binder.restoreCallingIdentity(ident);
1031 }
1032 }
1033 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001034
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001035 public void setPasswordQuality(ComponentName who, int quality) {
1036 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001037
Dianne Hackbornd6847842010-01-12 18:14:19 -08001038 synchronized (this) {
1039 if (who == null) {
1040 throw new NullPointerException("ComponentName is null");
1041 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001042 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1043 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001044 if (ap.passwordQuality != quality) {
1045 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001046 saveSettingsLocked();
1047 }
1048 }
1049 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001050
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001051 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001052 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001053 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001054
Dianne Hackborn254cb442010-01-27 19:23:59 -08001055 if (who != null) {
1056 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001057 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001058 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001059
Dianne Hackborn254cb442010-01-27 19:23:59 -08001060 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001061 for (int i=0; i<N; i++) {
1062 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001063 if (mode < admin.passwordQuality) {
1064 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001065 }
1066 }
1067 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001068 }
1069 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001070
Dianne Hackborn254cb442010-01-27 19:23:59 -08001071 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001072 synchronized (this) {
1073 if (who == null) {
1074 throw new NullPointerException("ComponentName is null");
1075 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001076 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1077 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001078 if (ap.minimumPasswordLength != length) {
1079 ap.minimumPasswordLength = length;
1080 saveSettingsLocked();
1081 }
1082 }
1083 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001084
Dianne Hackborn254cb442010-01-27 19:23:59 -08001085 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001086 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001087 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001088
Dianne Hackborn254cb442010-01-27 19:23:59 -08001089 if (who != null) {
1090 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1091 return admin != null ? admin.minimumPasswordLength : length;
1092 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001093
Dianne Hackborn254cb442010-01-27 19:23:59 -08001094 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001095 for (int i=0; i<N; i++) {
1096 ActiveAdmin admin = mAdminList.get(i);
1097 if (length < admin.minimumPasswordLength) {
1098 length = admin.minimumPasswordLength;
1099 }
1100 }
1101 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001102 }
1103 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001104
1105 public void setPasswordHistoryLength(ComponentName who, int length) {
1106 synchronized (this) {
1107 if (who == null) {
1108 throw new NullPointerException("ComponentName is null");
1109 }
1110 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1111 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1112 if (ap.passwordHistoryLength != length) {
1113 ap.passwordHistoryLength = length;
1114 saveSettingsLocked();
1115 }
1116 }
1117 }
1118
1119 public int getPasswordHistoryLength(ComponentName who) {
1120 synchronized (this) {
1121 int length = 0;
1122
1123 if (who != null) {
1124 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1125 return admin != null ? admin.passwordHistoryLength : length;
1126 }
1127
1128 final int N = mAdminList.size();
1129 for (int i = 0; i < N; i++) {
1130 ActiveAdmin admin = mAdminList.get(i);
1131 if (length < admin.passwordHistoryLength) {
1132 length = admin.passwordHistoryLength;
1133 }
1134 }
1135 return length;
1136 }
1137 }
1138
Jim Millera4e28d12010-11-08 16:15:47 -08001139 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1140 synchronized (this) {
1141 if (who == null) {
1142 throw new NullPointerException("ComponentName is null");
1143 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001144 if (timeout < 0) {
1145 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001146 }
1147 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1148 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1149 // Calling this API automatically bumps the expiration date
1150 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1151 ap.passwordExpirationDate = expiration;
1152 ap.passwordExpirationTimeout = timeout;
1153 if (timeout > 0L) {
1154 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1155 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1156 .format(new Date(expiration)));
1157 }
1158 saveSettingsLocked();
1159 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1160 }
1161 }
1162
Andy Stadler043116a2010-11-29 17:43:32 -08001163 /**
1164 * Return a single admin's expiration cycle time, or the min of all cycle times.
1165 * Returns 0 if not configured.
1166 */
Jim Millera4e28d12010-11-08 16:15:47 -08001167 public long getPasswordExpirationTimeout(ComponentName who) {
1168 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001169 if (who != null) {
1170 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001171 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001172 }
1173
Andy Stadler043116a2010-11-29 17:43:32 -08001174 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001175 final int N = mAdminList.size();
1176 for (int i = 0; i < N; i++) {
1177 ActiveAdmin admin = mAdminList.get(i);
1178 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1179 && timeout > admin.passwordExpirationTimeout)) {
1180 timeout = admin.passwordExpirationTimeout;
1181 }
1182 }
1183 return timeout;
1184 }
1185 }
1186
Andy Stadler043116a2010-11-29 17:43:32 -08001187 /**
1188 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1189 * Returns 0 if not configured.
1190 */
Jim Millera4e28d12010-11-08 16:15:47 -08001191 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001192 if (who != null) {
1193 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001194 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001195 }
1196
Andy Stadler043116a2010-11-29 17:43:32 -08001197 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001198 final int N = mAdminList.size();
1199 for (int i = 0; i < N; i++) {
1200 ActiveAdmin admin = mAdminList.get(i);
1201 if (timeout == 0L || (admin.passwordExpirationDate != 0
1202 && timeout > admin.passwordExpirationDate)) {
1203 timeout = admin.passwordExpirationDate;
1204 }
1205 }
1206 return timeout;
1207 }
1208
1209 public long getPasswordExpiration(ComponentName who) {
1210 synchronized (this) {
1211 return getPasswordExpirationLocked(who);
1212 }
1213 }
1214
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001215 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1216 synchronized (this) {
1217 if (who == null) {
1218 throw new NullPointerException("ComponentName is null");
1219 }
1220 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1221 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1222 if (ap.minimumPasswordUpperCase != length) {
1223 ap.minimumPasswordUpperCase = length;
1224 saveSettingsLocked();
1225 }
1226 }
1227 }
1228
1229 public int getPasswordMinimumUpperCase(ComponentName who) {
1230 synchronized (this) {
1231 int length = 0;
1232
1233 if (who != null) {
1234 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1235 return admin != null ? admin.minimumPasswordUpperCase : length;
1236 }
1237
1238 final int N = mAdminList.size();
1239 for (int i=0; i<N; i++) {
1240 ActiveAdmin admin = mAdminList.get(i);
1241 if (length < admin.minimumPasswordUpperCase) {
1242 length = admin.minimumPasswordUpperCase;
1243 }
1244 }
1245 return length;
1246 }
1247 }
1248
1249 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1250 synchronized (this) {
1251 if (who == null) {
1252 throw new NullPointerException("ComponentName is null");
1253 }
1254 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1255 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1256 if (ap.minimumPasswordLowerCase != length) {
1257 ap.minimumPasswordLowerCase = length;
1258 saveSettingsLocked();
1259 }
1260 }
1261 }
1262
1263 public int getPasswordMinimumLowerCase(ComponentName who) {
1264 synchronized (this) {
1265 int length = 0;
1266
1267 if (who != null) {
1268 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1269 return admin != null ? admin.minimumPasswordLowerCase : length;
1270 }
1271
1272 final int N = mAdminList.size();
1273 for (int i=0; i<N; i++) {
1274 ActiveAdmin admin = mAdminList.get(i);
1275 if (length < admin.minimumPasswordLowerCase) {
1276 length = admin.minimumPasswordLowerCase;
1277 }
1278 }
1279 return length;
1280 }
1281 }
1282
1283 public void setPasswordMinimumLetters(ComponentName who, int length) {
1284 synchronized (this) {
1285 if (who == null) {
1286 throw new NullPointerException("ComponentName is null");
1287 }
1288 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1289 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1290 if (ap.minimumPasswordLetters != length) {
1291 ap.minimumPasswordLetters = length;
1292 saveSettingsLocked();
1293 }
1294 }
1295 }
1296
1297 public int getPasswordMinimumLetters(ComponentName who) {
1298 synchronized (this) {
1299 int length = 0;
1300
1301 if (who != null) {
1302 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1303 return admin != null ? admin.minimumPasswordLetters : length;
1304 }
1305
1306 final int N = mAdminList.size();
1307 for (int i=0; i<N; i++) {
1308 ActiveAdmin admin = mAdminList.get(i);
1309 if (length < admin.minimumPasswordLetters) {
1310 length = admin.minimumPasswordLetters;
1311 }
1312 }
1313 return length;
1314 }
1315 }
1316
1317 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1318 synchronized (this) {
1319 if (who == null) {
1320 throw new NullPointerException("ComponentName is null");
1321 }
1322 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1323 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1324 if (ap.minimumPasswordNumeric != length) {
1325 ap.minimumPasswordNumeric = length;
1326 saveSettingsLocked();
1327 }
1328 }
1329 }
1330
1331 public int getPasswordMinimumNumeric(ComponentName who) {
1332 synchronized (this) {
1333 int length = 0;
1334
1335 if (who != null) {
1336 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1337 return admin != null ? admin.minimumPasswordNumeric : length;
1338 }
1339
1340 final int N = mAdminList.size();
1341 for (int i = 0; i < N; i++) {
1342 ActiveAdmin admin = mAdminList.get(i);
1343 if (length < admin.minimumPasswordNumeric) {
1344 length = admin.minimumPasswordNumeric;
1345 }
1346 }
1347 return length;
1348 }
1349 }
1350
1351 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1352 synchronized (this) {
1353 if (who == null) {
1354 throw new NullPointerException("ComponentName is null");
1355 }
1356 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1357 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1358 if (ap.minimumPasswordSymbols != length) {
1359 ap.minimumPasswordSymbols = length;
1360 saveSettingsLocked();
1361 }
1362 }
1363 }
1364
1365 public int getPasswordMinimumSymbols(ComponentName who) {
1366 synchronized (this) {
1367 int length = 0;
1368
1369 if (who != null) {
1370 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1371 return admin != null ? admin.minimumPasswordSymbols : length;
1372 }
1373
1374 final int N = mAdminList.size();
1375 for (int i=0; i<N; i++) {
1376 ActiveAdmin admin = mAdminList.get(i);
1377 if (length < admin.minimumPasswordSymbols) {
1378 length = admin.minimumPasswordSymbols;
1379 }
1380 }
1381 return length;
1382 }
1383 }
1384
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001385 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1386 synchronized (this) {
1387 if (who == null) {
1388 throw new NullPointerException("ComponentName is null");
1389 }
1390 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1391 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1392 if (ap.minimumPasswordNonLetter != length) {
1393 ap.minimumPasswordNonLetter = length;
1394 saveSettingsLocked();
1395 }
1396 }
1397 }
1398
1399 public int getPasswordMinimumNonLetter(ComponentName who) {
1400 synchronized (this) {
1401 int length = 0;
1402
1403 if (who != null) {
1404 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1405 return admin != null ? admin.minimumPasswordNonLetter : length;
1406 }
1407
1408 final int N = mAdminList.size();
1409 for (int i=0; i<N; i++) {
1410 ActiveAdmin admin = mAdminList.get(i);
1411 if (length < admin.minimumPasswordNonLetter) {
1412 length = admin.minimumPasswordNonLetter;
1413 }
1414 }
1415 return length;
1416 }
1417 }
1418
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001419 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001420 synchronized (this) {
1421 // This API can only be called by an active device admin,
1422 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001423 getActiveAdminForCallerLocked(null,
1424 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001425 if (mActivePasswordQuality < getPasswordQuality(null)
1426 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1427 return false;
1428 }
1429 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1430 return true;
1431 }
1432 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1433 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1434 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1435 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001436 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1437 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001438 }
1439 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001440
Dianne Hackbornd6847842010-01-12 18:14:19 -08001441 public int getCurrentFailedPasswordAttempts() {
1442 synchronized (this) {
1443 // This API can only be called by an active device admin,
1444 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001445 getActiveAdminForCallerLocked(null,
1446 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001447 return mFailedPasswordAttempts;
1448 }
1449 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001450
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001451 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1452 synchronized (this) {
1453 // This API can only be called by an active device admin,
1454 // so try to retrieve it to check that the caller is one.
1455 getActiveAdminForCallerLocked(who,
1456 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1457 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1458 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1459 if (ap.maximumFailedPasswordsForWipe != num) {
1460 ap.maximumFailedPasswordsForWipe = num;
1461 saveSettingsLocked();
1462 }
1463 }
1464 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001465
Dianne Hackborn254cb442010-01-27 19:23:59 -08001466 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001467 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001468 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001469
Dianne Hackborn254cb442010-01-27 19:23:59 -08001470 if (who != null) {
1471 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1472 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1473 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001474
Dianne Hackborn254cb442010-01-27 19:23:59 -08001475 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001476 for (int i=0; i<N; i++) {
1477 ActiveAdmin admin = mAdminList.get(i);
1478 if (count == 0) {
1479 count = admin.maximumFailedPasswordsForWipe;
1480 } else if (admin.maximumFailedPasswordsForWipe != 0
1481 && count > admin.maximumFailedPasswordsForWipe) {
1482 count = admin.maximumFailedPasswordsForWipe;
1483 }
1484 }
1485 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001486 }
1487 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001488
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001489 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001490 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001491 synchronized (this) {
1492 // This API can only be called by an active device admin,
1493 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001494 getActiveAdminForCallerLocked(null,
1495 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001496 quality = getPasswordQuality(null);
1497 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001498 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001499 if (realQuality < quality
1500 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001501 Slog.w(TAG, "resetPassword: password quality 0x"
1502 + Integer.toHexString(quality)
1503 + " does not meet required quality 0x"
1504 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001505 return false;
1506 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001507 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001508 }
1509 int length = getPasswordMinimumLength(null);
1510 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001511 Slog.w(TAG, "resetPassword: password length " + password.length()
1512 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001513 return false;
1514 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001515 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1516 int letters = 0;
1517 int uppercase = 0;
1518 int lowercase = 0;
1519 int numbers = 0;
1520 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001521 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001522 for (int i = 0; i < password.length(); i++) {
1523 char c = password.charAt(i);
1524 if (c >= 'A' && c <= 'Z') {
1525 letters++;
1526 uppercase++;
1527 } else if (c >= 'a' && c <= 'z') {
1528 letters++;
1529 lowercase++;
1530 } else if (c >= '0' && c <= '9') {
1531 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001532 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001533 } else {
1534 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001535 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001536 }
1537 }
1538 int neededLetters = getPasswordMinimumLetters(null);
1539 if(letters < neededLetters) {
1540 Slog.w(TAG, "resetPassword: number of letters " + letters
1541 + " does not meet required number of letters " + neededLetters);
1542 return false;
1543 }
1544 int neededNumbers = getPasswordMinimumNumeric(null);
1545 if (numbers < neededNumbers) {
1546 Slog
1547 .w(TAG, "resetPassword: number of numerical digits " + numbers
1548 + " does not meet required number of numerical digits "
1549 + neededNumbers);
1550 return false;
1551 }
1552 int neededLowerCase = getPasswordMinimumLowerCase(null);
1553 if (lowercase < neededLowerCase) {
1554 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1555 + " does not meet required number of lowercase letters "
1556 + neededLowerCase);
1557 return false;
1558 }
1559 int neededUpperCase = getPasswordMinimumUpperCase(null);
1560 if (uppercase < neededUpperCase) {
1561 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1562 + " does not meet required number of uppercase letters "
1563 + neededUpperCase);
1564 return false;
1565 }
1566 int neededSymbols = getPasswordMinimumSymbols(null);
1567 if (symbols < neededSymbols) {
1568 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1569 + " does not meet required number of special symbols " + neededSymbols);
1570 return false;
1571 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001572 int neededNonLetter = getPasswordMinimumNonLetter(null);
1573 if (nonletter < neededNonLetter) {
1574 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1575 + " does not meet required number of non-letter characters "
1576 + neededNonLetter);
1577 return false;
1578 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001579 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001580 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001581
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001582 int callingUid = Binder.getCallingUid();
1583 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001584 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001585 return false;
1586 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001587
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001588 // Don't do this with the lock held, because it is going to call
1589 // back in to the service.
1590 long ident = Binder.clearCallingIdentity();
1591 try {
1592 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001593 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001594 synchronized (this) {
1595 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1596 != 0 ? callingUid : -1;
1597 if (mPasswordOwner != newOwner) {
1598 mPasswordOwner = newOwner;
1599 saveSettingsLocked();
1600 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001601 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001602 } finally {
1603 Binder.restoreCallingIdentity(ident);
1604 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001605
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001606 return true;
1607 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001608
Dianne Hackbornd6847842010-01-12 18:14:19 -08001609 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1610 synchronized (this) {
1611 if (who == null) {
1612 throw new NullPointerException("ComponentName is null");
1613 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001614 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001615 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001616 if (ap.maximumTimeToUnlock != timeMs) {
1617 ap.maximumTimeToUnlock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001618 saveSettingsLocked();
1619 updateMaximumTimeToLockLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001620 }
1621 }
1622 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001623
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001624 void updateMaximumTimeToLockLocked() {
1625 long timeMs = getMaximumTimeToLock(null);
1626 if (mLastMaximumTimeToLock == timeMs) {
1627 return;
1628 }
1629
1630 long ident = Binder.clearCallingIdentity();
1631 try {
1632 if (timeMs <= 0) {
1633 timeMs = Integer.MAX_VALUE;
1634 } else {
1635 // Make sure KEEP_SCREEN_ON is disabled, since that
1636 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07001637 Settings.Global.putInt(mContext.getContentResolver(),
1638 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001639 }
1640
1641 mLastMaximumTimeToLock = timeMs;
1642
1643 try {
Jeff Brown96307042012-07-27 15:51:34 -07001644 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001645 } catch (RemoteException e) {
1646 Slog.w(TAG, "Failure talking with power manager", e);
1647 }
1648 } finally {
1649 Binder.restoreCallingIdentity(ident);
1650 }
1651 }
1652
Dianne Hackborn254cb442010-01-27 19:23:59 -08001653 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001654 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001655 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001656
Dianne Hackborn254cb442010-01-27 19:23:59 -08001657 if (who != null) {
1658 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1659 return admin != null ? admin.maximumTimeToUnlock : time;
1660 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001661
Dianne Hackborn254cb442010-01-27 19:23:59 -08001662 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001663 for (int i=0; i<N; i++) {
1664 ActiveAdmin admin = mAdminList.get(i);
1665 if (time == 0) {
1666 time = admin.maximumTimeToUnlock;
1667 } else if (admin.maximumTimeToUnlock != 0
1668 && time > admin.maximumTimeToUnlock) {
1669 time = admin.maximumTimeToUnlock;
1670 }
1671 }
1672 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001673 }
1674 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001675
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001676 public void lockNow() {
1677 synchronized (this) {
1678 // This API can only be called by an active device admin,
1679 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001680 getActiveAdminForCallerLocked(null,
1681 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001682 long ident = Binder.clearCallingIdentity();
1683 try {
Jim Miller93c518e2012-01-17 15:55:31 -08001684 // Power off the display
Jeff Brown96307042012-07-27 15:51:34 -07001685 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1686 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
Jim Miller93c518e2012-01-17 15:55:31 -08001687 // Ensure the device is locked
1688 getWindowManager().lockNow();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001689 } catch (RemoteException e) {
1690 } finally {
1691 Binder.restoreCallingIdentity(ident);
1692 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001693 }
1694 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001695
Ben Komaloed48c8b2011-10-17 17:30:21 -07001696 private boolean isExtStorageEncrypted() {
1697 String state = SystemProperties.get("vold.decrypt");
1698 return !"".equals(state);
1699 }
1700
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001701 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001702 // If the SD card is encrypted and non-removable, we have to force a wipe.
1703 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1704 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1705
1706 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1707 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001708 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001709 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001710 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1711 mWakeLock.acquire(10000);
1712 mContext.startService(intent);
1713 } else {
1714 try {
1715 RecoverySystem.rebootWipeUserData(mContext);
1716 } catch (IOException e) {
1717 Slog.w(TAG, "Failed requesting data wipe", e);
1718 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001719 }
1720 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001721
Dianne Hackbornd6847842010-01-12 18:14:19 -08001722 public void wipeData(int flags) {
1723 synchronized (this) {
1724 // This API can only be called by an active device admin,
1725 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001726 getActiveAdminForCallerLocked(null,
1727 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001728 long ident = Binder.clearCallingIdentity();
1729 try {
1730 wipeDataLocked(flags);
1731 } finally {
1732 Binder.restoreCallingIdentity(ident);
1733 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001734 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001735 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001736
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001737 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1738 mContext.enforceCallingOrSelfPermission(
1739 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001740
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001741 synchronized (this) {
1742 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1743 if (admin == null) {
1744 try {
1745 result.sendResult(null);
1746 } catch (RemoteException e) {
1747 }
1748 return;
1749 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001750 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001751 intent.setComponent(admin.info.getComponent());
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001752 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
1753 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001754 @Override
1755 public void onReceive(Context context, Intent intent) {
1756 try {
1757 result.sendResult(getResultExtras(false));
1758 } catch (RemoteException e) {
1759 }
1760 }
1761 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001762 }
1763 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001764
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001765 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001766 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001767 mContext.enforceCallingOrSelfPermission(
1768 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001769
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001770 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001771
Dianne Hackbornd6847842010-01-12 18:14:19 -08001772 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001773 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001774 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1775 || mActivePasswordUpperCase != uppercase
1776 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001777 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001778 long ident = Binder.clearCallingIdentity();
1779 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001780 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001781 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001782 mActivePasswordLetters = letters;
1783 mActivePasswordLowerCase = lowercase;
1784 mActivePasswordUpperCase = uppercase;
1785 mActivePasswordNumeric = numbers;
1786 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001787 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001788 mFailedPasswordAttempts = 0;
1789 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001790 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001791 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001792 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001793 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001794 } finally {
1795 Binder.restoreCallingIdentity(ident);
1796 }
1797 }
1798 }
1799 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001800
Andy Stadler043116a2010-11-29 17:43:32 -08001801 /**
1802 * Called any time the device password is updated. Resets all password expiration clocks.
1803 */
Jim Millera4e28d12010-11-08 16:15:47 -08001804 private void updatePasswordExpirationsLocked() {
1805 final int N = mAdminList.size();
1806 if (N > 0) {
1807 for (int i=0; i<N; i++) {
1808 ActiveAdmin admin = mAdminList.get(i);
1809 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001810 long timeout = admin.passwordExpirationTimeout;
1811 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1812 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001813 }
1814 }
1815 saveSettingsLocked();
1816 }
1817 }
1818
Dianne Hackbornd6847842010-01-12 18:14:19 -08001819 public void reportFailedPasswordAttempt() {
1820 mContext.enforceCallingOrSelfPermission(
1821 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001822
Dianne Hackbornd6847842010-01-12 18:14:19 -08001823 synchronized (this) {
1824 long ident = Binder.clearCallingIdentity();
1825 try {
1826 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001827 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001828 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001829 if (max > 0 && mFailedPasswordAttempts >= max) {
1830 wipeDataLocked(0);
1831 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001832 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001833 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001834 } finally {
1835 Binder.restoreCallingIdentity(ident);
1836 }
1837 }
1838 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001839
Dianne Hackbornd6847842010-01-12 18:14:19 -08001840 public void reportSuccessfulPasswordAttempt() {
1841 mContext.enforceCallingOrSelfPermission(
1842 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001843
Dianne Hackbornd6847842010-01-12 18:14:19 -08001844 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001845 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001846 long ident = Binder.clearCallingIdentity();
1847 try {
1848 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001849 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001850 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001851 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001852 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001853 } finally {
1854 Binder.restoreCallingIdentity(ident);
1855 }
1856 }
1857 }
1858 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001859
Oscar Montemayor69238c62010-08-03 10:51:06 -07001860 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1861 String exclusionList) {
1862 synchronized(this) {
1863 if (who == null) {
1864 throw new NullPointerException("ComponentName is null");
1865 }
1866
1867 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1868 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1869
1870 // Scan through active admins and find if anyone has already
1871 // set the global proxy.
Oscar Montemayor69238c62010-08-03 10:51:06 -07001872 Set<ComponentName> compSet = mAdminMap.keySet();
1873 for (ComponentName component : compSet) {
1874 ActiveAdmin ap = mAdminMap.get(component);
1875 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1876 // Another admin already sets the global proxy
1877 // Return it to the caller.
1878 return component;
1879 }
1880 }
1881 if (proxySpec == null) {
1882 admin.specifiesGlobalProxy = false;
1883 admin.globalProxySpec = null;
1884 admin.globalProxyExclusionList = null;
1885 } else {
1886
1887 admin.specifiesGlobalProxy = true;
1888 admin.globalProxySpec = proxySpec;
1889 admin.globalProxyExclusionList = exclusionList;
1890 }
1891
1892 // Reset the global proxy accordingly
1893 // Do this using system permissions, as apps cannot write to secure settings
1894 long origId = Binder.clearCallingIdentity();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001895 resetGlobalProxyLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -07001896 Binder.restoreCallingIdentity(origId);
1897 return null;
1898 }
1899 }
1900
1901 public ComponentName getGlobalProxyAdmin() {
1902 synchronized(this) {
1903 // Scan through active admins and find if anyone has already
1904 // set the global proxy.
1905 final int N = mAdminList.size();
1906 for (int i = 0; i < N; i++) {
1907 ActiveAdmin ap = mAdminList.get(i);
1908 if (ap.specifiesGlobalProxy) {
1909 // Device admin sets the global proxy
1910 // Return it to the caller.
1911 return ap.info.getComponent();
1912 }
1913 }
1914 }
1915 // No device admin sets the global proxy.
1916 return null;
1917 }
1918
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001919 private void resetGlobalProxyLocked() {
Oscar Montemayor69238c62010-08-03 10:51:06 -07001920 final int N = mAdminList.size();
1921 for (int i = 0; i < N; i++) {
1922 ActiveAdmin ap = mAdminList.get(i);
1923 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001924 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001925 return;
1926 }
1927 }
1928 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001929 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001930 }
1931
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001932 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07001933 if (exclusionList == null) {
1934 exclusionList = "";
1935 }
1936 if (proxySpec == null) {
1937 proxySpec = "";
1938 }
1939 // Remove white spaces
1940 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001941 String data[] = proxySpec.split(":");
1942 int proxyPort = 8080;
1943 if (data.length > 1) {
1944 try {
1945 proxyPort = Integer.parseInt(data[1]);
1946 } catch (NumberFormatException e) {}
1947 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001948 exclusionList = exclusionList.trim();
1949 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001950 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1951 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1952 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1953 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001954 }
1955
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001956 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001957 * Set the storage encryption request for a single admin. Returns the new total request
1958 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001959 */
1960 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1961 synchronized (this) {
1962 // Check for permissions
1963 if (who == null) {
1964 throw new NullPointerException("ComponentName is null");
1965 }
1966 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1967 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1968
Andy Stadler22dbfda2011-01-17 12:47:31 -08001969 // Quick exit: If the filesystem does not support encryption, we can exit early.
1970 if (!isEncryptionSupported()) {
1971 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1972 }
1973
1974 // (1) Record the value for the admin so it's sticky
1975 if (ap.encryptionRequested != encrypt) {
1976 ap.encryptionRequested = encrypt;
1977 saveSettingsLocked();
1978 }
1979
1980 // (2) Compute "max" for all admins
1981 boolean newRequested = false;
1982 final int N = mAdminList.size();
1983 for (int i = 0; i < N; i++) {
1984 newRequested |= mAdminList.get(i).encryptionRequested;
1985 }
1986
1987 // Notify OS of new request
1988 setEncryptionRequested(newRequested);
1989
1990 // Return the new global request status
1991 return newRequested
1992 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1993 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001994 }
1995 }
1996
1997 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001998 * Get the current storage encryption request status for a given admin, or aggregate of all
1999 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002000 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08002001 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002002 synchronized (this) {
2003 // Check for permissions if a particular caller is specified
2004 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002005 // When checking for a single caller, status is based on caller's request
Andy Stadlerc994d692011-06-01 15:30:54 -07002006 ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
2007 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002008 }
2009
Andy Stadler22dbfda2011-01-17 12:47:31 -08002010 // If no particular caller is specified, return the aggregate set of requests.
2011 // This is short circuited by returning true on the first hit.
2012 final int N = mAdminList.size();
2013 for (int i = 0; i < N; i++) {
2014 if (mAdminList.get(i).encryptionRequested) {
2015 return true;
2016 }
2017 }
2018 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002019 }
2020 }
2021
Andy Stadler22dbfda2011-01-17 12:47:31 -08002022 /**
2023 * Get the current encryption status of the device.
2024 */
2025 public int getStorageEncryptionStatus() {
2026 return getEncryptionStatus();
2027 }
2028
2029 /**
2030 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2031 */
2032 private boolean isEncryptionSupported() {
2033 // Note, this can be implemented as
2034 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2035 // But is provided as a separate internal method if there's a faster way to do a
2036 // simple check for supported-or-not.
2037 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2038 }
2039
2040 /**
2041 * Hook to low-levels: Reporting the current status of encryption.
2042 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2043 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2044 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2045 */
2046 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002047 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2048 if ("encrypted".equalsIgnoreCase(status)) {
2049 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2050 } else if ("unencrypted".equalsIgnoreCase(status)) {
2051 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2052 } else {
2053 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2054 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002055 }
2056
2057 /**
2058 * Hook to low-levels: If needed, record the new admin setting for encryption.
2059 */
2060 private void setEncryptionRequested(boolean encrypt) {
2061 }
2062
Ben Komalo2447edd2011-05-09 16:05:33 -07002063 /**
2064 * The system property used to share the state of the camera. The native camera service
2065 * is expected to read this property and act accordingly.
2066 */
2067 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2068
2069 /**
2070 * Disables all device cameras according to the specified admin.
2071 */
2072 public void setCameraDisabled(ComponentName who, boolean disabled) {
2073 synchronized (this) {
2074 if (who == null) {
2075 throw new NullPointerException("ComponentName is null");
2076 }
2077 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2078 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2079 if (ap.disableCamera != disabled) {
2080 ap.disableCamera = disabled;
2081 saveSettingsLocked();
2082 }
2083 syncDeviceCapabilitiesLocked();
2084 }
2085 }
2086
2087 /**
2088 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2089 * active admins.
2090 */
2091 public boolean getCameraDisabled(ComponentName who) {
2092 synchronized (this) {
2093 if (who != null) {
2094 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
2095 return (admin != null) ? admin.disableCamera : false;
2096 }
2097
2098 // Determine whether or not the device camera is disabled for any active admins.
2099 final int N = mAdminList.size();
2100 for (int i = 0; i < N; i++) {
2101 ActiveAdmin admin = mAdminList.get(i);
2102 if (admin.disableCamera) {
2103 return true;
2104 }
2105 }
2106 return false;
2107 }
2108 }
2109
Jim Millerb8ec4702012-08-31 17:19:10 -07002110 /**
2111 * Selectively disable keyguard widgets.
2112 */
2113 public void setKeyguardWidgetsDisabled(ComponentName who, int which) {
2114 synchronized (this) {
2115 if (who == null) {
2116 throw new NullPointerException("ComponentName is null");
2117 }
2118 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2119 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS);
2120 if ((ap.disableKeyguardWidgets & which) != which) {
2121 ap.disableKeyguardWidgets |= which;
2122 saveSettingsLocked();
2123 }
2124 syncDeviceCapabilitiesLocked();
2125 }
2126 }
2127
2128 /**
2129 * Gets the disabled state for widgets in keyguard for the given admin,
2130 * or the aggregate of all active admins if who is null.
2131 */
2132 public int getKeyguardWidgetsDisabled(ComponentName who) {
2133 synchronized (this) {
2134 if (who != null) {
2135 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
2136 return (admin != null) ? admin.disableKeyguardWidgets : 0;
2137 }
2138
2139 // Determine whether or not keyguard widgets are disabled for any active admins.
2140 final int N = mAdminList.size();
2141 int which = 0;
2142 for (int i = 0; i < N; i++) {
2143 ActiveAdmin admin = mAdminList.get(i);
2144 which |= admin.disableKeyguardWidgets;
2145 }
2146 return which;
2147 }
2148 }
2149
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002150 @Override
2151 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2152 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2153 != PackageManager.PERMISSION_GRANTED) {
2154
2155 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2156 + Binder.getCallingPid()
2157 + ", uid=" + Binder.getCallingUid());
2158 return;
2159 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002160
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002161 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002162
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002163 synchronized (this) {
2164 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002165
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002166 p.println(" Enabled Device Admins:");
2167 final int N = mAdminList.size();
2168 for (int i=0; i<N; i++) {
2169 ActiveAdmin ap = mAdminList.get(i);
2170 if (ap != null) {
2171 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2172 pw.println(":");
2173 ap.dump(" ", pw);
2174 }
2175 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002176
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002177 pw.println(" ");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002178 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
2179 }
2180 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002181}