blob: 78636f30e8afe5139a7a78e3e21e9aa6fc140a58 [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;
Jim Millera4e28d12010-11-08 16:15:47 -080047import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080048import android.os.IBinder;
49import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070050import android.os.PowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080051import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080052import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080053import android.os.RemoteException;
54import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080055import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080056import android.os.SystemProperties;
Oscar Montemayor69238c62010-08-03 10:51:06 -070057import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080058import android.util.PrintWriterPrinter;
59import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080060import android.util.Slog;
Dianne Hackbornd6847842010-01-12 18:14:19 -080061import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080062import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080063
64import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080065import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080066import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070067import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080068import java.io.FileOutputStream;
69import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080070import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080071import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080072import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080073import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080074import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080075import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070076import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077
78/**
79 * Implementation of the device policy APIs.
80 */
81public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Jim Miller6b857682011-02-16 16:27:41 -080082 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080083
Jim Miller6b857682011-02-16 16:27:41 -080084 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070085
Jim Millera4e28d12010-11-08 16:15:47 -080086 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
87
88 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
89 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
90
91 private static final long MS_PER_DAY = 86400 * 1000;
Jim Millera4e28d12010-11-08 16:15:47 -080092
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080093 final Context mContext;
94 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070095 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080096
Dianne Hackborndf83afa2010-01-20 13:37:26 -080097 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070098
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080099 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800100 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700101 int mActivePasswordUpperCase = 0;
102 int mActivePasswordLowerCase = 0;
103 int mActivePasswordLetters = 0;
104 int mActivePasswordNumeric = 0;
105 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700106 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800107 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700108
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800109 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800110 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700111
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800112 final HashMap<ComponentName, ActiveAdmin> mAdminMap
113 = new HashMap<ComponentName, ActiveAdmin>();
114 final ArrayList<ActiveAdmin> mAdminList
115 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700116
Jim Millera4e28d12010-11-08 16:15:47 -0800117 BroadcastReceiver mReceiver = new BroadcastReceiver() {
118 @Override
119 public void onReceive(Context context, Intent intent) {
120 String action = intent.getAction();
121 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
122 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
123 Slog.v(TAG, "Sending password expiration notifications for action " + action);
124 mHandler.post(new Runnable() {
125 public void run() {
126 handlePasswordExpirationNotification();
127 }
128 });
129 }
130 }
131 };
132
Dianne Hackbornd6847842010-01-12 18:14:19 -0800133 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800134 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700135
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800136 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700137
138 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
139 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
140
141 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
142 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
143
144 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
145 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
146
147 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
148 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
149
150 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
151 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LOWER_CASE;
152
153 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
154 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
155
156 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
157 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
158
159 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
160 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
161
162 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
163 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
164
165 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
166 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
167
168 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
169 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
170
171 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
172 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
173
Andy Stadler22dbfda2011-01-17 12:47:31 -0800174 boolean encryptionRequested = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700175
Oscar Montemayor69238c62010-08-03 10:51:06 -0700176 // TODO: review implementation decisions with frameworks team
177 boolean specifiesGlobalProxy = false;
178 String globalProxySpec = null;
179 String globalProxyExclusionList = null;
180
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800181 ActiveAdmin(DeviceAdminInfo _info) {
182 info = _info;
183 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700184
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800185 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700186
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800187 void writeToXml(XmlSerializer out)
188 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800189 out.startTag(null, "policies");
190 info.writePoliciesToXml(out);
191 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800192 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
193 out.startTag(null, "password-quality");
194 out.attribute(null, "value", Integer.toString(passwordQuality));
195 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700196 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800197 out.startTag(null, "min-password-length");
198 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700199 out.endTag(null, "min-password-length");
200 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700201 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700202 out.startTag(null, "password-history-length");
203 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
204 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800205 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700206 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700207 out.startTag(null, "min-password-uppercase");
208 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
209 out.endTag(null, "min-password-uppercase");
210 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700211 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700212 out.startTag(null, "min-password-lowercase");
213 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
214 out.endTag(null, "min-password-lowercase");
215 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700216 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700217 out.startTag(null, "min-password-letters");
218 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
219 out.endTag(null, "min-password-letters");
220 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700221 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700222 out.startTag(null, "min-password-numeric");
223 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
224 out.endTag(null, "min-password-numeric");
225 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700226 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700227 out.startTag(null, "min-password-symbols");
228 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
229 out.endTag(null, "min-password-symbols");
230 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700231 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700232 out.startTag(null, "min-password-nonletter");
233 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
234 out.endTag(null, "min-password-nonletter");
235 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800236 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700237 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800238 out.startTag(null, "max-time-to-unlock");
239 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
240 out.endTag(null, "max-time-to-unlock");
241 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700242 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800243 out.startTag(null, "max-failed-password-wipe");
244 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
245 out.endTag(null, "max-failed-password-wipe");
246 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700247 if (specifiesGlobalProxy) {
248 out.startTag(null, "specifies-global-proxy");
249 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
250 out.endTag(null, "specifies_global_proxy");
251 if (globalProxySpec != null) {
252 out.startTag(null, "global-proxy-spec");
253 out.attribute(null, "value", globalProxySpec);
254 out.endTag(null, "global-proxy-spec");
255 }
256 if (globalProxyExclusionList != null) {
257 out.startTag(null, "global-proxy-exclusion-list");
258 out.attribute(null, "value", globalProxyExclusionList);
259 out.endTag(null, "global-proxy-exclusion-list");
260 }
261 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700262 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800263 out.startTag(null, "password-expiration-timeout");
264 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
265 out.endTag(null, "password-expiration-timeout");
266 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700267 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800268 out.startTag(null, "password-expiration-date");
269 out.attribute(null, "value", Long.toString(passwordExpirationDate));
270 out.endTag(null, "password-expiration-date");
271 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800272 if (encryptionRequested) {
273 out.startTag(null, "encryption-requested");
274 out.attribute(null, "value", Boolean.toString(encryptionRequested));
275 out.endTag(null, "encryption-requested");
276 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800277 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700278
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800279 void readFromXml(XmlPullParser parser)
280 throws XmlPullParserException, IOException {
281 int outerDepth = parser.getDepth();
282 int type;
283 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
284 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
285 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
286 continue;
287 }
288 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800289 if ("policies".equals(tag)) {
290 info.readPoliciesFromXml(parser);
291 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800292 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800293 parser.getAttributeValue(null, "value"));
294 } else if ("min-password-length".equals(tag)) {
295 minimumPasswordLength = Integer.parseInt(
296 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700297 } else if ("password-history-length".equals(tag)) {
298 passwordHistoryLength = Integer.parseInt(
299 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700300 } else if ("min-password-uppercase".equals(tag)) {
301 minimumPasswordUpperCase = Integer.parseInt(
302 parser.getAttributeValue(null, "value"));
303 } else if ("min-password-lowercase".equals(tag)) {
304 minimumPasswordLowerCase = Integer.parseInt(
305 parser.getAttributeValue(null, "value"));
306 } else if ("min-password-letters".equals(tag)) {
307 minimumPasswordLetters = Integer.parseInt(
308 parser.getAttributeValue(null, "value"));
309 } else if ("min-password-numeric".equals(tag)) {
310 minimumPasswordNumeric = Integer.parseInt(
311 parser.getAttributeValue(null, "value"));
312 } else if ("min-password-symbols".equals(tag)) {
313 minimumPasswordSymbols = Integer.parseInt(
314 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700315 } else if ("min-password-nonletter".equals(tag)) {
316 minimumPasswordNonLetter = Integer.parseInt(
317 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800318 } else if ("max-time-to-unlock".equals(tag)) {
319 maximumTimeToUnlock = Long.parseLong(
320 parser.getAttributeValue(null, "value"));
321 } else if ("max-failed-password-wipe".equals(tag)) {
322 maximumFailedPasswordsForWipe = Integer.parseInt(
323 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700324 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800325 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700326 parser.getAttributeValue(null, "value"));
327 } else if ("global-proxy-spec".equals(tag)) {
328 globalProxySpec =
329 parser.getAttributeValue(null, "value");
330 } else if ("global-proxy-exclusion-list".equals(tag)) {
331 globalProxyExclusionList =
332 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800333 } else if ("password-expiration-timeout".equals(tag)) {
334 passwordExpirationTimeout = Long.parseLong(
335 parser.getAttributeValue(null, "value"));
336 } else if ("password-expiration-date".equals(tag)) {
337 passwordExpirationDate = Long.parseLong(
338 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800339 } else if ("encryption-requested".equals(tag)) {
340 encryptionRequested = Boolean.parseBoolean(
341 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800342 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700343 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800344 }
345 XmlUtils.skipCurrentTag(parser);
346 }
347 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700348
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800349 void dump(String prefix, PrintWriter pw) {
350 pw.print(prefix); pw.print("uid="); pw.println(getUid());
351 pw.print(prefix); pw.println("policies:");
352 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
353 if (pols != null) {
354 for (int i=0; i<pols.size(); i++) {
355 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
356 }
357 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700358 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700359 pw.println(Integer.toHexString(passwordQuality));
360 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800361 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700362 pw.print(prefix); pw.print("passwordHistoryLength=");
363 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700364 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
365 pw.println(minimumPasswordUpperCase);
366 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
367 pw.println(minimumPasswordLowerCase);
368 pw.print(prefix); pw.print("minimumPasswordLetters=");
369 pw.println(minimumPasswordLetters);
370 pw.print(prefix); pw.print("minimumPasswordNumeric=");
371 pw.println(minimumPasswordNumeric);
372 pw.print(prefix); pw.print("minimumPasswordSymbols=");
373 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700374 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
375 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800376 pw.print(prefix); pw.print("maximumTimeToUnlock=");
377 pw.println(maximumTimeToUnlock);
378 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
379 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700380 pw.print(prefix); pw.print("specifiesGlobalProxy=");
381 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800382 pw.print(prefix); pw.print("passwordExpirationTimeout=");
383 pw.println(passwordExpirationTimeout);
384 pw.print(prefix); pw.print("passwordExpirationDate=");
385 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700386 if (globalProxySpec != null) {
387 pw.print(prefix); pw.print("globalProxySpec=");
388 pw.println(globalProxySpec);
389 }
390 if (globalProxyExclusionList != null) {
391 pw.print(prefix); pw.print("globalProxyEclusionList=");
392 pw.println(globalProxyExclusionList);
393 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800394 pw.print(prefix); pw.print("encryptionRequested=");
395 pw.println(encryptionRequested);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800396 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800397 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700398
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800399 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800400 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800401 public void onSomePackagesChanged() {
402 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800403 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800404 for (int i=mAdminList.size()-1; i>=0; i--) {
405 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700406 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800407 if (change == PACKAGE_PERMANENT_CHANGE
408 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700409 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800410 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800411 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800412 mAdminList.remove(i);
413 } else if (isPackageModified(aa.info.getPackageName())) {
414 try {
415 mContext.getPackageManager().getReceiverInfo(
416 aa.info.getComponent(), 0);
417 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700418 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800419 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800420 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800421 mAdminList.remove(i);
422 }
423 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800424 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800425 if (removed) {
426 validatePasswordOwnerLocked();
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700427 saveSettingsLocked();
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800428 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800429 }
430 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800431 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700432
Dianne Hackbornd6847842010-01-12 18:14:19 -0800433 /**
434 * Instantiates the service.
435 */
436 public DevicePolicyManagerService(Context context) {
437 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800438 mMonitor = new MyPackageMonitor();
439 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700440 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
441 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800442 IntentFilter filter = new IntentFilter();
443 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
444 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
445 context.registerReceiver(mReceiver, filter);
446 }
447
Andy Stadler043116a2010-11-29 17:43:32 -0800448 /**
449 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
450 * reminders. Clears alarm if no expirations are configured.
451 */
Jim Millera4e28d12010-11-08 16:15:47 -0800452 protected void setExpirationAlarmCheckLocked(Context context) {
453 final long expiration = getPasswordExpirationLocked(null);
454 final long now = System.currentTimeMillis();
455 final long timeToExpire = expiration - now;
456 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800457 if (expiration == 0) {
458 // No expirations are currently configured: Cancel alarm.
459 alarmTime = 0;
460 } else if (timeToExpire <= 0) {
461 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800462 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800463 } else {
464 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
465 // the expiration time.
466 long alarmInterval = timeToExpire % MS_PER_DAY;
467 if (alarmInterval == 0) {
468 alarmInterval = MS_PER_DAY;
469 }
470 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800471 }
472
Andy Stadler1f35d482010-11-19 15:39:41 -0800473 long token = Binder.clearCallingIdentity();
474 try {
475 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
476 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
477 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
478 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
479 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800480 if (alarmTime != 0) {
481 am.set(AlarmManager.RTC, alarmTime, pi);
482 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800483 } finally {
484 Binder.restoreCallingIdentity(token);
485 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800486 }
487
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800488 private IPowerManager getIPowerManager() {
489 if (mIPowerManager == null) {
490 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
491 mIPowerManager = IPowerManager.Stub.asInterface(b);
492 }
493 return mIPowerManager;
494 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700495
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800496 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800497 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800498 if (admin != null
499 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
500 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
501 return admin;
502 }
503 return null;
504 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700505
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800506 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
507 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800508 final int callingUid = Binder.getCallingUid();
509 if (who != null) {
510 ActiveAdmin admin = mAdminMap.get(who);
511 if (admin == null) {
512 throw new SecurityException("No active admin " + who);
513 }
514 if (admin.getUid() != callingUid) {
515 throw new SecurityException("Admin " + who + " is not owned by uid "
516 + Binder.getCallingUid());
517 }
518 if (!admin.info.usesPolicy(reqPolicy)) {
519 throw new SecurityException("Admin " + admin.info.getComponent()
520 + " did not specify uses-policy for: "
521 + admin.info.getTagForPolicy(reqPolicy));
522 }
523 return admin;
524 } else {
525 final int N = mAdminList.size();
526 for (int i=0; i<N; i++) {
527 ActiveAdmin admin = mAdminList.get(i);
528 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
529 return admin;
530 }
531 }
532 throw new SecurityException("No active admin owned by uid "
533 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800534 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800535 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700536
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800537 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700538 sendAdminCommandLocked(admin, action, null);
539 }
540
541 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800542 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800543 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800544 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
545 intent.putExtra("expiration", admin.passwordExpirationDate);
546 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700547 if (result != null) {
548 mContext.sendOrderedBroadcast(intent, null, result, mHandler,
549 Activity.RESULT_OK, null, null);
550 } else {
551 mContext.sendBroadcast(intent);
552 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800553 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700554
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800555 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800556 final int N = mAdminList.size();
557 if (N > 0) {
558 for (int i=0; i<N; i++) {
559 ActiveAdmin admin = mAdminList.get(i);
560 if (admin.info.usesPolicy(reqPolicy)) {
561 sendAdminCommandLocked(admin, action);
562 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800563 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800564 }
565 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700566
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700567 void removeActiveAdminLocked(final ComponentName adminReceiver) {
568 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800569 if (admin != null) {
570 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700571 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
572 new BroadcastReceiver() {
573 @Override
574 public void onReceive(Context context, Intent intent) {
575 synchronized (this) {
576 boolean doProxyCleanup = admin.info.usesPolicy(
577 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
578 mAdminList.remove(admin);
579 mAdminMap.remove(adminReceiver);
580 validatePasswordOwnerLocked();
581 if (doProxyCleanup) {
582 resetGlobalProxy();
583 }
584 saveSettingsLocked();
585 }
586 }
587 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800588 }
589 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700590
Dianne Hackbornd6847842010-01-12 18:14:19 -0800591 public DeviceAdminInfo findAdmin(ComponentName adminName) {
592 Intent resolveIntent = new Intent();
593 resolveIntent.setComponent(adminName);
594 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
595 resolveIntent, PackageManager.GET_META_DATA);
596 if (infos == null || infos.size() <= 0) {
597 throw new IllegalArgumentException("Unknown admin: " + adminName);
598 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700599
Dianne Hackbornd6847842010-01-12 18:14:19 -0800600 try {
601 return new DeviceAdminInfo(mContext, infos.get(0));
602 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700603 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800604 return null;
605 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700606 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800607 return null;
608 }
609 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700610
Dianne Hackbornd6847842010-01-12 18:14:19 -0800611 private static JournaledFile makeJournaledFile() {
612 final String base = "/data/system/device_policies.xml";
613 return new JournaledFile(new File(base), new File(base + ".tmp"));
614 }
615
616 private void saveSettingsLocked() {
617 JournaledFile journal = makeJournaledFile();
618 FileOutputStream stream = null;
619 try {
620 stream = new FileOutputStream(journal.chooseForWrite(), false);
621 XmlSerializer out = new FastXmlSerializer();
622 out.setOutput(stream, "utf-8");
623 out.startDocument(null, true);
624
625 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700626
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800627 final int N = mAdminList.size();
628 for (int i=0; i<N; i++) {
629 ActiveAdmin ap = mAdminList.get(i);
630 if (ap != null) {
631 out.startTag(null, "admin");
632 out.attribute(null, "name", ap.info.getComponent().flattenToString());
633 ap.writeToXml(out);
634 out.endTag(null, "admin");
635 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800636 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700637
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800638 if (mPasswordOwner >= 0) {
639 out.startTag(null, "password-owner");
640 out.attribute(null, "value", Integer.toString(mPasswordOwner));
641 out.endTag(null, "password-owner");
642 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700643
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800644 if (mFailedPasswordAttempts != 0) {
645 out.startTag(null, "failed-password-attempts");
646 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
647 out.endTag(null, "failed-password-attempts");
648 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700649
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700650 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
651 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
652 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700653 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700654 out.startTag(null, "active-password");
655 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
656 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700657 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
658 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
659 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
660 out.attribute(null, "numeric", Integer
661 .toString(mActivePasswordNumeric));
662 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700663 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700664 out.endTag(null, "active-password");
665 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700666
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700667 out.endTag(null, "policies");
668
Dianne Hackbornd6847842010-01-12 18:14:19 -0800669 out.endDocument();
670 stream.close();
671 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700672 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800673 } catch (IOException e) {
674 try {
675 if (stream != null) {
676 stream.close();
677 }
678 } catch (IOException ex) {
679 // Ignore
680 }
681 journal.rollback();
682 }
683 }
684
Jim Miller284b62e2010-06-08 14:27:42 -0700685 private void sendChangedNotification() {
686 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
687 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
688 mContext.sendBroadcast(intent);
689 }
690
Dianne Hackbornd6847842010-01-12 18:14:19 -0800691 private void loadSettingsLocked() {
692 JournaledFile journal = makeJournaledFile();
693 FileInputStream stream = null;
694 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800695 try {
696 stream = new FileInputStream(file);
697 XmlPullParser parser = Xml.newPullParser();
698 parser.setInput(stream, null);
699
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800700 int type;
701 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
702 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800703 }
704 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800705 if (!"policies".equals(tag)) {
706 throw new XmlPullParserException(
707 "Settings do not start with policies tag: found " + tag);
708 }
709 type = parser.next();
710 int outerDepth = parser.getDepth();
711 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
712 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
713 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
714 continue;
715 }
716 tag = parser.getName();
717 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800718 String name = parser.getAttributeValue(null, "name");
719 try {
720 DeviceAdminInfo dai = findAdmin(
721 ComponentName.unflattenFromString(name));
722 if (dai != null) {
723 ActiveAdmin ap = new ActiveAdmin(dai);
724 ap.readFromXml(parser);
725 mAdminMap.put(ap.info.getComponent(), ap);
726 mAdminList.add(ap);
727 }
728 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700729 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800730 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800731 } else if ("failed-password-attempts".equals(tag)) {
732 mFailedPasswordAttempts = Integer.parseInt(
733 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800734 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800735 } else if ("password-owner".equals(tag)) {
736 mPasswordOwner = Integer.parseInt(
737 parser.getAttributeValue(null, "value"));
738 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700739 } else if ("active-password".equals(tag)) {
740 mActivePasswordQuality = Integer.parseInt(
741 parser.getAttributeValue(null, "quality"));
742 mActivePasswordLength = Integer.parseInt(
743 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700744 mActivePasswordUpperCase = Integer.parseInt(
745 parser.getAttributeValue(null, "uppercase"));
746 mActivePasswordLowerCase = Integer.parseInt(
747 parser.getAttributeValue(null, "lowercase"));
748 mActivePasswordLetters = Integer.parseInt(
749 parser.getAttributeValue(null, "letters"));
750 mActivePasswordNumeric = Integer.parseInt(
751 parser.getAttributeValue(null, "numeric"));
752 mActivePasswordSymbols = Integer.parseInt(
753 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700754 mActivePasswordNonLetter = Integer.parseInt(
755 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700756 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800757 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700758 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800759 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800760 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800761 }
762 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700763 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800764 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700765 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800766 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700767 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700768 } catch (FileNotFoundException e) {
769 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800770 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700771 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800772 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700773 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800774 }
775 try {
776 if (stream != null) {
777 stream.close();
778 }
779 } catch (IOException e) {
780 // Ignore
781 }
782
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700783 // Validate that what we stored for the password quality matches
784 // sufficiently what is currently set. Note that this is only
785 // a sanity check in case the two get out of sync; this should
786 // never normally happen.
787 LockPatternUtils utils = new LockPatternUtils(mContext);
788 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
789 Slog.w(TAG, "Active password quality 0x"
790 + Integer.toHexString(mActivePasswordQuality)
791 + " does not match actual quality 0x"
792 + Integer.toHexString(utils.getActivePasswordQuality()));
793 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
794 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700795 mActivePasswordUpperCase = 0;
796 mActivePasswordLowerCase = 0;
797 mActivePasswordLetters = 0;
798 mActivePasswordNumeric = 0;
799 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700800 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700801 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700802
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800803 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700804
Dianne Hackborn254cb442010-01-27 19:23:59 -0800805 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800806 if (timeMs <= 0) {
807 timeMs = Integer.MAX_VALUE;
808 }
809 try {
810 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
811 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700812 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800813 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800814 }
815
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700816 static void validateQualityConstant(int quality) {
817 switch (quality) {
818 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
819 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
820 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
821 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
822 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700823 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700824 return;
825 }
826 throw new IllegalArgumentException("Invalid quality constant: 0x"
827 + Integer.toHexString(quality));
828 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700829
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800830 void validatePasswordOwnerLocked() {
831 if (mPasswordOwner >= 0) {
832 boolean haveOwner = false;
833 for (int i=mAdminList.size()-1; i>=0; i--) {
834 if (mAdminList.get(i).getUid() == mPasswordOwner) {
835 haveOwner = true;
836 break;
837 }
838 }
839 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700840 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800841 + " no longer active; disabling");
842 mPasswordOwner = -1;
843 }
844 }
845 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700846
Dianne Hackbornd6847842010-01-12 18:14:19 -0800847 public void systemReady() {
848 synchronized (this) {
849 loadSettingsLocked();
850 }
851 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700852
Jim Millera4e28d12010-11-08 16:15:47 -0800853 private void handlePasswordExpirationNotification() {
854 synchronized (this) {
855 final long now = System.currentTimeMillis();
856 final int N = mAdminList.size();
857 if (N <= 0) {
858 return;
859 }
860 for (int i=0; i < N; i++) {
861 ActiveAdmin admin = mAdminList.get(i);
862 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
863 && admin.passwordExpirationTimeout > 0L
864 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800865 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800866 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
867 }
868 }
869 setExpirationAlarmCheckLocked(mContext);
870 }
871 }
872
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800873 /**
874 * @param adminReceiver The admin to add
875 * @param refreshing true = update an active admin, no error
876 */
877 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800878 mContext.enforceCallingOrSelfPermission(
879 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700880
Dianne Hackbornd6847842010-01-12 18:14:19 -0800881 DeviceAdminInfo info = findAdmin(adminReceiver);
882 if (info == null) {
883 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
884 }
885 synchronized (this) {
886 long ident = Binder.clearCallingIdentity();
887 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800888 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800889 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800890 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800891 ActiveAdmin newAdmin = new ActiveAdmin(info);
892 mAdminMap.put(adminReceiver, newAdmin);
893 int replaceIndex = -1;
894 if (refreshing) {
895 final int N = mAdminList.size();
896 for (int i=0; i < N; i++) {
897 ActiveAdmin oldAdmin = mAdminList.get(i);
898 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
899 replaceIndex = i;
900 break;
901 }
902 }
903 }
904 if (replaceIndex == -1) {
905 mAdminList.add(newAdmin);
906 } else {
907 mAdminList.set(replaceIndex, newAdmin);
908 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800909 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800910 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800911 } finally {
912 Binder.restoreCallingIdentity(ident);
913 }
914 }
915 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700916
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800917 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800918 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800919 return getActiveAdminUncheckedLocked(adminReceiver) != null;
920 }
921 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700922
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800923 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
924 synchronized (this) {
925 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
926 if (administrator == null) {
927 throw new SecurityException("No active admin " + adminReceiver);
928 }
929 return administrator.info.usesPolicy(policyId);
930 }
931 }
932
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800933 public List<ComponentName> getActiveAdmins() {
934 synchronized (this) {
935 final int N = mAdminList.size();
936 if (N <= 0) {
937 return null;
938 }
939 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
940 for (int i=0; i<N; i++) {
941 res.add(mAdminList.get(i).info.getComponent());
942 }
943 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800944 }
945 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700946
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800947 public boolean packageHasActiveAdmins(String packageName) {
948 synchronized (this) {
949 final int N = mAdminList.size();
950 for (int i=0; i<N; i++) {
951 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
952 return true;
953 }
954 }
955 return false;
956 }
957 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700958
Dianne Hackbornd6847842010-01-12 18:14:19 -0800959 public void removeActiveAdmin(ComponentName adminReceiver) {
960 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800961 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
962 if (admin == null) {
963 return;
964 }
965 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800966 mContext.enforceCallingOrSelfPermission(
967 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
968 }
969 long ident = Binder.clearCallingIdentity();
970 try {
971 removeActiveAdminLocked(adminReceiver);
972 } finally {
973 Binder.restoreCallingIdentity(ident);
974 }
975 }
976 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700977
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700978 public void setPasswordQuality(ComponentName who, int quality) {
979 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700980
Dianne Hackbornd6847842010-01-12 18:14:19 -0800981 synchronized (this) {
982 if (who == null) {
983 throw new NullPointerException("ComponentName is null");
984 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800985 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
986 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700987 if (ap.passwordQuality != quality) {
988 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800989 saveSettingsLocked();
990 }
991 }
992 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700993
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800994 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800995 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800996 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700997
Dianne Hackborn254cb442010-01-27 19:23:59 -0800998 if (who != null) {
999 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001000 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001001 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001002
Dianne Hackborn254cb442010-01-27 19:23:59 -08001003 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001004 for (int i=0; i<N; i++) {
1005 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001006 if (mode < admin.passwordQuality) {
1007 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001008 }
1009 }
1010 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001011 }
1012 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001013
Dianne Hackborn254cb442010-01-27 19:23:59 -08001014 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001015 synchronized (this) {
1016 if (who == null) {
1017 throw new NullPointerException("ComponentName is null");
1018 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001019 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1020 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001021 if (ap.minimumPasswordLength != length) {
1022 ap.minimumPasswordLength = length;
1023 saveSettingsLocked();
1024 }
1025 }
1026 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001027
Dianne Hackborn254cb442010-01-27 19:23:59 -08001028 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001029 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001030 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001031
Dianne Hackborn254cb442010-01-27 19:23:59 -08001032 if (who != null) {
1033 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1034 return admin != null ? admin.minimumPasswordLength : length;
1035 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001036
Dianne Hackborn254cb442010-01-27 19:23:59 -08001037 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001038 for (int i=0; i<N; i++) {
1039 ActiveAdmin admin = mAdminList.get(i);
1040 if (length < admin.minimumPasswordLength) {
1041 length = admin.minimumPasswordLength;
1042 }
1043 }
1044 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001045 }
1046 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001047
1048 public void setPasswordHistoryLength(ComponentName who, int length) {
1049 synchronized (this) {
1050 if (who == null) {
1051 throw new NullPointerException("ComponentName is null");
1052 }
1053 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1054 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1055 if (ap.passwordHistoryLength != length) {
1056 ap.passwordHistoryLength = length;
1057 saveSettingsLocked();
1058 }
1059 }
1060 }
1061
1062 public int getPasswordHistoryLength(ComponentName who) {
1063 synchronized (this) {
1064 int length = 0;
1065
1066 if (who != null) {
1067 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1068 return admin != null ? admin.passwordHistoryLength : length;
1069 }
1070
1071 final int N = mAdminList.size();
1072 for (int i = 0; i < N; i++) {
1073 ActiveAdmin admin = mAdminList.get(i);
1074 if (length < admin.passwordHistoryLength) {
1075 length = admin.passwordHistoryLength;
1076 }
1077 }
1078 return length;
1079 }
1080 }
1081
Jim Millera4e28d12010-11-08 16:15:47 -08001082 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1083 synchronized (this) {
1084 if (who == null) {
1085 throw new NullPointerException("ComponentName is null");
1086 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001087 if (timeout < 0) {
1088 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001089 }
1090 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1091 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1092 // Calling this API automatically bumps the expiration date
1093 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1094 ap.passwordExpirationDate = expiration;
1095 ap.passwordExpirationTimeout = timeout;
1096 if (timeout > 0L) {
1097 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1098 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1099 .format(new Date(expiration)));
1100 }
1101 saveSettingsLocked();
1102 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1103 }
1104 }
1105
Andy Stadler043116a2010-11-29 17:43:32 -08001106 /**
1107 * Return a single admin's expiration cycle time, or the min of all cycle times.
1108 * Returns 0 if not configured.
1109 */
Jim Millera4e28d12010-11-08 16:15:47 -08001110 public long getPasswordExpirationTimeout(ComponentName who) {
1111 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001112 if (who != null) {
1113 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001114 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001115 }
1116
Andy Stadler043116a2010-11-29 17:43:32 -08001117 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001118 final int N = mAdminList.size();
1119 for (int i = 0; i < N; i++) {
1120 ActiveAdmin admin = mAdminList.get(i);
1121 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1122 && timeout > admin.passwordExpirationTimeout)) {
1123 timeout = admin.passwordExpirationTimeout;
1124 }
1125 }
1126 return timeout;
1127 }
1128 }
1129
Andy Stadler043116a2010-11-29 17:43:32 -08001130 /**
1131 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1132 * Returns 0 if not configured.
1133 */
Jim Millera4e28d12010-11-08 16:15:47 -08001134 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001135 if (who != null) {
1136 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001137 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001138 }
1139
Andy Stadler043116a2010-11-29 17:43:32 -08001140 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001141 final int N = mAdminList.size();
1142 for (int i = 0; i < N; i++) {
1143 ActiveAdmin admin = mAdminList.get(i);
1144 if (timeout == 0L || (admin.passwordExpirationDate != 0
1145 && timeout > admin.passwordExpirationDate)) {
1146 timeout = admin.passwordExpirationDate;
1147 }
1148 }
1149 return timeout;
1150 }
1151
1152 public long getPasswordExpiration(ComponentName who) {
1153 synchronized (this) {
1154 return getPasswordExpirationLocked(who);
1155 }
1156 }
1157
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001158 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1159 synchronized (this) {
1160 if (who == null) {
1161 throw new NullPointerException("ComponentName is null");
1162 }
1163 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1164 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1165 if (ap.minimumPasswordUpperCase != length) {
1166 ap.minimumPasswordUpperCase = length;
1167 saveSettingsLocked();
1168 }
1169 }
1170 }
1171
1172 public int getPasswordMinimumUpperCase(ComponentName who) {
1173 synchronized (this) {
1174 int length = 0;
1175
1176 if (who != null) {
1177 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1178 return admin != null ? admin.minimumPasswordUpperCase : length;
1179 }
1180
1181 final int N = mAdminList.size();
1182 for (int i=0; i<N; i++) {
1183 ActiveAdmin admin = mAdminList.get(i);
1184 if (length < admin.minimumPasswordUpperCase) {
1185 length = admin.minimumPasswordUpperCase;
1186 }
1187 }
1188 return length;
1189 }
1190 }
1191
1192 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1193 synchronized (this) {
1194 if (who == null) {
1195 throw new NullPointerException("ComponentName is null");
1196 }
1197 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1198 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1199 if (ap.minimumPasswordLowerCase != length) {
1200 ap.minimumPasswordLowerCase = length;
1201 saveSettingsLocked();
1202 }
1203 }
1204 }
1205
1206 public int getPasswordMinimumLowerCase(ComponentName who) {
1207 synchronized (this) {
1208 int length = 0;
1209
1210 if (who != null) {
1211 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1212 return admin != null ? admin.minimumPasswordLowerCase : length;
1213 }
1214
1215 final int N = mAdminList.size();
1216 for (int i=0; i<N; i++) {
1217 ActiveAdmin admin = mAdminList.get(i);
1218 if (length < admin.minimumPasswordLowerCase) {
1219 length = admin.minimumPasswordLowerCase;
1220 }
1221 }
1222 return length;
1223 }
1224 }
1225
1226 public void setPasswordMinimumLetters(ComponentName who, int length) {
1227 synchronized (this) {
1228 if (who == null) {
1229 throw new NullPointerException("ComponentName is null");
1230 }
1231 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1232 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1233 if (ap.minimumPasswordLetters != length) {
1234 ap.minimumPasswordLetters = length;
1235 saveSettingsLocked();
1236 }
1237 }
1238 }
1239
1240 public int getPasswordMinimumLetters(ComponentName who) {
1241 synchronized (this) {
1242 int length = 0;
1243
1244 if (who != null) {
1245 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1246 return admin != null ? admin.minimumPasswordLetters : length;
1247 }
1248
1249 final int N = mAdminList.size();
1250 for (int i=0; i<N; i++) {
1251 ActiveAdmin admin = mAdminList.get(i);
1252 if (length < admin.minimumPasswordLetters) {
1253 length = admin.minimumPasswordLetters;
1254 }
1255 }
1256 return length;
1257 }
1258 }
1259
1260 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1261 synchronized (this) {
1262 if (who == null) {
1263 throw new NullPointerException("ComponentName is null");
1264 }
1265 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1266 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1267 if (ap.minimumPasswordNumeric != length) {
1268 ap.minimumPasswordNumeric = length;
1269 saveSettingsLocked();
1270 }
1271 }
1272 }
1273
1274 public int getPasswordMinimumNumeric(ComponentName who) {
1275 synchronized (this) {
1276 int length = 0;
1277
1278 if (who != null) {
1279 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1280 return admin != null ? admin.minimumPasswordNumeric : length;
1281 }
1282
1283 final int N = mAdminList.size();
1284 for (int i = 0; i < N; i++) {
1285 ActiveAdmin admin = mAdminList.get(i);
1286 if (length < admin.minimumPasswordNumeric) {
1287 length = admin.minimumPasswordNumeric;
1288 }
1289 }
1290 return length;
1291 }
1292 }
1293
1294 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1295 synchronized (this) {
1296 if (who == null) {
1297 throw new NullPointerException("ComponentName is null");
1298 }
1299 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1300 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1301 if (ap.minimumPasswordSymbols != length) {
1302 ap.minimumPasswordSymbols = length;
1303 saveSettingsLocked();
1304 }
1305 }
1306 }
1307
1308 public int getPasswordMinimumSymbols(ComponentName who) {
1309 synchronized (this) {
1310 int length = 0;
1311
1312 if (who != null) {
1313 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1314 return admin != null ? admin.minimumPasswordSymbols : length;
1315 }
1316
1317 final int N = mAdminList.size();
1318 for (int i=0; i<N; i++) {
1319 ActiveAdmin admin = mAdminList.get(i);
1320 if (length < admin.minimumPasswordSymbols) {
1321 length = admin.minimumPasswordSymbols;
1322 }
1323 }
1324 return length;
1325 }
1326 }
1327
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001328 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1329 synchronized (this) {
1330 if (who == null) {
1331 throw new NullPointerException("ComponentName is null");
1332 }
1333 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1334 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1335 if (ap.minimumPasswordNonLetter != length) {
1336 ap.minimumPasswordNonLetter = length;
1337 saveSettingsLocked();
1338 }
1339 }
1340 }
1341
1342 public int getPasswordMinimumNonLetter(ComponentName who) {
1343 synchronized (this) {
1344 int length = 0;
1345
1346 if (who != null) {
1347 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1348 return admin != null ? admin.minimumPasswordNonLetter : length;
1349 }
1350
1351 final int N = mAdminList.size();
1352 for (int i=0; i<N; i++) {
1353 ActiveAdmin admin = mAdminList.get(i);
1354 if (length < admin.minimumPasswordNonLetter) {
1355 length = admin.minimumPasswordNonLetter;
1356 }
1357 }
1358 return length;
1359 }
1360 }
1361
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001362 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001363 synchronized (this) {
1364 // This API can only be called by an active device admin,
1365 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001366 getActiveAdminForCallerLocked(null,
1367 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001368 if (mActivePasswordQuality < getPasswordQuality(null)
1369 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1370 return false;
1371 }
1372 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1373 return true;
1374 }
1375 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1376 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1377 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1378 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001379 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1380 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001381 }
1382 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001383
Dianne Hackbornd6847842010-01-12 18:14:19 -08001384 public int getCurrentFailedPasswordAttempts() {
1385 synchronized (this) {
1386 // This API can only be called by an active device admin,
1387 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001388 getActiveAdminForCallerLocked(null,
1389 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001390 return mFailedPasswordAttempts;
1391 }
1392 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001393
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001394 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1395 synchronized (this) {
1396 // This API can only be called by an active device admin,
1397 // so try to retrieve it to check that the caller is one.
1398 getActiveAdminForCallerLocked(who,
1399 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1400 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1401 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1402 if (ap.maximumFailedPasswordsForWipe != num) {
1403 ap.maximumFailedPasswordsForWipe = num;
1404 saveSettingsLocked();
1405 }
1406 }
1407 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001408
Dianne Hackborn254cb442010-01-27 19:23:59 -08001409 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001410 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001411 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001412
Dianne Hackborn254cb442010-01-27 19:23:59 -08001413 if (who != null) {
1414 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1415 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1416 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001417
Dianne Hackborn254cb442010-01-27 19:23:59 -08001418 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001419 for (int i=0; i<N; i++) {
1420 ActiveAdmin admin = mAdminList.get(i);
1421 if (count == 0) {
1422 count = admin.maximumFailedPasswordsForWipe;
1423 } else if (admin.maximumFailedPasswordsForWipe != 0
1424 && count > admin.maximumFailedPasswordsForWipe) {
1425 count = admin.maximumFailedPasswordsForWipe;
1426 }
1427 }
1428 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001429 }
1430 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001431
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001432 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001433 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001434 synchronized (this) {
1435 // This API can only be called by an active device admin,
1436 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001437 getActiveAdminForCallerLocked(null,
1438 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001439 quality = getPasswordQuality(null);
1440 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001441 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001442 if (realQuality < quality
1443 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001444 Slog.w(TAG, "resetPassword: password quality 0x"
1445 + Integer.toHexString(quality)
1446 + " does not meet required quality 0x"
1447 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001448 return false;
1449 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001450 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001451 }
1452 int length = getPasswordMinimumLength(null);
1453 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001454 Slog.w(TAG, "resetPassword: password length " + password.length()
1455 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001456 return false;
1457 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001458 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1459 int letters = 0;
1460 int uppercase = 0;
1461 int lowercase = 0;
1462 int numbers = 0;
1463 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001464 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001465 for (int i = 0; i < password.length(); i++) {
1466 char c = password.charAt(i);
1467 if (c >= 'A' && c <= 'Z') {
1468 letters++;
1469 uppercase++;
1470 } else if (c >= 'a' && c <= 'z') {
1471 letters++;
1472 lowercase++;
1473 } else if (c >= '0' && c <= '9') {
1474 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001475 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001476 } else {
1477 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001478 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001479 }
1480 }
1481 int neededLetters = getPasswordMinimumLetters(null);
1482 if(letters < neededLetters) {
1483 Slog.w(TAG, "resetPassword: number of letters " + letters
1484 + " does not meet required number of letters " + neededLetters);
1485 return false;
1486 }
1487 int neededNumbers = getPasswordMinimumNumeric(null);
1488 if (numbers < neededNumbers) {
1489 Slog
1490 .w(TAG, "resetPassword: number of numerical digits " + numbers
1491 + " does not meet required number of numerical digits "
1492 + neededNumbers);
1493 return false;
1494 }
1495 int neededLowerCase = getPasswordMinimumLowerCase(null);
1496 if (lowercase < neededLowerCase) {
1497 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1498 + " does not meet required number of lowercase letters "
1499 + neededLowerCase);
1500 return false;
1501 }
1502 int neededUpperCase = getPasswordMinimumUpperCase(null);
1503 if (uppercase < neededUpperCase) {
1504 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1505 + " does not meet required number of uppercase letters "
1506 + neededUpperCase);
1507 return false;
1508 }
1509 int neededSymbols = getPasswordMinimumSymbols(null);
1510 if (symbols < neededSymbols) {
1511 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1512 + " does not meet required number of special symbols " + neededSymbols);
1513 return false;
1514 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001515 int neededNonLetter = getPasswordMinimumNonLetter(null);
1516 if (nonletter < neededNonLetter) {
1517 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1518 + " does not meet required number of non-letter characters "
1519 + neededNonLetter);
1520 return false;
1521 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001522 }
1523
1524 LockPatternUtils utils = new LockPatternUtils(mContext);
1525 if(utils.checkPasswordHistory(password)) {
1526 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1527 + getPasswordHistoryLength(null) + " passwords");
1528 return false;
1529 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001530 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001531
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001532 int callingUid = Binder.getCallingUid();
1533 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001534 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001535 return false;
1536 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001537
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001538 // Don't do this with the lock held, because it is going to call
1539 // back in to the service.
1540 long ident = Binder.clearCallingIdentity();
1541 try {
1542 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001543 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001544 synchronized (this) {
1545 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1546 != 0 ? callingUid : -1;
1547 if (mPasswordOwner != newOwner) {
1548 mPasswordOwner = newOwner;
1549 saveSettingsLocked();
1550 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001551 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001552 } finally {
1553 Binder.restoreCallingIdentity(ident);
1554 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001555
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001556 return true;
1557 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001558
Dianne Hackbornd6847842010-01-12 18:14:19 -08001559 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1560 synchronized (this) {
1561 if (who == null) {
1562 throw new NullPointerException("ComponentName is null");
1563 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001564 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001565 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001566 if (ap.maximumTimeToUnlock != timeMs) {
1567 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001568
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001569 long ident = Binder.clearCallingIdentity();
1570 try {
1571 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001572
Dianne Hackborn254cb442010-01-27 19:23:59 -08001573 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001574 if (timeMs <= 0) {
1575 timeMs = Integer.MAX_VALUE;
1576 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001577
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001578 try {
1579 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1580 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001581 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001582 }
1583 } finally {
1584 Binder.restoreCallingIdentity(ident);
1585 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001586 }
1587 }
1588 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001589
Dianne Hackborn254cb442010-01-27 19:23:59 -08001590 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001591 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001592 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001593
Dianne Hackborn254cb442010-01-27 19:23:59 -08001594 if (who != null) {
1595 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1596 return admin != null ? admin.maximumTimeToUnlock : time;
1597 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001598
Dianne Hackborn254cb442010-01-27 19:23:59 -08001599 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001600 for (int i=0; i<N; i++) {
1601 ActiveAdmin admin = mAdminList.get(i);
1602 if (time == 0) {
1603 time = admin.maximumTimeToUnlock;
1604 } else if (admin.maximumTimeToUnlock != 0
1605 && time > admin.maximumTimeToUnlock) {
1606 time = admin.maximumTimeToUnlock;
1607 }
1608 }
1609 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001610 }
1611 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001612
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001613 public void lockNow() {
1614 synchronized (this) {
1615 // This API can only be called by an active device admin,
1616 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001617 getActiveAdminForCallerLocked(null,
1618 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001619 long ident = Binder.clearCallingIdentity();
1620 try {
1621 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1622 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1623 } catch (RemoteException e) {
1624 } finally {
1625 Binder.restoreCallingIdentity(ident);
1626 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001627 }
1628 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001629
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001630 void wipeDataLocked(int flags) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001631 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
1632 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1633 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1634 mWakeLock.acquire(10000);
1635 mContext.startService(intent);
1636 } else {
1637 try {
1638 RecoverySystem.rebootWipeUserData(mContext);
1639 } catch (IOException e) {
1640 Slog.w(TAG, "Failed requesting data wipe", e);
1641 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001642 }
1643 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001644
Dianne Hackbornd6847842010-01-12 18:14:19 -08001645 public void wipeData(int flags) {
1646 synchronized (this) {
1647 // This API can only be called by an active device admin,
1648 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001649 getActiveAdminForCallerLocked(null,
1650 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001651 long ident = Binder.clearCallingIdentity();
1652 try {
1653 wipeDataLocked(flags);
1654 } finally {
1655 Binder.restoreCallingIdentity(ident);
1656 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001657 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001658 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001659
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001660 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1661 mContext.enforceCallingOrSelfPermission(
1662 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001663
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001664 synchronized (this) {
1665 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1666 if (admin == null) {
1667 try {
1668 result.sendResult(null);
1669 } catch (RemoteException e) {
1670 }
1671 return;
1672 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001673 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001674 intent.setComponent(admin.info.getComponent());
1675 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1676 @Override
1677 public void onReceive(Context context, Intent intent) {
1678 try {
1679 result.sendResult(getResultExtras(false));
1680 } catch (RemoteException e) {
1681 }
1682 }
1683 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001684 }
1685 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001686
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001687 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001688 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001689 mContext.enforceCallingOrSelfPermission(
1690 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001691
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001692 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001693
Dianne Hackbornd6847842010-01-12 18:14:19 -08001694 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001695 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001696 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1697 || mActivePasswordUpperCase != uppercase
1698 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001699 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001700 long ident = Binder.clearCallingIdentity();
1701 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001702 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001703 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001704 mActivePasswordLetters = letters;
1705 mActivePasswordLowerCase = lowercase;
1706 mActivePasswordUpperCase = uppercase;
1707 mActivePasswordNumeric = numbers;
1708 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001709 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001710 mFailedPasswordAttempts = 0;
1711 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001712 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001713 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001714 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001715 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001716 } finally {
1717 Binder.restoreCallingIdentity(ident);
1718 }
1719 }
1720 }
1721 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001722
Andy Stadler043116a2010-11-29 17:43:32 -08001723 /**
1724 * Called any time the device password is updated. Resets all password expiration clocks.
1725 */
Jim Millera4e28d12010-11-08 16:15:47 -08001726 private void updatePasswordExpirationsLocked() {
1727 final int N = mAdminList.size();
1728 if (N > 0) {
1729 for (int i=0; i<N; i++) {
1730 ActiveAdmin admin = mAdminList.get(i);
1731 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001732 long timeout = admin.passwordExpirationTimeout;
1733 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1734 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001735 }
1736 }
1737 saveSettingsLocked();
1738 }
1739 }
1740
Dianne Hackbornd6847842010-01-12 18:14:19 -08001741 public void reportFailedPasswordAttempt() {
1742 mContext.enforceCallingOrSelfPermission(
1743 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001744
Dianne Hackbornd6847842010-01-12 18:14:19 -08001745 synchronized (this) {
1746 long ident = Binder.clearCallingIdentity();
1747 try {
1748 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001749 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001750 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001751 if (max > 0 && mFailedPasswordAttempts >= max) {
1752 wipeDataLocked(0);
1753 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001754 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001755 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001756 } finally {
1757 Binder.restoreCallingIdentity(ident);
1758 }
1759 }
1760 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001761
Dianne Hackbornd6847842010-01-12 18:14:19 -08001762 public void reportSuccessfulPasswordAttempt() {
1763 mContext.enforceCallingOrSelfPermission(
1764 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001765
Dianne Hackbornd6847842010-01-12 18:14:19 -08001766 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001767 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001768 long ident = Binder.clearCallingIdentity();
1769 try {
1770 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001771 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001772 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001773 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001774 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001775 } finally {
1776 Binder.restoreCallingIdentity(ident);
1777 }
1778 }
1779 }
1780 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001781
Oscar Montemayor69238c62010-08-03 10:51:06 -07001782 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1783 String exclusionList) {
1784 synchronized(this) {
1785 if (who == null) {
1786 throw new NullPointerException("ComponentName is null");
1787 }
1788
1789 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1790 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1791
1792 // Scan through active admins and find if anyone has already
1793 // set the global proxy.
Oscar Montemayor69238c62010-08-03 10:51:06 -07001794 Set<ComponentName> compSet = mAdminMap.keySet();
1795 for (ComponentName component : compSet) {
1796 ActiveAdmin ap = mAdminMap.get(component);
1797 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1798 // Another admin already sets the global proxy
1799 // Return it to the caller.
1800 return component;
1801 }
1802 }
1803 if (proxySpec == null) {
1804 admin.specifiesGlobalProxy = false;
1805 admin.globalProxySpec = null;
1806 admin.globalProxyExclusionList = null;
1807 } else {
1808
1809 admin.specifiesGlobalProxy = true;
1810 admin.globalProxySpec = proxySpec;
1811 admin.globalProxyExclusionList = exclusionList;
1812 }
1813
1814 // Reset the global proxy accordingly
1815 // Do this using system permissions, as apps cannot write to secure settings
1816 long origId = Binder.clearCallingIdentity();
1817 resetGlobalProxy();
1818 Binder.restoreCallingIdentity(origId);
1819 return null;
1820 }
1821 }
1822
1823 public ComponentName getGlobalProxyAdmin() {
1824 synchronized(this) {
1825 // Scan through active admins and find if anyone has already
1826 // set the global proxy.
1827 final int N = mAdminList.size();
1828 for (int i = 0; i < N; i++) {
1829 ActiveAdmin ap = mAdminList.get(i);
1830 if (ap.specifiesGlobalProxy) {
1831 // Device admin sets the global proxy
1832 // Return it to the caller.
1833 return ap.info.getComponent();
1834 }
1835 }
1836 }
1837 // No device admin sets the global proxy.
1838 return null;
1839 }
1840
1841 private void resetGlobalProxy() {
1842 final int N = mAdminList.size();
1843 for (int i = 0; i < N; i++) {
1844 ActiveAdmin ap = mAdminList.get(i);
1845 if (ap.specifiesGlobalProxy) {
1846 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1847 return;
1848 }
1849 }
1850 // No device admins defining global proxies - reset global proxy settings to none
1851 saveGlobalProxy(null, null);
1852 }
1853
1854 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1855 if (exclusionList == null) {
1856 exclusionList = "";
1857 }
1858 if (proxySpec == null) {
1859 proxySpec = "";
1860 }
1861 // Remove white spaces
1862 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001863 String data[] = proxySpec.split(":");
1864 int proxyPort = 8080;
1865 if (data.length > 1) {
1866 try {
1867 proxyPort = Integer.parseInt(data[1]);
1868 } catch (NumberFormatException e) {}
1869 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001870 exclusionList = exclusionList.trim();
1871 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001872 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1873 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1874 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1875 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001876 }
1877
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001878 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001879 * Set the storage encryption request for a single admin. Returns the new total request
1880 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001881 */
1882 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1883 synchronized (this) {
1884 // Check for permissions
1885 if (who == null) {
1886 throw new NullPointerException("ComponentName is null");
1887 }
1888 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1889 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1890
Andy Stadler22dbfda2011-01-17 12:47:31 -08001891 // Quick exit: If the filesystem does not support encryption, we can exit early.
1892 if (!isEncryptionSupported()) {
1893 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1894 }
1895
1896 // (1) Record the value for the admin so it's sticky
1897 if (ap.encryptionRequested != encrypt) {
1898 ap.encryptionRequested = encrypt;
1899 saveSettingsLocked();
1900 }
1901
1902 // (2) Compute "max" for all admins
1903 boolean newRequested = false;
1904 final int N = mAdminList.size();
1905 for (int i = 0; i < N; i++) {
1906 newRequested |= mAdminList.get(i).encryptionRequested;
1907 }
1908
1909 // Notify OS of new request
1910 setEncryptionRequested(newRequested);
1911
1912 // Return the new global request status
1913 return newRequested
1914 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1915 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001916 }
1917 }
1918
1919 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001920 * Get the current storage encryption request status for a given admin, or aggregate of all
1921 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001922 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08001923 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001924 synchronized (this) {
1925 // Check for permissions if a particular caller is specified
1926 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08001927 // When checking for a single caller, status is based on caller's request
Andy Stadlerc994d692011-06-01 15:30:54 -07001928 ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
1929 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001930 }
1931
Andy Stadler22dbfda2011-01-17 12:47:31 -08001932 // If no particular caller is specified, return the aggregate set of requests.
1933 // This is short circuited by returning true on the first hit.
1934 final int N = mAdminList.size();
1935 for (int i = 0; i < N; i++) {
1936 if (mAdminList.get(i).encryptionRequested) {
1937 return true;
1938 }
1939 }
1940 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001941 }
1942 }
1943
Andy Stadler22dbfda2011-01-17 12:47:31 -08001944 /**
1945 * Get the current encryption status of the device.
1946 */
1947 public int getStorageEncryptionStatus() {
1948 return getEncryptionStatus();
1949 }
1950
1951 /**
1952 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
1953 */
1954 private boolean isEncryptionSupported() {
1955 // Note, this can be implemented as
1956 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1957 // But is provided as a separate internal method if there's a faster way to do a
1958 // simple check for supported-or-not.
1959 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1960 }
1961
1962 /**
1963 * Hook to low-levels: Reporting the current status of encryption.
1964 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
1965 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
1966 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
1967 */
1968 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08001969 String status = SystemProperties.get("ro.crypto.state", "unsupported");
1970 if ("encrypted".equalsIgnoreCase(status)) {
1971 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
1972 } else if ("unencrypted".equalsIgnoreCase(status)) {
1973 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
1974 } else {
1975 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1976 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08001977 }
1978
1979 /**
1980 * Hook to low-levels: If needed, record the new admin setting for encryption.
1981 */
1982 private void setEncryptionRequested(boolean encrypt) {
1983 }
1984
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001985 @Override
1986 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1987 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1988 != PackageManager.PERMISSION_GRANTED) {
1989
1990 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1991 + Binder.getCallingPid()
1992 + ", uid=" + Binder.getCallingUid());
1993 return;
1994 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001995
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001996 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001997
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001998 synchronized (this) {
1999 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002000
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002001 p.println(" Enabled Device Admins:");
2002 final int N = mAdminList.size();
2003 for (int i=0; i<N; i++) {
2004 ActiveAdmin ap = mAdminList.get(i);
2005 if (ap != null) {
2006 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2007 pw.println(":");
2008 ap.dump(" ", pw);
2009 }
2010 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002011
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002012 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002013 pw.print(" mActivePasswordQuality=0x");
2014 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002015 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002016 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
2017 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
2018 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
2019 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
2020 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07002021 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002022 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
2023 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
2024 }
2025 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002026}