blob: 8a9e351800468d07ad84516747a7d0689551068a [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;
Oscar Montemayor69238c62010-08-03 10:51:06 -070056import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080057import android.util.PrintWriterPrinter;
58import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080059import android.util.Slog;
Dianne Hackbornd6847842010-01-12 18:14:19 -080060import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080061import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080062
63import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080064import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080065import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070066import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080067import java.io.FileOutputStream;
68import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080069import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080070import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080071import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080072import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080073import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080074import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070075import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080076
77/**
78 * Implementation of the device policy APIs.
79 */
80public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Jim Millera4e28d12010-11-08 16:15:47 -080081 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
82
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080083 static final String TAG = "DevicePolicyManagerService";
Konstantin Lopyrev32558232010-05-20 16:18:05 -070084
Jim Millera4e28d12010-11-08 16:15:47 -080085 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
86
87 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
88 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
89
90 private static final long MS_PER_DAY = 86400 * 1000;
Jim Millera4e28d12010-11-08 16:15:47 -080091
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080092 final Context mContext;
93 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070094 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080095
Dianne Hackborndf83afa2010-01-20 13:37:26 -080096 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070097
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080098 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080099 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700100 int mActivePasswordUpperCase = 0;
101 int mActivePasswordLowerCase = 0;
102 int mActivePasswordLetters = 0;
103 int mActivePasswordNumeric = 0;
104 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700105 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800106 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700107
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800108 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800109 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700110
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800111 final HashMap<ComponentName, ActiveAdmin> mAdminMap
112 = new HashMap<ComponentName, ActiveAdmin>();
113 final ArrayList<ActiveAdmin> mAdminList
114 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700115
Jim Millera4e28d12010-11-08 16:15:47 -0800116 BroadcastReceiver mReceiver = new BroadcastReceiver() {
117 @Override
118 public void onReceive(Context context, Intent intent) {
119 String action = intent.getAction();
120 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
121 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
122 Slog.v(TAG, "Sending password expiration notifications for action " + action);
123 mHandler.post(new Runnable() {
124 public void run() {
125 handlePasswordExpirationNotification();
126 }
127 });
128 }
129 }
130 };
131
Dianne Hackbornd6847842010-01-12 18:14:19 -0800132 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800133 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700134
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800135 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800136 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700137 int passwordHistoryLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700138 int minimumPasswordUpperCase = 0;
139 int minimumPasswordLowerCase = 0;
140 int minimumPasswordLetters = 1;
141 int minimumPasswordNumeric = 1;
142 int minimumPasswordSymbols = 1;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700143 int minimumPasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800144 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800145 int maximumFailedPasswordsForWipe = 0;
Jim Millera4e28d12010-11-08 16:15:47 -0800146 long passwordExpirationTimeout = 0L;
147 long passwordExpirationDate = 0L;
Andy Stadler22dbfda2011-01-17 12:47:31 -0800148 boolean encryptionRequested = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700149
Oscar Montemayor69238c62010-08-03 10:51:06 -0700150 // TODO: review implementation decisions with frameworks team
151 boolean specifiesGlobalProxy = false;
152 String globalProxySpec = null;
153 String globalProxyExclusionList = null;
154
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800155 ActiveAdmin(DeviceAdminInfo _info) {
156 info = _info;
157 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700158
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800159 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700160
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800161 void writeToXml(XmlSerializer out)
162 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800163 out.startTag(null, "policies");
164 info.writePoliciesToXml(out);
165 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800166 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
167 out.startTag(null, "password-quality");
168 out.attribute(null, "value", Integer.toString(passwordQuality));
169 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800170 if (minimumPasswordLength > 0) {
171 out.startTag(null, "min-password-length");
172 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700173 out.endTag(null, "min-password-length");
174 }
175 if(passwordHistoryLength > 0) {
176 out.startTag(null, "password-history-length");
177 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
178 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800179 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700180 if (minimumPasswordUpperCase > 0) {
181 out.startTag(null, "min-password-uppercase");
182 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
183 out.endTag(null, "min-password-uppercase");
184 }
185 if (minimumPasswordLowerCase > 0) {
186 out.startTag(null, "min-password-lowercase");
187 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
188 out.endTag(null, "min-password-lowercase");
189 }
190 if (minimumPasswordLetters > 0) {
191 out.startTag(null, "min-password-letters");
192 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
193 out.endTag(null, "min-password-letters");
194 }
195 if (minimumPasswordNumeric > 0) {
196 out.startTag(null, "min-password-numeric");
197 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
198 out.endTag(null, "min-password-numeric");
199 }
200 if (minimumPasswordSymbols > 0) {
201 out.startTag(null, "min-password-symbols");
202 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
203 out.endTag(null, "min-password-symbols");
204 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700205 if (minimumPasswordNonLetter > 0) {
206 out.startTag(null, "min-password-nonletter");
207 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
208 out.endTag(null, "min-password-nonletter");
209 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800210 }
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700211 if (maximumTimeToUnlock != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800212 out.startTag(null, "max-time-to-unlock");
213 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
214 out.endTag(null, "max-time-to-unlock");
215 }
216 if (maximumFailedPasswordsForWipe != 0) {
217 out.startTag(null, "max-failed-password-wipe");
218 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
219 out.endTag(null, "max-failed-password-wipe");
220 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700221 if (specifiesGlobalProxy) {
222 out.startTag(null, "specifies-global-proxy");
223 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
224 out.endTag(null, "specifies_global_proxy");
225 if (globalProxySpec != null) {
226 out.startTag(null, "global-proxy-spec");
227 out.attribute(null, "value", globalProxySpec);
228 out.endTag(null, "global-proxy-spec");
229 }
230 if (globalProxyExclusionList != null) {
231 out.startTag(null, "global-proxy-exclusion-list");
232 out.attribute(null, "value", globalProxyExclusionList);
233 out.endTag(null, "global-proxy-exclusion-list");
234 }
235 }
Jim Millera4e28d12010-11-08 16:15:47 -0800236 if (passwordExpirationTimeout != 0L) {
237 out.startTag(null, "password-expiration-timeout");
238 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
239 out.endTag(null, "password-expiration-timeout");
240 }
241 if (passwordExpirationDate != 0L) {
242 out.startTag(null, "password-expiration-date");
243 out.attribute(null, "value", Long.toString(passwordExpirationDate));
244 out.endTag(null, "password-expiration-date");
245 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800246 if (encryptionRequested) {
247 out.startTag(null, "encryption-requested");
248 out.attribute(null, "value", Boolean.toString(encryptionRequested));
249 out.endTag(null, "encryption-requested");
250 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800251 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700252
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800253 void readFromXml(XmlPullParser parser)
254 throws XmlPullParserException, IOException {
255 int outerDepth = parser.getDepth();
256 int type;
257 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
258 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
259 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
260 continue;
261 }
262 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800263 if ("policies".equals(tag)) {
264 info.readPoliciesFromXml(parser);
265 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800266 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800267 parser.getAttributeValue(null, "value"));
268 } else if ("min-password-length".equals(tag)) {
269 minimumPasswordLength = Integer.parseInt(
270 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700271 } else if ("password-history-length".equals(tag)) {
272 passwordHistoryLength = Integer.parseInt(
273 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700274 } else if ("min-password-uppercase".equals(tag)) {
275 minimumPasswordUpperCase = Integer.parseInt(
276 parser.getAttributeValue(null, "value"));
277 } else if ("min-password-lowercase".equals(tag)) {
278 minimumPasswordLowerCase = Integer.parseInt(
279 parser.getAttributeValue(null, "value"));
280 } else if ("min-password-letters".equals(tag)) {
281 minimumPasswordLetters = Integer.parseInt(
282 parser.getAttributeValue(null, "value"));
283 } else if ("min-password-numeric".equals(tag)) {
284 minimumPasswordNumeric = Integer.parseInt(
285 parser.getAttributeValue(null, "value"));
286 } else if ("min-password-symbols".equals(tag)) {
287 minimumPasswordSymbols = Integer.parseInt(
288 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700289 } else if ("min-password-nonletter".equals(tag)) {
290 minimumPasswordNonLetter = Integer.parseInt(
291 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800292 } else if ("max-time-to-unlock".equals(tag)) {
293 maximumTimeToUnlock = Long.parseLong(
294 parser.getAttributeValue(null, "value"));
295 } else if ("max-failed-password-wipe".equals(tag)) {
296 maximumFailedPasswordsForWipe = Integer.parseInt(
297 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700298 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800299 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700300 parser.getAttributeValue(null, "value"));
301 } else if ("global-proxy-spec".equals(tag)) {
302 globalProxySpec =
303 parser.getAttributeValue(null, "value");
304 } else if ("global-proxy-exclusion-list".equals(tag)) {
305 globalProxyExclusionList =
306 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800307 } else if ("password-expiration-timeout".equals(tag)) {
308 passwordExpirationTimeout = Long.parseLong(
309 parser.getAttributeValue(null, "value"));
310 } else if ("password-expiration-date".equals(tag)) {
311 passwordExpirationDate = Long.parseLong(
312 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800313 } else if ("encryption-requested".equals(tag)) {
314 encryptionRequested = Boolean.parseBoolean(
315 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800316 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700317 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800318 }
319 XmlUtils.skipCurrentTag(parser);
320 }
321 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700322
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800323 void dump(String prefix, PrintWriter pw) {
324 pw.print(prefix); pw.print("uid="); pw.println(getUid());
325 pw.print(prefix); pw.println("policies:");
326 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
327 if (pols != null) {
328 for (int i=0; i<pols.size(); i++) {
329 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
330 }
331 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700332 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700333 pw.println(Integer.toHexString(passwordQuality));
334 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800335 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700336 pw.print(prefix); pw.print("passwordHistoryLength=");
337 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700338 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
339 pw.println(minimumPasswordUpperCase);
340 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
341 pw.println(minimumPasswordLowerCase);
342 pw.print(prefix); pw.print("minimumPasswordLetters=");
343 pw.println(minimumPasswordLetters);
344 pw.print(prefix); pw.print("minimumPasswordNumeric=");
345 pw.println(minimumPasswordNumeric);
346 pw.print(prefix); pw.print("minimumPasswordSymbols=");
347 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700348 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
349 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800350 pw.print(prefix); pw.print("maximumTimeToUnlock=");
351 pw.println(maximumTimeToUnlock);
352 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
353 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700354 pw.print(prefix); pw.print("specifiesGlobalProxy=");
355 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800356 pw.print(prefix); pw.print("passwordExpirationTimeout=");
357 pw.println(passwordExpirationTimeout);
358 pw.print(prefix); pw.print("passwordExpirationDate=");
359 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700360 if (globalProxySpec != null) {
361 pw.print(prefix); pw.print("globalProxySpec=");
362 pw.println(globalProxySpec);
363 }
364 if (globalProxyExclusionList != null) {
365 pw.print(prefix); pw.print("globalProxyEclusionList=");
366 pw.println(globalProxyExclusionList);
367 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800368 pw.print(prefix); pw.print("encryptionRequested=");
369 pw.println(encryptionRequested);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800370 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800371 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700372
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800373 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800374 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800375 public void onSomePackagesChanged() {
376 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800377 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800378 for (int i=mAdminList.size()-1; i>=0; i--) {
379 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700380 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800381 if (change == PACKAGE_PERMANENT_CHANGE
382 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700383 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800384 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800385 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800386 mAdminList.remove(i);
387 } else if (isPackageModified(aa.info.getPackageName())) {
388 try {
389 mContext.getPackageManager().getReceiverInfo(
390 aa.info.getComponent(), 0);
391 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700392 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800393 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800394 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800395 mAdminList.remove(i);
396 }
397 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800398 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800399 if (removed) {
400 validatePasswordOwnerLocked();
401 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800402 }
403 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800404 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700405
Dianne Hackbornd6847842010-01-12 18:14:19 -0800406 /**
407 * Instantiates the service.
408 */
409 public DevicePolicyManagerService(Context context) {
410 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800411 mMonitor = new MyPackageMonitor();
412 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700413 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
414 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800415 IntentFilter filter = new IntentFilter();
416 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
417 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
418 context.registerReceiver(mReceiver, filter);
419 }
420
Andy Stadler043116a2010-11-29 17:43:32 -0800421 /**
422 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
423 * reminders. Clears alarm if no expirations are configured.
424 */
Jim Millera4e28d12010-11-08 16:15:47 -0800425 protected void setExpirationAlarmCheckLocked(Context context) {
426 final long expiration = getPasswordExpirationLocked(null);
427 final long now = System.currentTimeMillis();
428 final long timeToExpire = expiration - now;
429 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800430 if (expiration == 0) {
431 // No expirations are currently configured: Cancel alarm.
432 alarmTime = 0;
433 } else if (timeToExpire <= 0) {
434 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800435 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800436 } else {
437 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
438 // the expiration time.
439 long alarmInterval = timeToExpire % MS_PER_DAY;
440 if (alarmInterval == 0) {
441 alarmInterval = MS_PER_DAY;
442 }
443 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800444 }
445
Andy Stadler1f35d482010-11-19 15:39:41 -0800446 long token = Binder.clearCallingIdentity();
447 try {
448 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
449 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
450 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
451 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
452 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800453 if (alarmTime != 0) {
454 am.set(AlarmManager.RTC, alarmTime, pi);
455 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800456 } finally {
457 Binder.restoreCallingIdentity(token);
458 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800459 }
460
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800461 private IPowerManager getIPowerManager() {
462 if (mIPowerManager == null) {
463 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
464 mIPowerManager = IPowerManager.Stub.asInterface(b);
465 }
466 return mIPowerManager;
467 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700468
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800469 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800470 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800471 if (admin != null
472 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
473 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
474 return admin;
475 }
476 return null;
477 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700478
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800479 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
480 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800481 final int callingUid = Binder.getCallingUid();
482 if (who != null) {
483 ActiveAdmin admin = mAdminMap.get(who);
484 if (admin == null) {
485 throw new SecurityException("No active admin " + who);
486 }
487 if (admin.getUid() != callingUid) {
488 throw new SecurityException("Admin " + who + " is not owned by uid "
489 + Binder.getCallingUid());
490 }
491 if (!admin.info.usesPolicy(reqPolicy)) {
492 throw new SecurityException("Admin " + admin.info.getComponent()
493 + " did not specify uses-policy for: "
494 + admin.info.getTagForPolicy(reqPolicy));
495 }
496 return admin;
497 } else {
498 final int N = mAdminList.size();
499 for (int i=0; i<N; i++) {
500 ActiveAdmin admin = mAdminList.get(i);
501 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
502 return admin;
503 }
504 }
505 throw new SecurityException("No active admin owned by uid "
506 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800507 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800508 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700509
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800510 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800511 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800512 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800513 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
514 intent.putExtra("expiration", admin.passwordExpirationDate);
515 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800516 mContext.sendBroadcast(intent);
517 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700518
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800519 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800520 final int N = mAdminList.size();
521 if (N > 0) {
522 for (int i=0; i<N; i++) {
523 ActiveAdmin admin = mAdminList.get(i);
524 if (admin.info.usesPolicy(reqPolicy)) {
525 sendAdminCommandLocked(admin, action);
526 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800527 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800528 }
529 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700530
Dianne Hackbornd6847842010-01-12 18:14:19 -0800531 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800532 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
533 if (admin != null) {
Oscar Montemayor69238c62010-08-03 10:51:06 -0700534 boolean doProxyCleanup =
535 admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800536 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800537 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800538 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800539 mAdminList.remove(admin);
540 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800541 validatePasswordOwnerLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -0700542 if (doProxyCleanup) {
543 resetGlobalProxy();
544 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800545 }
546 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700547
Dianne Hackbornd6847842010-01-12 18:14:19 -0800548 public DeviceAdminInfo findAdmin(ComponentName adminName) {
549 Intent resolveIntent = new Intent();
550 resolveIntent.setComponent(adminName);
551 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
552 resolveIntent, PackageManager.GET_META_DATA);
553 if (infos == null || infos.size() <= 0) {
554 throw new IllegalArgumentException("Unknown admin: " + adminName);
555 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700556
Dianne Hackbornd6847842010-01-12 18:14:19 -0800557 try {
558 return new DeviceAdminInfo(mContext, infos.get(0));
559 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700560 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800561 return null;
562 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700563 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800564 return null;
565 }
566 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700567
Dianne Hackbornd6847842010-01-12 18:14:19 -0800568 private static JournaledFile makeJournaledFile() {
569 final String base = "/data/system/device_policies.xml";
570 return new JournaledFile(new File(base), new File(base + ".tmp"));
571 }
572
573 private void saveSettingsLocked() {
574 JournaledFile journal = makeJournaledFile();
575 FileOutputStream stream = null;
576 try {
577 stream = new FileOutputStream(journal.chooseForWrite(), false);
578 XmlSerializer out = new FastXmlSerializer();
579 out.setOutput(stream, "utf-8");
580 out.startDocument(null, true);
581
582 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700583
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800584 final int N = mAdminList.size();
585 for (int i=0; i<N; i++) {
586 ActiveAdmin ap = mAdminList.get(i);
587 if (ap != null) {
588 out.startTag(null, "admin");
589 out.attribute(null, "name", ap.info.getComponent().flattenToString());
590 ap.writeToXml(out);
591 out.endTag(null, "admin");
592 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800593 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700594
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800595 if (mPasswordOwner >= 0) {
596 out.startTag(null, "password-owner");
597 out.attribute(null, "value", Integer.toString(mPasswordOwner));
598 out.endTag(null, "password-owner");
599 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700600
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800601 if (mFailedPasswordAttempts != 0) {
602 out.startTag(null, "failed-password-attempts");
603 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
604 out.endTag(null, "failed-password-attempts");
605 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700606
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700607 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
608 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
609 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700610 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700611 out.startTag(null, "active-password");
612 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
613 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700614 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
615 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
616 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
617 out.attribute(null, "numeric", Integer
618 .toString(mActivePasswordNumeric));
619 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700620 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700621 out.endTag(null, "active-password");
622 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700623
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700624 out.endTag(null, "policies");
625
Dianne Hackbornd6847842010-01-12 18:14:19 -0800626 out.endDocument();
627 stream.close();
628 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700629 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800630 } catch (IOException e) {
631 try {
632 if (stream != null) {
633 stream.close();
634 }
635 } catch (IOException ex) {
636 // Ignore
637 }
638 journal.rollback();
639 }
640 }
641
Jim Miller284b62e2010-06-08 14:27:42 -0700642 private void sendChangedNotification() {
643 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
644 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
645 mContext.sendBroadcast(intent);
646 }
647
Dianne Hackbornd6847842010-01-12 18:14:19 -0800648 private void loadSettingsLocked() {
649 JournaledFile journal = makeJournaledFile();
650 FileInputStream stream = null;
651 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800652 try {
653 stream = new FileInputStream(file);
654 XmlPullParser parser = Xml.newPullParser();
655 parser.setInput(stream, null);
656
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800657 int type;
658 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
659 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800660 }
661 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800662 if (!"policies".equals(tag)) {
663 throw new XmlPullParserException(
664 "Settings do not start with policies tag: found " + tag);
665 }
666 type = parser.next();
667 int outerDepth = parser.getDepth();
668 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
669 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
670 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
671 continue;
672 }
673 tag = parser.getName();
674 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800675 String name = parser.getAttributeValue(null, "name");
676 try {
677 DeviceAdminInfo dai = findAdmin(
678 ComponentName.unflattenFromString(name));
679 if (dai != null) {
680 ActiveAdmin ap = new ActiveAdmin(dai);
681 ap.readFromXml(parser);
682 mAdminMap.put(ap.info.getComponent(), ap);
683 mAdminList.add(ap);
684 }
685 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700686 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800687 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800688 } else if ("failed-password-attempts".equals(tag)) {
689 mFailedPasswordAttempts = Integer.parseInt(
690 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800691 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800692 } else if ("password-owner".equals(tag)) {
693 mPasswordOwner = Integer.parseInt(
694 parser.getAttributeValue(null, "value"));
695 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700696 } else if ("active-password".equals(tag)) {
697 mActivePasswordQuality = Integer.parseInt(
698 parser.getAttributeValue(null, "quality"));
699 mActivePasswordLength = Integer.parseInt(
700 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700701 mActivePasswordUpperCase = Integer.parseInt(
702 parser.getAttributeValue(null, "uppercase"));
703 mActivePasswordLowerCase = Integer.parseInt(
704 parser.getAttributeValue(null, "lowercase"));
705 mActivePasswordLetters = Integer.parseInt(
706 parser.getAttributeValue(null, "letters"));
707 mActivePasswordNumeric = Integer.parseInt(
708 parser.getAttributeValue(null, "numeric"));
709 mActivePasswordSymbols = Integer.parseInt(
710 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700711 mActivePasswordNonLetter = Integer.parseInt(
712 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700713 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800714 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700715 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800716 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800717 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800718 }
719 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700720 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800721 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700722 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800723 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700724 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700725 } catch (FileNotFoundException e) {
726 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800727 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700728 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800729 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700730 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800731 }
732 try {
733 if (stream != null) {
734 stream.close();
735 }
736 } catch (IOException e) {
737 // Ignore
738 }
739
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700740 // Validate that what we stored for the password quality matches
741 // sufficiently what is currently set. Note that this is only
742 // a sanity check in case the two get out of sync; this should
743 // never normally happen.
744 LockPatternUtils utils = new LockPatternUtils(mContext);
745 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
746 Slog.w(TAG, "Active password quality 0x"
747 + Integer.toHexString(mActivePasswordQuality)
748 + " does not match actual quality 0x"
749 + Integer.toHexString(utils.getActivePasswordQuality()));
750 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
751 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700752 mActivePasswordUpperCase = 0;
753 mActivePasswordLowerCase = 0;
754 mActivePasswordLetters = 0;
755 mActivePasswordNumeric = 0;
756 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700757 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700758 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700759
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800760 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700761
Dianne Hackborn254cb442010-01-27 19:23:59 -0800762 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800763 if (timeMs <= 0) {
764 timeMs = Integer.MAX_VALUE;
765 }
766 try {
767 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
768 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700769 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800770 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800771 }
772
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700773 static void validateQualityConstant(int quality) {
774 switch (quality) {
775 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
776 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
777 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
778 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
779 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700780 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700781 return;
782 }
783 throw new IllegalArgumentException("Invalid quality constant: 0x"
784 + Integer.toHexString(quality));
785 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700786
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800787 void validatePasswordOwnerLocked() {
788 if (mPasswordOwner >= 0) {
789 boolean haveOwner = false;
790 for (int i=mAdminList.size()-1; i>=0; i--) {
791 if (mAdminList.get(i).getUid() == mPasswordOwner) {
792 haveOwner = true;
793 break;
794 }
795 }
796 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700797 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800798 + " no longer active; disabling");
799 mPasswordOwner = -1;
800 }
801 }
802 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700803
Dianne Hackbornd6847842010-01-12 18:14:19 -0800804 public void systemReady() {
805 synchronized (this) {
806 loadSettingsLocked();
807 }
808 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700809
Jim Millera4e28d12010-11-08 16:15:47 -0800810 private void handlePasswordExpirationNotification() {
811 synchronized (this) {
812 final long now = System.currentTimeMillis();
813 final int N = mAdminList.size();
814 if (N <= 0) {
815 return;
816 }
817 for (int i=0; i < N; i++) {
818 ActiveAdmin admin = mAdminList.get(i);
819 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
820 && admin.passwordExpirationTimeout > 0L
821 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800822 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800823 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
824 }
825 }
826 setExpirationAlarmCheckLocked(mContext);
827 }
828 }
829
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800830 /**
831 * @param adminReceiver The admin to add
832 * @param refreshing true = update an active admin, no error
833 */
834 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800835 mContext.enforceCallingOrSelfPermission(
836 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700837
Dianne Hackbornd6847842010-01-12 18:14:19 -0800838 DeviceAdminInfo info = findAdmin(adminReceiver);
839 if (info == null) {
840 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
841 }
842 synchronized (this) {
843 long ident = Binder.clearCallingIdentity();
844 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800845 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800846 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800847 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800848 ActiveAdmin newAdmin = new ActiveAdmin(info);
849 mAdminMap.put(adminReceiver, newAdmin);
850 int replaceIndex = -1;
851 if (refreshing) {
852 final int N = mAdminList.size();
853 for (int i=0; i < N; i++) {
854 ActiveAdmin oldAdmin = mAdminList.get(i);
855 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
856 replaceIndex = i;
857 break;
858 }
859 }
860 }
861 if (replaceIndex == -1) {
862 mAdminList.add(newAdmin);
863 } else {
864 mAdminList.set(replaceIndex, newAdmin);
865 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800866 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800867 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800868 } finally {
869 Binder.restoreCallingIdentity(ident);
870 }
871 }
872 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700873
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800874 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800875 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800876 return getActiveAdminUncheckedLocked(adminReceiver) != null;
877 }
878 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700879
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800880 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
881 synchronized (this) {
882 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
883 if (administrator == null) {
884 throw new SecurityException("No active admin " + adminReceiver);
885 }
886 return administrator.info.usesPolicy(policyId);
887 }
888 }
889
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800890 public List<ComponentName> getActiveAdmins() {
891 synchronized (this) {
892 final int N = mAdminList.size();
893 if (N <= 0) {
894 return null;
895 }
896 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
897 for (int i=0; i<N; i++) {
898 res.add(mAdminList.get(i).info.getComponent());
899 }
900 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800901 }
902 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700903
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800904 public boolean packageHasActiveAdmins(String packageName) {
905 synchronized (this) {
906 final int N = mAdminList.size();
907 for (int i=0; i<N; i++) {
908 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
909 return true;
910 }
911 }
912 return false;
913 }
914 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700915
Dianne Hackbornd6847842010-01-12 18:14:19 -0800916 public void removeActiveAdmin(ComponentName adminReceiver) {
917 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800918 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
919 if (admin == null) {
920 return;
921 }
922 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800923 mContext.enforceCallingOrSelfPermission(
924 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
925 }
926 long ident = Binder.clearCallingIdentity();
927 try {
928 removeActiveAdminLocked(adminReceiver);
929 } finally {
930 Binder.restoreCallingIdentity(ident);
931 }
932 }
933 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700934
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700935 public void setPasswordQuality(ComponentName who, int quality) {
936 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700937
Dianne Hackbornd6847842010-01-12 18:14:19 -0800938 synchronized (this) {
939 if (who == null) {
940 throw new NullPointerException("ComponentName is null");
941 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800942 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
943 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700944 if (ap.passwordQuality != quality) {
945 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800946 saveSettingsLocked();
947 }
948 }
949 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700950
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800951 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800952 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800953 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700954
Dianne Hackborn254cb442010-01-27 19:23:59 -0800955 if (who != null) {
956 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800957 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800958 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700959
Dianne Hackborn254cb442010-01-27 19:23:59 -0800960 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800961 for (int i=0; i<N; i++) {
962 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800963 if (mode < admin.passwordQuality) {
964 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800965 }
966 }
967 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800968 }
969 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700970
Dianne Hackborn254cb442010-01-27 19:23:59 -0800971 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800972 synchronized (this) {
973 if (who == null) {
974 throw new NullPointerException("ComponentName is null");
975 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800976 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
977 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800978 if (ap.minimumPasswordLength != length) {
979 ap.minimumPasswordLength = length;
980 saveSettingsLocked();
981 }
982 }
983 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700984
Dianne Hackborn254cb442010-01-27 19:23:59 -0800985 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800986 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800987 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700988
Dianne Hackborn254cb442010-01-27 19:23:59 -0800989 if (who != null) {
990 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
991 return admin != null ? admin.minimumPasswordLength : length;
992 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700993
Dianne Hackborn254cb442010-01-27 19:23:59 -0800994 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800995 for (int i=0; i<N; i++) {
996 ActiveAdmin admin = mAdminList.get(i);
997 if (length < admin.minimumPasswordLength) {
998 length = admin.minimumPasswordLength;
999 }
1000 }
1001 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001002 }
1003 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001004
1005 public void setPasswordHistoryLength(ComponentName who, int length) {
1006 synchronized (this) {
1007 if (who == null) {
1008 throw new NullPointerException("ComponentName is null");
1009 }
1010 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1011 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1012 if (ap.passwordHistoryLength != length) {
1013 ap.passwordHistoryLength = length;
1014 saveSettingsLocked();
1015 }
1016 }
1017 }
1018
1019 public int getPasswordHistoryLength(ComponentName who) {
1020 synchronized (this) {
1021 int length = 0;
1022
1023 if (who != null) {
1024 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1025 return admin != null ? admin.passwordHistoryLength : length;
1026 }
1027
1028 final int N = mAdminList.size();
1029 for (int i = 0; i < N; i++) {
1030 ActiveAdmin admin = mAdminList.get(i);
1031 if (length < admin.passwordHistoryLength) {
1032 length = admin.passwordHistoryLength;
1033 }
1034 }
1035 return length;
1036 }
1037 }
1038
Jim Millera4e28d12010-11-08 16:15:47 -08001039 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1040 synchronized (this) {
1041 if (who == null) {
1042 throw new NullPointerException("ComponentName is null");
1043 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001044 if (timeout < 0) {
1045 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001046 }
1047 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1048 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1049 // Calling this API automatically bumps the expiration date
1050 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1051 ap.passwordExpirationDate = expiration;
1052 ap.passwordExpirationTimeout = timeout;
1053 if (timeout > 0L) {
1054 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1055 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1056 .format(new Date(expiration)));
1057 }
1058 saveSettingsLocked();
1059 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1060 }
1061 }
1062
Andy Stadler043116a2010-11-29 17:43:32 -08001063 /**
1064 * Return a single admin's expiration cycle time, or the min of all cycle times.
1065 * Returns 0 if not configured.
1066 */
Jim Millera4e28d12010-11-08 16:15:47 -08001067 public long getPasswordExpirationTimeout(ComponentName who) {
1068 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001069 if (who != null) {
1070 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001071 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001072 }
1073
Andy Stadler043116a2010-11-29 17:43:32 -08001074 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001075 final int N = mAdminList.size();
1076 for (int i = 0; i < N; i++) {
1077 ActiveAdmin admin = mAdminList.get(i);
1078 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1079 && timeout > admin.passwordExpirationTimeout)) {
1080 timeout = admin.passwordExpirationTimeout;
1081 }
1082 }
1083 return timeout;
1084 }
1085 }
1086
Andy Stadler043116a2010-11-29 17:43:32 -08001087 /**
1088 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1089 * Returns 0 if not configured.
1090 */
Jim Millera4e28d12010-11-08 16:15:47 -08001091 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001092 if (who != null) {
1093 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001094 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001095 }
1096
Andy Stadler043116a2010-11-29 17:43:32 -08001097 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001098 final int N = mAdminList.size();
1099 for (int i = 0; i < N; i++) {
1100 ActiveAdmin admin = mAdminList.get(i);
1101 if (timeout == 0L || (admin.passwordExpirationDate != 0
1102 && timeout > admin.passwordExpirationDate)) {
1103 timeout = admin.passwordExpirationDate;
1104 }
1105 }
1106 return timeout;
1107 }
1108
1109 public long getPasswordExpiration(ComponentName who) {
1110 synchronized (this) {
1111 return getPasswordExpirationLocked(who);
1112 }
1113 }
1114
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001115 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1116 synchronized (this) {
1117 if (who == null) {
1118 throw new NullPointerException("ComponentName is null");
1119 }
1120 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1121 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1122 if (ap.minimumPasswordUpperCase != length) {
1123 ap.minimumPasswordUpperCase = length;
1124 saveSettingsLocked();
1125 }
1126 }
1127 }
1128
1129 public int getPasswordMinimumUpperCase(ComponentName who) {
1130 synchronized (this) {
1131 int length = 0;
1132
1133 if (who != null) {
1134 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1135 return admin != null ? admin.minimumPasswordUpperCase : length;
1136 }
1137
1138 final int N = mAdminList.size();
1139 for (int i=0; i<N; i++) {
1140 ActiveAdmin admin = mAdminList.get(i);
1141 if (length < admin.minimumPasswordUpperCase) {
1142 length = admin.minimumPasswordUpperCase;
1143 }
1144 }
1145 return length;
1146 }
1147 }
1148
1149 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1150 synchronized (this) {
1151 if (who == null) {
1152 throw new NullPointerException("ComponentName is null");
1153 }
1154 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1155 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1156 if (ap.minimumPasswordLowerCase != length) {
1157 ap.minimumPasswordLowerCase = length;
1158 saveSettingsLocked();
1159 }
1160 }
1161 }
1162
1163 public int getPasswordMinimumLowerCase(ComponentName who) {
1164 synchronized (this) {
1165 int length = 0;
1166
1167 if (who != null) {
1168 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1169 return admin != null ? admin.minimumPasswordLowerCase : length;
1170 }
1171
1172 final int N = mAdminList.size();
1173 for (int i=0; i<N; i++) {
1174 ActiveAdmin admin = mAdminList.get(i);
1175 if (length < admin.minimumPasswordLowerCase) {
1176 length = admin.minimumPasswordLowerCase;
1177 }
1178 }
1179 return length;
1180 }
1181 }
1182
1183 public void setPasswordMinimumLetters(ComponentName who, int length) {
1184 synchronized (this) {
1185 if (who == null) {
1186 throw new NullPointerException("ComponentName is null");
1187 }
1188 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1189 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1190 if (ap.minimumPasswordLetters != length) {
1191 ap.minimumPasswordLetters = length;
1192 saveSettingsLocked();
1193 }
1194 }
1195 }
1196
1197 public int getPasswordMinimumLetters(ComponentName who) {
1198 synchronized (this) {
1199 int length = 0;
1200
1201 if (who != null) {
1202 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1203 return admin != null ? admin.minimumPasswordLetters : length;
1204 }
1205
1206 final int N = mAdminList.size();
1207 for (int i=0; i<N; i++) {
1208 ActiveAdmin admin = mAdminList.get(i);
1209 if (length < admin.minimumPasswordLetters) {
1210 length = admin.minimumPasswordLetters;
1211 }
1212 }
1213 return length;
1214 }
1215 }
1216
1217 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1218 synchronized (this) {
1219 if (who == null) {
1220 throw new NullPointerException("ComponentName is null");
1221 }
1222 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1223 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1224 if (ap.minimumPasswordNumeric != length) {
1225 ap.minimumPasswordNumeric = length;
1226 saveSettingsLocked();
1227 }
1228 }
1229 }
1230
1231 public int getPasswordMinimumNumeric(ComponentName who) {
1232 synchronized (this) {
1233 int length = 0;
1234
1235 if (who != null) {
1236 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1237 return admin != null ? admin.minimumPasswordNumeric : length;
1238 }
1239
1240 final int N = mAdminList.size();
1241 for (int i = 0; i < N; i++) {
1242 ActiveAdmin admin = mAdminList.get(i);
1243 if (length < admin.minimumPasswordNumeric) {
1244 length = admin.minimumPasswordNumeric;
1245 }
1246 }
1247 return length;
1248 }
1249 }
1250
1251 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1252 synchronized (this) {
1253 if (who == null) {
1254 throw new NullPointerException("ComponentName is null");
1255 }
1256 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1257 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1258 if (ap.minimumPasswordSymbols != length) {
1259 ap.minimumPasswordSymbols = length;
1260 saveSettingsLocked();
1261 }
1262 }
1263 }
1264
1265 public int getPasswordMinimumSymbols(ComponentName who) {
1266 synchronized (this) {
1267 int length = 0;
1268
1269 if (who != null) {
1270 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1271 return admin != null ? admin.minimumPasswordSymbols : length;
1272 }
1273
1274 final int N = mAdminList.size();
1275 for (int i=0; i<N; i++) {
1276 ActiveAdmin admin = mAdminList.get(i);
1277 if (length < admin.minimumPasswordSymbols) {
1278 length = admin.minimumPasswordSymbols;
1279 }
1280 }
1281 return length;
1282 }
1283 }
1284
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001285 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1286 synchronized (this) {
1287 if (who == null) {
1288 throw new NullPointerException("ComponentName is null");
1289 }
1290 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1291 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1292 if (ap.minimumPasswordNonLetter != length) {
1293 ap.minimumPasswordNonLetter = length;
1294 saveSettingsLocked();
1295 }
1296 }
1297 }
1298
1299 public int getPasswordMinimumNonLetter(ComponentName who) {
1300 synchronized (this) {
1301 int length = 0;
1302
1303 if (who != null) {
1304 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1305 return admin != null ? admin.minimumPasswordNonLetter : length;
1306 }
1307
1308 final int N = mAdminList.size();
1309 for (int i=0; i<N; i++) {
1310 ActiveAdmin admin = mAdminList.get(i);
1311 if (length < admin.minimumPasswordNonLetter) {
1312 length = admin.minimumPasswordNonLetter;
1313 }
1314 }
1315 return length;
1316 }
1317 }
1318
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001319 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001320 synchronized (this) {
1321 // This API can only be called by an active device admin,
1322 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001323 getActiveAdminForCallerLocked(null,
1324 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001325 if (mActivePasswordQuality < getPasswordQuality(null)
1326 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1327 return false;
1328 }
1329 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1330 return true;
1331 }
1332 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1333 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1334 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1335 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001336 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1337 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001338 }
1339 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001340
Dianne Hackbornd6847842010-01-12 18:14:19 -08001341 public int getCurrentFailedPasswordAttempts() {
1342 synchronized (this) {
1343 // This API can only be called by an active device admin,
1344 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001345 getActiveAdminForCallerLocked(null,
1346 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001347 return mFailedPasswordAttempts;
1348 }
1349 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001350
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001351 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1352 synchronized (this) {
1353 // This API can only be called by an active device admin,
1354 // so try to retrieve it to check that the caller is one.
1355 getActiveAdminForCallerLocked(who,
1356 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1357 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1358 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1359 if (ap.maximumFailedPasswordsForWipe != num) {
1360 ap.maximumFailedPasswordsForWipe = num;
1361 saveSettingsLocked();
1362 }
1363 }
1364 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001365
Dianne Hackborn254cb442010-01-27 19:23:59 -08001366 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001367 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001368 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001369
Dianne Hackborn254cb442010-01-27 19:23:59 -08001370 if (who != null) {
1371 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1372 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1373 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001374
Dianne Hackborn254cb442010-01-27 19:23:59 -08001375 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001376 for (int i=0; i<N; i++) {
1377 ActiveAdmin admin = mAdminList.get(i);
1378 if (count == 0) {
1379 count = admin.maximumFailedPasswordsForWipe;
1380 } else if (admin.maximumFailedPasswordsForWipe != 0
1381 && count > admin.maximumFailedPasswordsForWipe) {
1382 count = admin.maximumFailedPasswordsForWipe;
1383 }
1384 }
1385 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001386 }
1387 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001388
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001389 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001390 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001391 synchronized (this) {
1392 // This API can only be called by an active device admin,
1393 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001394 getActiveAdminForCallerLocked(null,
1395 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001396 quality = getPasswordQuality(null);
1397 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001398 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001399 if (realQuality < quality
1400 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001401 Slog.w(TAG, "resetPassword: password quality 0x"
1402 + Integer.toHexString(quality)
1403 + " does not meet required quality 0x"
1404 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001405 return false;
1406 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001407 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001408 }
1409 int length = getPasswordMinimumLength(null);
1410 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001411 Slog.w(TAG, "resetPassword: password length " + password.length()
1412 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001413 return false;
1414 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001415 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1416 int letters = 0;
1417 int uppercase = 0;
1418 int lowercase = 0;
1419 int numbers = 0;
1420 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001421 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001422 for (int i = 0; i < password.length(); i++) {
1423 char c = password.charAt(i);
1424 if (c >= 'A' && c <= 'Z') {
1425 letters++;
1426 uppercase++;
1427 } else if (c >= 'a' && c <= 'z') {
1428 letters++;
1429 lowercase++;
1430 } else if (c >= '0' && c <= '9') {
1431 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001432 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001433 } else {
1434 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001435 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001436 }
1437 }
1438 int neededLetters = getPasswordMinimumLetters(null);
1439 if(letters < neededLetters) {
1440 Slog.w(TAG, "resetPassword: number of letters " + letters
1441 + " does not meet required number of letters " + neededLetters);
1442 return false;
1443 }
1444 int neededNumbers = getPasswordMinimumNumeric(null);
1445 if (numbers < neededNumbers) {
1446 Slog
1447 .w(TAG, "resetPassword: number of numerical digits " + numbers
1448 + " does not meet required number of numerical digits "
1449 + neededNumbers);
1450 return false;
1451 }
1452 int neededLowerCase = getPasswordMinimumLowerCase(null);
1453 if (lowercase < neededLowerCase) {
1454 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1455 + " does not meet required number of lowercase letters "
1456 + neededLowerCase);
1457 return false;
1458 }
1459 int neededUpperCase = getPasswordMinimumUpperCase(null);
1460 if (uppercase < neededUpperCase) {
1461 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1462 + " does not meet required number of uppercase letters "
1463 + neededUpperCase);
1464 return false;
1465 }
1466 int neededSymbols = getPasswordMinimumSymbols(null);
1467 if (symbols < neededSymbols) {
1468 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1469 + " does not meet required number of special symbols " + neededSymbols);
1470 return false;
1471 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001472 int neededNonLetter = getPasswordMinimumNonLetter(null);
1473 if (nonletter < neededNonLetter) {
1474 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1475 + " does not meet required number of non-letter characters "
1476 + neededNonLetter);
1477 return false;
1478 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001479 }
1480
1481 LockPatternUtils utils = new LockPatternUtils(mContext);
1482 if(utils.checkPasswordHistory(password)) {
1483 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1484 + getPasswordHistoryLength(null) + " passwords");
1485 return false;
1486 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001487 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001488
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001489 int callingUid = Binder.getCallingUid();
1490 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001491 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001492 return false;
1493 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001494
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001495 // Don't do this with the lock held, because it is going to call
1496 // back in to the service.
1497 long ident = Binder.clearCallingIdentity();
1498 try {
1499 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001500 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001501 synchronized (this) {
1502 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1503 != 0 ? callingUid : -1;
1504 if (mPasswordOwner != newOwner) {
1505 mPasswordOwner = newOwner;
1506 saveSettingsLocked();
1507 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001508 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001509 } finally {
1510 Binder.restoreCallingIdentity(ident);
1511 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001512
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001513 return true;
1514 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001515
Dianne Hackbornd6847842010-01-12 18:14:19 -08001516 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1517 synchronized (this) {
1518 if (who == null) {
1519 throw new NullPointerException("ComponentName is null");
1520 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001521 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001522 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001523 if (ap.maximumTimeToUnlock != timeMs) {
1524 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001525
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001526 long ident = Binder.clearCallingIdentity();
1527 try {
1528 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001529
Dianne Hackborn254cb442010-01-27 19:23:59 -08001530 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001531 if (timeMs <= 0) {
1532 timeMs = Integer.MAX_VALUE;
1533 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001534
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001535 try {
1536 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1537 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001538 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001539 }
1540 } finally {
1541 Binder.restoreCallingIdentity(ident);
1542 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001543 }
1544 }
1545 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001546
Dianne Hackborn254cb442010-01-27 19:23:59 -08001547 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001548 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001549 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001550
Dianne Hackborn254cb442010-01-27 19:23:59 -08001551 if (who != null) {
1552 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1553 return admin != null ? admin.maximumTimeToUnlock : time;
1554 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001555
Dianne Hackborn254cb442010-01-27 19:23:59 -08001556 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001557 for (int i=0; i<N; i++) {
1558 ActiveAdmin admin = mAdminList.get(i);
1559 if (time == 0) {
1560 time = admin.maximumTimeToUnlock;
1561 } else if (admin.maximumTimeToUnlock != 0
1562 && time > admin.maximumTimeToUnlock) {
1563 time = admin.maximumTimeToUnlock;
1564 }
1565 }
1566 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001567 }
1568 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001569
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001570 public void lockNow() {
1571 synchronized (this) {
1572 // This API can only be called by an active device admin,
1573 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001574 getActiveAdminForCallerLocked(null,
1575 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001576 long ident = Binder.clearCallingIdentity();
1577 try {
1578 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1579 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1580 } catch (RemoteException e) {
1581 } finally {
1582 Binder.restoreCallingIdentity(ident);
1583 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001584 }
1585 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001586
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001587 void wipeDataLocked(int flags) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001588 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
1589 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1590 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1591 mWakeLock.acquire(10000);
1592 mContext.startService(intent);
1593 } else {
1594 try {
1595 RecoverySystem.rebootWipeUserData(mContext);
1596 } catch (IOException e) {
1597 Slog.w(TAG, "Failed requesting data wipe", e);
1598 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001599 }
1600 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001601
Dianne Hackbornd6847842010-01-12 18:14:19 -08001602 public void wipeData(int flags) {
1603 synchronized (this) {
1604 // This API can only be called by an active device admin,
1605 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001606 getActiveAdminForCallerLocked(null,
1607 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001608 long ident = Binder.clearCallingIdentity();
1609 try {
1610 wipeDataLocked(flags);
1611 } finally {
1612 Binder.restoreCallingIdentity(ident);
1613 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001614 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001615 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001616
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001617 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1618 mContext.enforceCallingOrSelfPermission(
1619 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001620
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001621 synchronized (this) {
1622 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1623 if (admin == null) {
1624 try {
1625 result.sendResult(null);
1626 } catch (RemoteException e) {
1627 }
1628 return;
1629 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001630 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001631 intent.setComponent(admin.info.getComponent());
1632 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1633 @Override
1634 public void onReceive(Context context, Intent intent) {
1635 try {
1636 result.sendResult(getResultExtras(false));
1637 } catch (RemoteException e) {
1638 }
1639 }
1640 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001641 }
1642 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001643
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001644 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001645 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001646 mContext.enforceCallingOrSelfPermission(
1647 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001648
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001649 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001650
Dianne Hackbornd6847842010-01-12 18:14:19 -08001651 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001652 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001653 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1654 || mActivePasswordUpperCase != uppercase
1655 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001656 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001657 long ident = Binder.clearCallingIdentity();
1658 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001659 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001660 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001661 mActivePasswordLetters = letters;
1662 mActivePasswordLowerCase = lowercase;
1663 mActivePasswordUpperCase = uppercase;
1664 mActivePasswordNumeric = numbers;
1665 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001666 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001667 mFailedPasswordAttempts = 0;
1668 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001669 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001670 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001671 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001672 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001673 } finally {
1674 Binder.restoreCallingIdentity(ident);
1675 }
1676 }
1677 }
1678 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001679
Andy Stadler043116a2010-11-29 17:43:32 -08001680 /**
1681 * Called any time the device password is updated. Resets all password expiration clocks.
1682 */
Jim Millera4e28d12010-11-08 16:15:47 -08001683 private void updatePasswordExpirationsLocked() {
1684 final int N = mAdminList.size();
1685 if (N > 0) {
1686 for (int i=0; i<N; i++) {
1687 ActiveAdmin admin = mAdminList.get(i);
1688 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001689 long timeout = admin.passwordExpirationTimeout;
1690 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1691 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001692 }
1693 }
1694 saveSettingsLocked();
1695 }
1696 }
1697
Dianne Hackbornd6847842010-01-12 18:14:19 -08001698 public void reportFailedPasswordAttempt() {
1699 mContext.enforceCallingOrSelfPermission(
1700 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001701
Dianne Hackbornd6847842010-01-12 18:14:19 -08001702 synchronized (this) {
1703 long ident = Binder.clearCallingIdentity();
1704 try {
1705 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001706 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001707 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001708 if (max > 0 && mFailedPasswordAttempts >= max) {
1709 wipeDataLocked(0);
1710 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001711 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001712 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001713 } finally {
1714 Binder.restoreCallingIdentity(ident);
1715 }
1716 }
1717 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001718
Dianne Hackbornd6847842010-01-12 18:14:19 -08001719 public void reportSuccessfulPasswordAttempt() {
1720 mContext.enforceCallingOrSelfPermission(
1721 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001722
Dianne Hackbornd6847842010-01-12 18:14:19 -08001723 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001724 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001725 long ident = Binder.clearCallingIdentity();
1726 try {
1727 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001728 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001729 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001730 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001731 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001732 } finally {
1733 Binder.restoreCallingIdentity(ident);
1734 }
1735 }
1736 }
1737 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001738
Oscar Montemayor69238c62010-08-03 10:51:06 -07001739 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1740 String exclusionList) {
1741 synchronized(this) {
1742 if (who == null) {
1743 throw new NullPointerException("ComponentName is null");
1744 }
1745
1746 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1747 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1748
1749 // Scan through active admins and find if anyone has already
1750 // set the global proxy.
1751 final int N = mAdminList.size();
1752 Set<ComponentName> compSet = mAdminMap.keySet();
1753 for (ComponentName component : compSet) {
1754 ActiveAdmin ap = mAdminMap.get(component);
1755 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1756 // Another admin already sets the global proxy
1757 // Return it to the caller.
1758 return component;
1759 }
1760 }
1761 if (proxySpec == null) {
1762 admin.specifiesGlobalProxy = false;
1763 admin.globalProxySpec = null;
1764 admin.globalProxyExclusionList = null;
1765 } else {
1766
1767 admin.specifiesGlobalProxy = true;
1768 admin.globalProxySpec = proxySpec;
1769 admin.globalProxyExclusionList = exclusionList;
1770 }
1771
1772 // Reset the global proxy accordingly
1773 // Do this using system permissions, as apps cannot write to secure settings
1774 long origId = Binder.clearCallingIdentity();
1775 resetGlobalProxy();
1776 Binder.restoreCallingIdentity(origId);
1777 return null;
1778 }
1779 }
1780
1781 public ComponentName getGlobalProxyAdmin() {
1782 synchronized(this) {
1783 // Scan through active admins and find if anyone has already
1784 // set the global proxy.
1785 final int N = mAdminList.size();
1786 for (int i = 0; i < N; i++) {
1787 ActiveAdmin ap = mAdminList.get(i);
1788 if (ap.specifiesGlobalProxy) {
1789 // Device admin sets the global proxy
1790 // Return it to the caller.
1791 return ap.info.getComponent();
1792 }
1793 }
1794 }
1795 // No device admin sets the global proxy.
1796 return null;
1797 }
1798
1799 private void resetGlobalProxy() {
1800 final int N = mAdminList.size();
1801 for (int i = 0; i < N; i++) {
1802 ActiveAdmin ap = mAdminList.get(i);
1803 if (ap.specifiesGlobalProxy) {
1804 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1805 return;
1806 }
1807 }
1808 // No device admins defining global proxies - reset global proxy settings to none
1809 saveGlobalProxy(null, null);
1810 }
1811
1812 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1813 if (exclusionList == null) {
1814 exclusionList = "";
1815 }
1816 if (proxySpec == null) {
1817 proxySpec = "";
1818 }
1819 // Remove white spaces
1820 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001821 String data[] = proxySpec.split(":");
1822 int proxyPort = 8080;
1823 if (data.length > 1) {
1824 try {
1825 proxyPort = Integer.parseInt(data[1]);
1826 } catch (NumberFormatException e) {}
1827 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001828 exclusionList = exclusionList.trim();
1829 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001830 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1831 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1832 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1833 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001834 }
1835
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001836 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001837 * Set the storage encryption request for a single admin. Returns the new total request
1838 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001839 */
1840 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1841 synchronized (this) {
1842 // Check for permissions
1843 if (who == null) {
1844 throw new NullPointerException("ComponentName is null");
1845 }
1846 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1847 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1848
Andy Stadler22dbfda2011-01-17 12:47:31 -08001849 // Quick exit: If the filesystem does not support encryption, we can exit early.
1850 if (!isEncryptionSupported()) {
1851 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1852 }
1853
1854 // (1) Record the value for the admin so it's sticky
1855 if (ap.encryptionRequested != encrypt) {
1856 ap.encryptionRequested = encrypt;
1857 saveSettingsLocked();
1858 }
1859
1860 // (2) Compute "max" for all admins
1861 boolean newRequested = false;
1862 final int N = mAdminList.size();
1863 for (int i = 0; i < N; i++) {
1864 newRequested |= mAdminList.get(i).encryptionRequested;
1865 }
1866
1867 // Notify OS of new request
1868 setEncryptionRequested(newRequested);
1869
1870 // Return the new global request status
1871 return newRequested
1872 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1873 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001874 }
1875 }
1876
1877 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001878 * Get the current storage encryption request status for a given admin, or aggregate of all
1879 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001880 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08001881 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001882 synchronized (this) {
1883 // Check for permissions if a particular caller is specified
1884 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08001885 // When checking for a single caller, status is based on caller's request
1886 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1887 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1888 return ap.encryptionRequested;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001889 }
1890
Andy Stadler22dbfda2011-01-17 12:47:31 -08001891 // If no particular caller is specified, return the aggregate set of requests.
1892 // This is short circuited by returning true on the first hit.
1893 final int N = mAdminList.size();
1894 for (int i = 0; i < N; i++) {
1895 if (mAdminList.get(i).encryptionRequested) {
1896 return true;
1897 }
1898 }
1899 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001900 }
1901 }
1902
Andy Stadler22dbfda2011-01-17 12:47:31 -08001903 /**
1904 * Get the current encryption status of the device.
1905 */
1906 public int getStorageEncryptionStatus() {
1907 return getEncryptionStatus();
1908 }
1909
1910 /**
1911 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
1912 */
1913 private boolean isEncryptionSupported() {
1914 // Note, this can be implemented as
1915 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1916 // But is provided as a separate internal method if there's a faster way to do a
1917 // simple check for supported-or-not.
1918 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1919 }
1920
1921 /**
1922 * Hook to low-levels: Reporting the current status of encryption.
1923 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
1924 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
1925 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
1926 */
1927 private int getEncryptionStatus() {
1928 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1929 }
1930
1931 /**
1932 * Hook to low-levels: If needed, record the new admin setting for encryption.
1933 */
1934 private void setEncryptionRequested(boolean encrypt) {
1935 }
1936
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001937 @Override
1938 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1939 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1940 != PackageManager.PERMISSION_GRANTED) {
1941
1942 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1943 + Binder.getCallingPid()
1944 + ", uid=" + Binder.getCallingUid());
1945 return;
1946 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001947
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001948 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001949
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001950 synchronized (this) {
1951 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001952
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001953 p.println(" Enabled Device Admins:");
1954 final int N = mAdminList.size();
1955 for (int i=0; i<N; i++) {
1956 ActiveAdmin ap = mAdminList.get(i);
1957 if (ap != null) {
1958 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1959 pw.println(":");
1960 ap.dump(" ", pw);
1961 }
1962 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001963
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001964 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001965 pw.print(" mActivePasswordQuality=0x");
1966 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001967 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001968 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1969 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1970 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1971 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1972 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001973 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001974 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1975 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1976 }
1977 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001978}