blob: 53a19f5de74f8662986e0a18cd72630fa295deac [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;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700148
Oscar Montemayor69238c62010-08-03 10:51:06 -0700149 // TODO: review implementation decisions with frameworks team
150 boolean specifiesGlobalProxy = false;
151 String globalProxySpec = null;
152 String globalProxyExclusionList = null;
153
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800154 ActiveAdmin(DeviceAdminInfo _info) {
155 info = _info;
156 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700157
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800158 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700159
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800160 void writeToXml(XmlSerializer out)
161 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800162 out.startTag(null, "policies");
163 info.writePoliciesToXml(out);
164 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800165 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
166 out.startTag(null, "password-quality");
167 out.attribute(null, "value", Integer.toString(passwordQuality));
168 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800169 if (minimumPasswordLength > 0) {
170 out.startTag(null, "min-password-length");
171 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700172 out.endTag(null, "min-password-length");
173 }
174 if(passwordHistoryLength > 0) {
175 out.startTag(null, "password-history-length");
176 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
177 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800178 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700179 if (minimumPasswordUpperCase > 0) {
180 out.startTag(null, "min-password-uppercase");
181 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
182 out.endTag(null, "min-password-uppercase");
183 }
184 if (minimumPasswordLowerCase > 0) {
185 out.startTag(null, "min-password-lowercase");
186 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
187 out.endTag(null, "min-password-lowercase");
188 }
189 if (minimumPasswordLetters > 0) {
190 out.startTag(null, "min-password-letters");
191 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
192 out.endTag(null, "min-password-letters");
193 }
194 if (minimumPasswordNumeric > 0) {
195 out.startTag(null, "min-password-numeric");
196 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
197 out.endTag(null, "min-password-numeric");
198 }
199 if (minimumPasswordSymbols > 0) {
200 out.startTag(null, "min-password-symbols");
201 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
202 out.endTag(null, "min-password-symbols");
203 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700204 if (minimumPasswordNonLetter > 0) {
205 out.startTag(null, "min-password-nonletter");
206 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
207 out.endTag(null, "min-password-nonletter");
208 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800209 }
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700210 if (maximumTimeToUnlock != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800211 out.startTag(null, "max-time-to-unlock");
212 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
213 out.endTag(null, "max-time-to-unlock");
214 }
215 if (maximumFailedPasswordsForWipe != 0) {
216 out.startTag(null, "max-failed-password-wipe");
217 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
218 out.endTag(null, "max-failed-password-wipe");
219 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700220 if (specifiesGlobalProxy) {
221 out.startTag(null, "specifies-global-proxy");
222 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
223 out.endTag(null, "specifies_global_proxy");
224 if (globalProxySpec != null) {
225 out.startTag(null, "global-proxy-spec");
226 out.attribute(null, "value", globalProxySpec);
227 out.endTag(null, "global-proxy-spec");
228 }
229 if (globalProxyExclusionList != null) {
230 out.startTag(null, "global-proxy-exclusion-list");
231 out.attribute(null, "value", globalProxyExclusionList);
232 out.endTag(null, "global-proxy-exclusion-list");
233 }
234 }
Jim Millera4e28d12010-11-08 16:15:47 -0800235 if (passwordExpirationTimeout != 0L) {
236 out.startTag(null, "password-expiration-timeout");
237 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
238 out.endTag(null, "password-expiration-timeout");
239 }
240 if (passwordExpirationDate != 0L) {
241 out.startTag(null, "password-expiration-date");
242 out.attribute(null, "value", Long.toString(passwordExpirationDate));
243 out.endTag(null, "password-expiration-date");
244 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800245 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700246
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800247 void readFromXml(XmlPullParser parser)
248 throws XmlPullParserException, IOException {
249 int outerDepth = parser.getDepth();
250 int type;
251 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
252 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
253 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
254 continue;
255 }
256 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800257 if ("policies".equals(tag)) {
258 info.readPoliciesFromXml(parser);
259 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800260 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800261 parser.getAttributeValue(null, "value"));
262 } else if ("min-password-length".equals(tag)) {
263 minimumPasswordLength = Integer.parseInt(
264 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700265 } else if ("password-history-length".equals(tag)) {
266 passwordHistoryLength = Integer.parseInt(
267 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700268 } else if ("min-password-uppercase".equals(tag)) {
269 minimumPasswordUpperCase = Integer.parseInt(
270 parser.getAttributeValue(null, "value"));
271 } else if ("min-password-lowercase".equals(tag)) {
272 minimumPasswordLowerCase = Integer.parseInt(
273 parser.getAttributeValue(null, "value"));
274 } else if ("min-password-letters".equals(tag)) {
275 minimumPasswordLetters = Integer.parseInt(
276 parser.getAttributeValue(null, "value"));
277 } else if ("min-password-numeric".equals(tag)) {
278 minimumPasswordNumeric = Integer.parseInt(
279 parser.getAttributeValue(null, "value"));
280 } else if ("min-password-symbols".equals(tag)) {
281 minimumPasswordSymbols = Integer.parseInt(
282 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700283 } else if ("min-password-nonletter".equals(tag)) {
284 minimumPasswordNonLetter = Integer.parseInt(
285 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800286 } else if ("max-time-to-unlock".equals(tag)) {
287 maximumTimeToUnlock = Long.parseLong(
288 parser.getAttributeValue(null, "value"));
289 } else if ("max-failed-password-wipe".equals(tag)) {
290 maximumFailedPasswordsForWipe = Integer.parseInt(
291 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700292 } else if ("specifies-global-proxy".equals(tag)) {
293 specifiesGlobalProxy = Boolean.getBoolean(
294 parser.getAttributeValue(null, "value"));
295 } else if ("global-proxy-spec".equals(tag)) {
296 globalProxySpec =
297 parser.getAttributeValue(null, "value");
298 } else if ("global-proxy-exclusion-list".equals(tag)) {
299 globalProxyExclusionList =
300 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800301 } else if ("password-expiration-timeout".equals(tag)) {
302 passwordExpirationTimeout = Long.parseLong(
303 parser.getAttributeValue(null, "value"));
304 } else if ("password-expiration-date".equals(tag)) {
305 passwordExpirationDate = Long.parseLong(
306 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800307 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700308 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800309 }
310 XmlUtils.skipCurrentTag(parser);
311 }
312 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700313
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800314 void dump(String prefix, PrintWriter pw) {
315 pw.print(prefix); pw.print("uid="); pw.println(getUid());
316 pw.print(prefix); pw.println("policies:");
317 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
318 if (pols != null) {
319 for (int i=0; i<pols.size(); i++) {
320 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
321 }
322 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700323 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700324 pw.println(Integer.toHexString(passwordQuality));
325 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800326 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700327 pw.print(prefix); pw.print("passwordHistoryLength=");
328 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700329 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
330 pw.println(minimumPasswordUpperCase);
331 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
332 pw.println(minimumPasswordLowerCase);
333 pw.print(prefix); pw.print("minimumPasswordLetters=");
334 pw.println(minimumPasswordLetters);
335 pw.print(prefix); pw.print("minimumPasswordNumeric=");
336 pw.println(minimumPasswordNumeric);
337 pw.print(prefix); pw.print("minimumPasswordSymbols=");
338 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700339 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
340 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800341 pw.print(prefix); pw.print("maximumTimeToUnlock=");
342 pw.println(maximumTimeToUnlock);
343 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
344 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700345 pw.print(prefix); pw.print("specifiesGlobalProxy=");
346 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800347 pw.print(prefix); pw.print("passwordExpirationTimeout=");
348 pw.println(passwordExpirationTimeout);
349 pw.print(prefix); pw.print("passwordExpirationDate=");
350 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700351 if (globalProxySpec != null) {
352 pw.print(prefix); pw.print("globalProxySpec=");
353 pw.println(globalProxySpec);
354 }
355 if (globalProxyExclusionList != null) {
356 pw.print(prefix); pw.print("globalProxyEclusionList=");
357 pw.println(globalProxyExclusionList);
358 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800359 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800360 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700361
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800362 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800363 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800364 public void onSomePackagesChanged() {
365 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800366 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800367 for (int i=mAdminList.size()-1; i>=0; i--) {
368 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700369 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800370 if (change == PACKAGE_PERMANENT_CHANGE
371 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700372 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800373 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800374 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800375 mAdminList.remove(i);
376 } else if (isPackageModified(aa.info.getPackageName())) {
377 try {
378 mContext.getPackageManager().getReceiverInfo(
379 aa.info.getComponent(), 0);
380 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700381 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800382 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800383 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800384 mAdminList.remove(i);
385 }
386 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800387 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800388 if (removed) {
389 validatePasswordOwnerLocked();
390 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800391 }
392 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800393 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700394
Dianne Hackbornd6847842010-01-12 18:14:19 -0800395 /**
396 * Instantiates the service.
397 */
398 public DevicePolicyManagerService(Context context) {
399 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800400 mMonitor = new MyPackageMonitor();
401 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700402 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
403 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800404 IntentFilter filter = new IntentFilter();
405 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
406 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
407 context.registerReceiver(mReceiver, filter);
408 }
409
Jim Millera4e28d12010-11-08 16:15:47 -0800410 protected void setExpirationAlarmCheckLocked(Context context) {
411 final long expiration = getPasswordExpirationLocked(null);
412 final long now = System.currentTimeMillis();
413 final long timeToExpire = expiration - now;
414 final long alarmTime;
415 if (timeToExpire > 0L && timeToExpire < MS_PER_DAY) {
416 // Next expiration is less than a day, set alarm for exact expiration time
417 alarmTime = now + timeToExpire;
418 } else {
419 // Check again in 24 hours...
420 alarmTime = now + MS_PER_DAY;
421 }
422
Andy Stadler1f35d482010-11-19 15:39:41 -0800423 long token = Binder.clearCallingIdentity();
424 try {
425 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
426 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
427 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
428 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
429 am.cancel(pi);
430 am.set(AlarmManager.RTC, alarmTime, pi);
431 } finally {
432 Binder.restoreCallingIdentity(token);
433 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800434 }
435
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800436 private IPowerManager getIPowerManager() {
437 if (mIPowerManager == null) {
438 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
439 mIPowerManager = IPowerManager.Stub.asInterface(b);
440 }
441 return mIPowerManager;
442 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700443
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800444 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800445 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800446 if (admin != null
447 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
448 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
449 return admin;
450 }
451 return null;
452 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700453
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800454 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
455 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800456 final int callingUid = Binder.getCallingUid();
457 if (who != null) {
458 ActiveAdmin admin = mAdminMap.get(who);
459 if (admin == null) {
460 throw new SecurityException("No active admin " + who);
461 }
462 if (admin.getUid() != callingUid) {
463 throw new SecurityException("Admin " + who + " is not owned by uid "
464 + Binder.getCallingUid());
465 }
466 if (!admin.info.usesPolicy(reqPolicy)) {
467 throw new SecurityException("Admin " + admin.info.getComponent()
468 + " did not specify uses-policy for: "
469 + admin.info.getTagForPolicy(reqPolicy));
470 }
471 return admin;
472 } else {
473 final int N = mAdminList.size();
474 for (int i=0; i<N; i++) {
475 ActiveAdmin admin = mAdminList.get(i);
476 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
477 return admin;
478 }
479 }
480 throw new SecurityException("No active admin owned by uid "
481 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800482 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800483 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700484
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800485 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800486 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800487 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800488 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
489 intent.putExtra("expiration", admin.passwordExpirationDate);
490 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800491 mContext.sendBroadcast(intent);
492 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700493
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800494 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800495 final int N = mAdminList.size();
496 if (N > 0) {
497 for (int i=0; i<N; i++) {
498 ActiveAdmin admin = mAdminList.get(i);
499 if (admin.info.usesPolicy(reqPolicy)) {
500 sendAdminCommandLocked(admin, action);
501 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800502 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800503 }
504 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700505
Dianne Hackbornd6847842010-01-12 18:14:19 -0800506 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800507 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
508 if (admin != null) {
Oscar Montemayor69238c62010-08-03 10:51:06 -0700509 boolean doProxyCleanup =
510 admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800511 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800512 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800513 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800514 mAdminList.remove(admin);
515 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800516 validatePasswordOwnerLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -0700517 if (doProxyCleanup) {
518 resetGlobalProxy();
519 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800520 }
521 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700522
Dianne Hackbornd6847842010-01-12 18:14:19 -0800523 public DeviceAdminInfo findAdmin(ComponentName adminName) {
524 Intent resolveIntent = new Intent();
525 resolveIntent.setComponent(adminName);
526 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
527 resolveIntent, PackageManager.GET_META_DATA);
528 if (infos == null || infos.size() <= 0) {
529 throw new IllegalArgumentException("Unknown admin: " + adminName);
530 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700531
Dianne Hackbornd6847842010-01-12 18:14:19 -0800532 try {
533 return new DeviceAdminInfo(mContext, infos.get(0));
534 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700535 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800536 return null;
537 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700538 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800539 return null;
540 }
541 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700542
Dianne Hackbornd6847842010-01-12 18:14:19 -0800543 private static JournaledFile makeJournaledFile() {
544 final String base = "/data/system/device_policies.xml";
545 return new JournaledFile(new File(base), new File(base + ".tmp"));
546 }
547
548 private void saveSettingsLocked() {
549 JournaledFile journal = makeJournaledFile();
550 FileOutputStream stream = null;
551 try {
552 stream = new FileOutputStream(journal.chooseForWrite(), false);
553 XmlSerializer out = new FastXmlSerializer();
554 out.setOutput(stream, "utf-8");
555 out.startDocument(null, true);
556
557 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700558
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800559 final int N = mAdminList.size();
560 for (int i=0; i<N; i++) {
561 ActiveAdmin ap = mAdminList.get(i);
562 if (ap != null) {
563 out.startTag(null, "admin");
564 out.attribute(null, "name", ap.info.getComponent().flattenToString());
565 ap.writeToXml(out);
566 out.endTag(null, "admin");
567 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800568 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700569
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800570 if (mPasswordOwner >= 0) {
571 out.startTag(null, "password-owner");
572 out.attribute(null, "value", Integer.toString(mPasswordOwner));
573 out.endTag(null, "password-owner");
574 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700575
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800576 if (mFailedPasswordAttempts != 0) {
577 out.startTag(null, "failed-password-attempts");
578 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
579 out.endTag(null, "failed-password-attempts");
580 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700581
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700582 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
583 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
584 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700585 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700586 out.startTag(null, "active-password");
587 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
588 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700589 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
590 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
591 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
592 out.attribute(null, "numeric", Integer
593 .toString(mActivePasswordNumeric));
594 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700595 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700596 out.endTag(null, "active-password");
597 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700598
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700599 out.endTag(null, "policies");
600
Dianne Hackbornd6847842010-01-12 18:14:19 -0800601 out.endDocument();
602 stream.close();
603 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700604 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800605 } catch (IOException e) {
606 try {
607 if (stream != null) {
608 stream.close();
609 }
610 } catch (IOException ex) {
611 // Ignore
612 }
613 journal.rollback();
614 }
615 }
616
Jim Miller284b62e2010-06-08 14:27:42 -0700617 private void sendChangedNotification() {
618 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
619 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
620 mContext.sendBroadcast(intent);
621 }
622
Dianne Hackbornd6847842010-01-12 18:14:19 -0800623 private void loadSettingsLocked() {
624 JournaledFile journal = makeJournaledFile();
625 FileInputStream stream = null;
626 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800627 try {
628 stream = new FileInputStream(file);
629 XmlPullParser parser = Xml.newPullParser();
630 parser.setInput(stream, null);
631
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800632 int type;
633 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
634 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800635 }
636 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800637 if (!"policies".equals(tag)) {
638 throw new XmlPullParserException(
639 "Settings do not start with policies tag: found " + tag);
640 }
641 type = parser.next();
642 int outerDepth = parser.getDepth();
643 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
644 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
645 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
646 continue;
647 }
648 tag = parser.getName();
649 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800650 String name = parser.getAttributeValue(null, "name");
651 try {
652 DeviceAdminInfo dai = findAdmin(
653 ComponentName.unflattenFromString(name));
654 if (dai != null) {
655 ActiveAdmin ap = new ActiveAdmin(dai);
656 ap.readFromXml(parser);
657 mAdminMap.put(ap.info.getComponent(), ap);
658 mAdminList.add(ap);
659 }
660 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700661 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800662 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800663 } else if ("failed-password-attempts".equals(tag)) {
664 mFailedPasswordAttempts = Integer.parseInt(
665 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800666 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800667 } else if ("password-owner".equals(tag)) {
668 mPasswordOwner = Integer.parseInt(
669 parser.getAttributeValue(null, "value"));
670 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700671 } else if ("active-password".equals(tag)) {
672 mActivePasswordQuality = Integer.parseInt(
673 parser.getAttributeValue(null, "quality"));
674 mActivePasswordLength = Integer.parseInt(
675 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700676 mActivePasswordUpperCase = Integer.parseInt(
677 parser.getAttributeValue(null, "uppercase"));
678 mActivePasswordLowerCase = Integer.parseInt(
679 parser.getAttributeValue(null, "lowercase"));
680 mActivePasswordLetters = Integer.parseInt(
681 parser.getAttributeValue(null, "letters"));
682 mActivePasswordNumeric = Integer.parseInt(
683 parser.getAttributeValue(null, "numeric"));
684 mActivePasswordSymbols = Integer.parseInt(
685 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700686 mActivePasswordNonLetter = Integer.parseInt(
687 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700688 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800689 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700690 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800691 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800692 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800693 }
694 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700695 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800696 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700697 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800698 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700699 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700700 } catch (FileNotFoundException e) {
701 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800702 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700703 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800704 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700705 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800706 }
707 try {
708 if (stream != null) {
709 stream.close();
710 }
711 } catch (IOException e) {
712 // Ignore
713 }
714
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700715 // Validate that what we stored for the password quality matches
716 // sufficiently what is currently set. Note that this is only
717 // a sanity check in case the two get out of sync; this should
718 // never normally happen.
719 LockPatternUtils utils = new LockPatternUtils(mContext);
720 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
721 Slog.w(TAG, "Active password quality 0x"
722 + Integer.toHexString(mActivePasswordQuality)
723 + " does not match actual quality 0x"
724 + Integer.toHexString(utils.getActivePasswordQuality()));
725 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
726 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700727 mActivePasswordUpperCase = 0;
728 mActivePasswordLowerCase = 0;
729 mActivePasswordLetters = 0;
730 mActivePasswordNumeric = 0;
731 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700732 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700733 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700734
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800735 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700736
Dianne Hackborn254cb442010-01-27 19:23:59 -0800737 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800738 if (timeMs <= 0) {
739 timeMs = Integer.MAX_VALUE;
740 }
741 try {
742 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
743 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700744 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800745 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800746 }
747
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700748 static void validateQualityConstant(int quality) {
749 switch (quality) {
750 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
751 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
752 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
753 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
754 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700755 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700756 return;
757 }
758 throw new IllegalArgumentException("Invalid quality constant: 0x"
759 + Integer.toHexString(quality));
760 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700761
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800762 void validatePasswordOwnerLocked() {
763 if (mPasswordOwner >= 0) {
764 boolean haveOwner = false;
765 for (int i=mAdminList.size()-1; i>=0; i--) {
766 if (mAdminList.get(i).getUid() == mPasswordOwner) {
767 haveOwner = true;
768 break;
769 }
770 }
771 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700772 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800773 + " no longer active; disabling");
774 mPasswordOwner = -1;
775 }
776 }
777 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700778
Dianne Hackbornd6847842010-01-12 18:14:19 -0800779 public void systemReady() {
780 synchronized (this) {
781 loadSettingsLocked();
782 }
783 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700784
Jim Millera4e28d12010-11-08 16:15:47 -0800785 private void handlePasswordExpirationNotification() {
786 synchronized (this) {
787 final long now = System.currentTimeMillis();
788 final int N = mAdminList.size();
789 if (N <= 0) {
790 return;
791 }
792 for (int i=0; i < N; i++) {
793 ActiveAdmin admin = mAdminList.get(i);
794 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
795 && admin.passwordExpirationTimeout > 0L
796 && admin.passwordExpirationDate > 0L
797 && now > admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
798 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
799 }
800 }
801 setExpirationAlarmCheckLocked(mContext);
802 }
803 }
804
Dianne Hackbornd6847842010-01-12 18:14:19 -0800805 public void setActiveAdmin(ComponentName adminReceiver) {
806 mContext.enforceCallingOrSelfPermission(
807 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700808
Dianne Hackbornd6847842010-01-12 18:14:19 -0800809 DeviceAdminInfo info = findAdmin(adminReceiver);
810 if (info == null) {
811 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
812 }
813 synchronized (this) {
814 long ident = Binder.clearCallingIdentity();
815 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800816 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
817 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800818 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800819 ActiveAdmin admin = new ActiveAdmin(info);
820 mAdminMap.put(adminReceiver, admin);
821 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800822 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800823 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800824 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800825 } finally {
826 Binder.restoreCallingIdentity(ident);
827 }
828 }
829 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700830
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800831 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800832 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800833 return getActiveAdminUncheckedLocked(adminReceiver) != null;
834 }
835 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700836
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800837 public List<ComponentName> getActiveAdmins() {
838 synchronized (this) {
839 final int N = mAdminList.size();
840 if (N <= 0) {
841 return null;
842 }
843 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
844 for (int i=0; i<N; i++) {
845 res.add(mAdminList.get(i).info.getComponent());
846 }
847 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800848 }
849 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700850
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800851 public boolean packageHasActiveAdmins(String packageName) {
852 synchronized (this) {
853 final int N = mAdminList.size();
854 for (int i=0; i<N; i++) {
855 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
856 return true;
857 }
858 }
859 return false;
860 }
861 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700862
Dianne Hackbornd6847842010-01-12 18:14:19 -0800863 public void removeActiveAdmin(ComponentName adminReceiver) {
864 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800865 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
866 if (admin == null) {
867 return;
868 }
869 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800870 mContext.enforceCallingOrSelfPermission(
871 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
872 }
873 long ident = Binder.clearCallingIdentity();
874 try {
875 removeActiveAdminLocked(adminReceiver);
876 } finally {
877 Binder.restoreCallingIdentity(ident);
878 }
879 }
880 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700881
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700882 public void setPasswordQuality(ComponentName who, int quality) {
883 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700884
Dianne Hackbornd6847842010-01-12 18:14:19 -0800885 synchronized (this) {
886 if (who == null) {
887 throw new NullPointerException("ComponentName is null");
888 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800889 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
890 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700891 if (ap.passwordQuality != quality) {
892 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800893 saveSettingsLocked();
894 }
895 }
896 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700897
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800898 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800899 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800900 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700901
Dianne Hackborn254cb442010-01-27 19:23:59 -0800902 if (who != null) {
903 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800904 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800905 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700906
Dianne Hackborn254cb442010-01-27 19:23:59 -0800907 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800908 for (int i=0; i<N; i++) {
909 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800910 if (mode < admin.passwordQuality) {
911 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800912 }
913 }
914 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800915 }
916 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700917
Dianne Hackborn254cb442010-01-27 19:23:59 -0800918 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800919 synchronized (this) {
920 if (who == null) {
921 throw new NullPointerException("ComponentName is null");
922 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800923 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
924 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800925 if (ap.minimumPasswordLength != length) {
926 ap.minimumPasswordLength = length;
927 saveSettingsLocked();
928 }
929 }
930 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700931
Dianne Hackborn254cb442010-01-27 19:23:59 -0800932 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800933 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800934 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700935
Dianne Hackborn254cb442010-01-27 19:23:59 -0800936 if (who != null) {
937 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
938 return admin != null ? admin.minimumPasswordLength : length;
939 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700940
Dianne Hackborn254cb442010-01-27 19:23:59 -0800941 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800942 for (int i=0; i<N; i++) {
943 ActiveAdmin admin = mAdminList.get(i);
944 if (length < admin.minimumPasswordLength) {
945 length = admin.minimumPasswordLength;
946 }
947 }
948 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800949 }
950 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700951
952 public void setPasswordHistoryLength(ComponentName who, int length) {
953 synchronized (this) {
954 if (who == null) {
955 throw new NullPointerException("ComponentName is null");
956 }
957 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
958 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
959 if (ap.passwordHistoryLength != length) {
960 ap.passwordHistoryLength = length;
961 saveSettingsLocked();
962 }
963 }
964 }
965
966 public int getPasswordHistoryLength(ComponentName who) {
967 synchronized (this) {
968 int length = 0;
969
970 if (who != null) {
971 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
972 return admin != null ? admin.passwordHistoryLength : length;
973 }
974
975 final int N = mAdminList.size();
976 for (int i = 0; i < N; i++) {
977 ActiveAdmin admin = mAdminList.get(i);
978 if (length < admin.passwordHistoryLength) {
979 length = admin.passwordHistoryLength;
980 }
981 }
982 return length;
983 }
984 }
985
Jim Millera4e28d12010-11-08 16:15:47 -0800986 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
987 synchronized (this) {
988 if (who == null) {
989 throw new NullPointerException("ComponentName is null");
990 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800991 if (timeout < 0) {
992 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -0800993 }
994 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
995 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
996 // Calling this API automatically bumps the expiration date
997 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
998 ap.passwordExpirationDate = expiration;
999 ap.passwordExpirationTimeout = timeout;
1000 if (timeout > 0L) {
1001 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1002 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1003 .format(new Date(expiration)));
1004 }
1005 saveSettingsLocked();
1006 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1007 }
1008 }
1009
1010 public long getPasswordExpirationTimeout(ComponentName who) {
1011 synchronized (this) {
1012 long timeout = 0L;
1013 if (who != null) {
1014 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1015 return admin != null ? admin.passwordExpirationTimeout : timeout;
1016 }
1017
1018 final int N = mAdminList.size();
1019 for (int i = 0; i < N; i++) {
1020 ActiveAdmin admin = mAdminList.get(i);
1021 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1022 && timeout > admin.passwordExpirationTimeout)) {
1023 timeout = admin.passwordExpirationTimeout;
1024 }
1025 }
1026 return timeout;
1027 }
1028 }
1029
1030 private long getPasswordExpirationLocked(ComponentName who) {
1031 long timeout = 0L;
1032 if (who != null) {
1033 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1034 return admin != null ? admin.passwordExpirationDate : timeout;
1035 }
1036
1037 final int N = mAdminList.size();
1038 for (int i = 0; i < N; i++) {
1039 ActiveAdmin admin = mAdminList.get(i);
1040 if (timeout == 0L || (admin.passwordExpirationDate != 0
1041 && timeout > admin.passwordExpirationDate)) {
1042 timeout = admin.passwordExpirationDate;
1043 }
1044 }
1045 return timeout;
1046 }
1047
1048 public long getPasswordExpiration(ComponentName who) {
1049 synchronized (this) {
1050 return getPasswordExpirationLocked(who);
1051 }
1052 }
1053
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001054 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1055 synchronized (this) {
1056 if (who == null) {
1057 throw new NullPointerException("ComponentName is null");
1058 }
1059 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1060 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1061 if (ap.minimumPasswordUpperCase != length) {
1062 ap.minimumPasswordUpperCase = length;
1063 saveSettingsLocked();
1064 }
1065 }
1066 }
1067
1068 public int getPasswordMinimumUpperCase(ComponentName who) {
1069 synchronized (this) {
1070 int length = 0;
1071
1072 if (who != null) {
1073 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1074 return admin != null ? admin.minimumPasswordUpperCase : length;
1075 }
1076
1077 final int N = mAdminList.size();
1078 for (int i=0; i<N; i++) {
1079 ActiveAdmin admin = mAdminList.get(i);
1080 if (length < admin.minimumPasswordUpperCase) {
1081 length = admin.minimumPasswordUpperCase;
1082 }
1083 }
1084 return length;
1085 }
1086 }
1087
1088 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1089 synchronized (this) {
1090 if (who == null) {
1091 throw new NullPointerException("ComponentName is null");
1092 }
1093 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1094 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1095 if (ap.minimumPasswordLowerCase != length) {
1096 ap.minimumPasswordLowerCase = length;
1097 saveSettingsLocked();
1098 }
1099 }
1100 }
1101
1102 public int getPasswordMinimumLowerCase(ComponentName who) {
1103 synchronized (this) {
1104 int length = 0;
1105
1106 if (who != null) {
1107 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1108 return admin != null ? admin.minimumPasswordLowerCase : length;
1109 }
1110
1111 final int N = mAdminList.size();
1112 for (int i=0; i<N; i++) {
1113 ActiveAdmin admin = mAdminList.get(i);
1114 if (length < admin.minimumPasswordLowerCase) {
1115 length = admin.minimumPasswordLowerCase;
1116 }
1117 }
1118 return length;
1119 }
1120 }
1121
1122 public void setPasswordMinimumLetters(ComponentName who, int length) {
1123 synchronized (this) {
1124 if (who == null) {
1125 throw new NullPointerException("ComponentName is null");
1126 }
1127 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1128 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1129 if (ap.minimumPasswordLetters != length) {
1130 ap.minimumPasswordLetters = length;
1131 saveSettingsLocked();
1132 }
1133 }
1134 }
1135
1136 public int getPasswordMinimumLetters(ComponentName who) {
1137 synchronized (this) {
1138 int length = 0;
1139
1140 if (who != null) {
1141 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1142 return admin != null ? admin.minimumPasswordLetters : length;
1143 }
1144
1145 final int N = mAdminList.size();
1146 for (int i=0; i<N; i++) {
1147 ActiveAdmin admin = mAdminList.get(i);
1148 if (length < admin.minimumPasswordLetters) {
1149 length = admin.minimumPasswordLetters;
1150 }
1151 }
1152 return length;
1153 }
1154 }
1155
1156 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1157 synchronized (this) {
1158 if (who == null) {
1159 throw new NullPointerException("ComponentName is null");
1160 }
1161 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1162 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1163 if (ap.minimumPasswordNumeric != length) {
1164 ap.minimumPasswordNumeric = length;
1165 saveSettingsLocked();
1166 }
1167 }
1168 }
1169
1170 public int getPasswordMinimumNumeric(ComponentName who) {
1171 synchronized (this) {
1172 int length = 0;
1173
1174 if (who != null) {
1175 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1176 return admin != null ? admin.minimumPasswordNumeric : length;
1177 }
1178
1179 final int N = mAdminList.size();
1180 for (int i = 0; i < N; i++) {
1181 ActiveAdmin admin = mAdminList.get(i);
1182 if (length < admin.minimumPasswordNumeric) {
1183 length = admin.minimumPasswordNumeric;
1184 }
1185 }
1186 return length;
1187 }
1188 }
1189
1190 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1191 synchronized (this) {
1192 if (who == null) {
1193 throw new NullPointerException("ComponentName is null");
1194 }
1195 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1196 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1197 if (ap.minimumPasswordSymbols != length) {
1198 ap.minimumPasswordSymbols = length;
1199 saveSettingsLocked();
1200 }
1201 }
1202 }
1203
1204 public int getPasswordMinimumSymbols(ComponentName who) {
1205 synchronized (this) {
1206 int length = 0;
1207
1208 if (who != null) {
1209 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1210 return admin != null ? admin.minimumPasswordSymbols : length;
1211 }
1212
1213 final int N = mAdminList.size();
1214 for (int i=0; i<N; i++) {
1215 ActiveAdmin admin = mAdminList.get(i);
1216 if (length < admin.minimumPasswordSymbols) {
1217 length = admin.minimumPasswordSymbols;
1218 }
1219 }
1220 return length;
1221 }
1222 }
1223
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001224 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1225 synchronized (this) {
1226 if (who == null) {
1227 throw new NullPointerException("ComponentName is null");
1228 }
1229 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1230 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1231 if (ap.minimumPasswordNonLetter != length) {
1232 ap.minimumPasswordNonLetter = length;
1233 saveSettingsLocked();
1234 }
1235 }
1236 }
1237
1238 public int getPasswordMinimumNonLetter(ComponentName who) {
1239 synchronized (this) {
1240 int length = 0;
1241
1242 if (who != null) {
1243 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1244 return admin != null ? admin.minimumPasswordNonLetter : length;
1245 }
1246
1247 final int N = mAdminList.size();
1248 for (int i=0; i<N; i++) {
1249 ActiveAdmin admin = mAdminList.get(i);
1250 if (length < admin.minimumPasswordNonLetter) {
1251 length = admin.minimumPasswordNonLetter;
1252 }
1253 }
1254 return length;
1255 }
1256 }
1257
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001258 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001259 synchronized (this) {
1260 // This API can only be called by an active device admin,
1261 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001262 getActiveAdminForCallerLocked(null,
1263 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001264 if (mActivePasswordQuality < getPasswordQuality(null)
1265 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1266 return false;
1267 }
1268 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1269 return true;
1270 }
1271 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1272 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1273 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1274 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001275 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1276 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001277 }
1278 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001279
Dianne Hackbornd6847842010-01-12 18:14:19 -08001280 public int getCurrentFailedPasswordAttempts() {
1281 synchronized (this) {
1282 // This API can only be called by an active device admin,
1283 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001284 getActiveAdminForCallerLocked(null,
1285 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001286 return mFailedPasswordAttempts;
1287 }
1288 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001289
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001290 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1291 synchronized (this) {
1292 // This API can only be called by an active device admin,
1293 // so try to retrieve it to check that the caller is one.
1294 getActiveAdminForCallerLocked(who,
1295 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1296 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1297 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1298 if (ap.maximumFailedPasswordsForWipe != num) {
1299 ap.maximumFailedPasswordsForWipe = num;
1300 saveSettingsLocked();
1301 }
1302 }
1303 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001304
Dianne Hackborn254cb442010-01-27 19:23:59 -08001305 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001306 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001307 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001308
Dianne Hackborn254cb442010-01-27 19:23:59 -08001309 if (who != null) {
1310 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1311 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1312 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001313
Dianne Hackborn254cb442010-01-27 19:23:59 -08001314 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001315 for (int i=0; i<N; i++) {
1316 ActiveAdmin admin = mAdminList.get(i);
1317 if (count == 0) {
1318 count = admin.maximumFailedPasswordsForWipe;
1319 } else if (admin.maximumFailedPasswordsForWipe != 0
1320 && count > admin.maximumFailedPasswordsForWipe) {
1321 count = admin.maximumFailedPasswordsForWipe;
1322 }
1323 }
1324 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001325 }
1326 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001327
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001328 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001329 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001330 synchronized (this) {
1331 // This API can only be called by an active device admin,
1332 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001333 getActiveAdminForCallerLocked(null,
1334 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001335 quality = getPasswordQuality(null);
1336 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001337 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001338 if (realQuality < quality
1339 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001340 Slog.w(TAG, "resetPassword: password quality 0x"
1341 + Integer.toHexString(quality)
1342 + " does not meet required quality 0x"
1343 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001344 return false;
1345 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001346 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001347 }
1348 int length = getPasswordMinimumLength(null);
1349 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001350 Slog.w(TAG, "resetPassword: password length " + password.length()
1351 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001352 return false;
1353 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001354 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1355 int letters = 0;
1356 int uppercase = 0;
1357 int lowercase = 0;
1358 int numbers = 0;
1359 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001360 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001361 for (int i = 0; i < password.length(); i++) {
1362 char c = password.charAt(i);
1363 if (c >= 'A' && c <= 'Z') {
1364 letters++;
1365 uppercase++;
1366 } else if (c >= 'a' && c <= 'z') {
1367 letters++;
1368 lowercase++;
1369 } else if (c >= '0' && c <= '9') {
1370 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001371 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001372 } else {
1373 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001374 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001375 }
1376 }
1377 int neededLetters = getPasswordMinimumLetters(null);
1378 if(letters < neededLetters) {
1379 Slog.w(TAG, "resetPassword: number of letters " + letters
1380 + " does not meet required number of letters " + neededLetters);
1381 return false;
1382 }
1383 int neededNumbers = getPasswordMinimumNumeric(null);
1384 if (numbers < neededNumbers) {
1385 Slog
1386 .w(TAG, "resetPassword: number of numerical digits " + numbers
1387 + " does not meet required number of numerical digits "
1388 + neededNumbers);
1389 return false;
1390 }
1391 int neededLowerCase = getPasswordMinimumLowerCase(null);
1392 if (lowercase < neededLowerCase) {
1393 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1394 + " does not meet required number of lowercase letters "
1395 + neededLowerCase);
1396 return false;
1397 }
1398 int neededUpperCase = getPasswordMinimumUpperCase(null);
1399 if (uppercase < neededUpperCase) {
1400 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1401 + " does not meet required number of uppercase letters "
1402 + neededUpperCase);
1403 return false;
1404 }
1405 int neededSymbols = getPasswordMinimumSymbols(null);
1406 if (symbols < neededSymbols) {
1407 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1408 + " does not meet required number of special symbols " + neededSymbols);
1409 return false;
1410 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001411 int neededNonLetter = getPasswordMinimumNonLetter(null);
1412 if (nonletter < neededNonLetter) {
1413 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1414 + " does not meet required number of non-letter characters "
1415 + neededNonLetter);
1416 return false;
1417 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001418 }
1419
1420 LockPatternUtils utils = new LockPatternUtils(mContext);
1421 if(utils.checkPasswordHistory(password)) {
1422 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1423 + getPasswordHistoryLength(null) + " passwords");
1424 return false;
1425 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001426 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001427
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001428 int callingUid = Binder.getCallingUid();
1429 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001430 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001431 return false;
1432 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001433
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001434 // Don't do this with the lock held, because it is going to call
1435 // back in to the service.
1436 long ident = Binder.clearCallingIdentity();
1437 try {
1438 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001439 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001440 synchronized (this) {
1441 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1442 != 0 ? callingUid : -1;
1443 if (mPasswordOwner != newOwner) {
1444 mPasswordOwner = newOwner;
1445 saveSettingsLocked();
1446 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001447 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001448 } finally {
1449 Binder.restoreCallingIdentity(ident);
1450 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001451
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001452 return true;
1453 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001454
Dianne Hackbornd6847842010-01-12 18:14:19 -08001455 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1456 synchronized (this) {
1457 if (who == null) {
1458 throw new NullPointerException("ComponentName is null");
1459 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001460 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001461 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001462 if (ap.maximumTimeToUnlock != timeMs) {
1463 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001464
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001465 long ident = Binder.clearCallingIdentity();
1466 try {
1467 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001468
Dianne Hackborn254cb442010-01-27 19:23:59 -08001469 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001470 if (timeMs <= 0) {
1471 timeMs = Integer.MAX_VALUE;
1472 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001473
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001474 try {
1475 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1476 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001477 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001478 }
1479 } finally {
1480 Binder.restoreCallingIdentity(ident);
1481 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001482 }
1483 }
1484 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001485
Dianne Hackborn254cb442010-01-27 19:23:59 -08001486 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001487 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001488 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001489
Dianne Hackborn254cb442010-01-27 19:23:59 -08001490 if (who != null) {
1491 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1492 return admin != null ? admin.maximumTimeToUnlock : time;
1493 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001494
Dianne Hackborn254cb442010-01-27 19:23:59 -08001495 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001496 for (int i=0; i<N; i++) {
1497 ActiveAdmin admin = mAdminList.get(i);
1498 if (time == 0) {
1499 time = admin.maximumTimeToUnlock;
1500 } else if (admin.maximumTimeToUnlock != 0
1501 && time > admin.maximumTimeToUnlock) {
1502 time = admin.maximumTimeToUnlock;
1503 }
1504 }
1505 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001506 }
1507 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001508
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001509 public void lockNow() {
1510 synchronized (this) {
1511 // This API can only be called by an active device admin,
1512 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001513 getActiveAdminForCallerLocked(null,
1514 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001515 long ident = Binder.clearCallingIdentity();
1516 try {
1517 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1518 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1519 } catch (RemoteException e) {
1520 } finally {
1521 Binder.restoreCallingIdentity(ident);
1522 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001523 }
1524 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001525
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001526 void wipeDataLocked(int flags) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001527 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
1528 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1529 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1530 mWakeLock.acquire(10000);
1531 mContext.startService(intent);
1532 } else {
1533 try {
1534 RecoverySystem.rebootWipeUserData(mContext);
1535 } catch (IOException e) {
1536 Slog.w(TAG, "Failed requesting data wipe", e);
1537 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001538 }
1539 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001540
Dianne Hackbornd6847842010-01-12 18:14:19 -08001541 public void wipeData(int flags) {
1542 synchronized (this) {
1543 // This API can only be called by an active device admin,
1544 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001545 getActiveAdminForCallerLocked(null,
1546 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001547 long ident = Binder.clearCallingIdentity();
1548 try {
1549 wipeDataLocked(flags);
1550 } finally {
1551 Binder.restoreCallingIdentity(ident);
1552 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001553 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001554 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001555
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001556 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1557 mContext.enforceCallingOrSelfPermission(
1558 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001559
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001560 synchronized (this) {
1561 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1562 if (admin == null) {
1563 try {
1564 result.sendResult(null);
1565 } catch (RemoteException e) {
1566 }
1567 return;
1568 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001569 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001570 intent.setComponent(admin.info.getComponent());
1571 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1572 @Override
1573 public void onReceive(Context context, Intent intent) {
1574 try {
1575 result.sendResult(getResultExtras(false));
1576 } catch (RemoteException e) {
1577 }
1578 }
1579 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001580 }
1581 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001582
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001583 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001584 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001585 mContext.enforceCallingOrSelfPermission(
1586 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001587
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001588 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001589
Dianne Hackbornd6847842010-01-12 18:14:19 -08001590 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001591 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001592 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1593 || mActivePasswordUpperCase != uppercase
1594 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001595 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001596 long ident = Binder.clearCallingIdentity();
1597 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001598 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001599 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001600 mActivePasswordLetters = letters;
1601 mActivePasswordLowerCase = lowercase;
1602 mActivePasswordUpperCase = uppercase;
1603 mActivePasswordNumeric = numbers;
1604 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001605 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001606 mFailedPasswordAttempts = 0;
1607 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001608 updatePasswordExpirationsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001609 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001610 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001611 } finally {
1612 Binder.restoreCallingIdentity(ident);
1613 }
1614 }
1615 }
1616 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001617
Jim Millera4e28d12010-11-08 16:15:47 -08001618 private void updatePasswordExpirationsLocked() {
1619 final int N = mAdminList.size();
1620 if (N > 0) {
1621 for (int i=0; i<N; i++) {
1622 ActiveAdmin admin = mAdminList.get(i);
1623 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
1624 admin.passwordExpirationDate = System.currentTimeMillis()
1625 + admin.passwordExpirationTimeout;
1626 }
1627 }
1628 saveSettingsLocked();
1629 }
1630 }
1631
Dianne Hackbornd6847842010-01-12 18:14:19 -08001632 public void reportFailedPasswordAttempt() {
1633 mContext.enforceCallingOrSelfPermission(
1634 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001635
Dianne Hackbornd6847842010-01-12 18:14:19 -08001636 synchronized (this) {
1637 long ident = Binder.clearCallingIdentity();
1638 try {
1639 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001640 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001641 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001642 if (max > 0 && mFailedPasswordAttempts >= max) {
1643 wipeDataLocked(0);
1644 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001645 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001646 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001647 } finally {
1648 Binder.restoreCallingIdentity(ident);
1649 }
1650 }
1651 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001652
Dianne Hackbornd6847842010-01-12 18:14:19 -08001653 public void reportSuccessfulPasswordAttempt() {
1654 mContext.enforceCallingOrSelfPermission(
1655 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001656
Dianne Hackbornd6847842010-01-12 18:14:19 -08001657 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001658 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001659 long ident = Binder.clearCallingIdentity();
1660 try {
1661 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001662 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001663 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001664 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001665 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001666 } finally {
1667 Binder.restoreCallingIdentity(ident);
1668 }
1669 }
1670 }
1671 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001672
Oscar Montemayor69238c62010-08-03 10:51:06 -07001673 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1674 String exclusionList) {
1675 synchronized(this) {
1676 if (who == null) {
1677 throw new NullPointerException("ComponentName is null");
1678 }
1679
1680 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1681 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1682
1683 // Scan through active admins and find if anyone has already
1684 // set the global proxy.
1685 final int N = mAdminList.size();
1686 Set<ComponentName> compSet = mAdminMap.keySet();
1687 for (ComponentName component : compSet) {
1688 ActiveAdmin ap = mAdminMap.get(component);
1689 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1690 // Another admin already sets the global proxy
1691 // Return it to the caller.
1692 return component;
1693 }
1694 }
1695 if (proxySpec == null) {
1696 admin.specifiesGlobalProxy = false;
1697 admin.globalProxySpec = null;
1698 admin.globalProxyExclusionList = null;
1699 } else {
1700
1701 admin.specifiesGlobalProxy = true;
1702 admin.globalProxySpec = proxySpec;
1703 admin.globalProxyExclusionList = exclusionList;
1704 }
1705
1706 // Reset the global proxy accordingly
1707 // Do this using system permissions, as apps cannot write to secure settings
1708 long origId = Binder.clearCallingIdentity();
1709 resetGlobalProxy();
1710 Binder.restoreCallingIdentity(origId);
1711 return null;
1712 }
1713 }
1714
1715 public ComponentName getGlobalProxyAdmin() {
1716 synchronized(this) {
1717 // Scan through active admins and find if anyone has already
1718 // set the global proxy.
1719 final int N = mAdminList.size();
1720 for (int i = 0; i < N; i++) {
1721 ActiveAdmin ap = mAdminList.get(i);
1722 if (ap.specifiesGlobalProxy) {
1723 // Device admin sets the global proxy
1724 // Return it to the caller.
1725 return ap.info.getComponent();
1726 }
1727 }
1728 }
1729 // No device admin sets the global proxy.
1730 return null;
1731 }
1732
1733 private void resetGlobalProxy() {
1734 final int N = mAdminList.size();
1735 for (int i = 0; i < N; i++) {
1736 ActiveAdmin ap = mAdminList.get(i);
1737 if (ap.specifiesGlobalProxy) {
1738 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1739 return;
1740 }
1741 }
1742 // No device admins defining global proxies - reset global proxy settings to none
1743 saveGlobalProxy(null, null);
1744 }
1745
1746 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1747 if (exclusionList == null) {
1748 exclusionList = "";
1749 }
1750 if (proxySpec == null) {
1751 proxySpec = "";
1752 }
1753 // Remove white spaces
1754 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001755 String data[] = proxySpec.split(":");
1756 int proxyPort = 8080;
1757 if (data.length > 1) {
1758 try {
1759 proxyPort = Integer.parseInt(data[1]);
1760 } catch (NumberFormatException e) {}
1761 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001762 exclusionList = exclusionList.trim();
1763 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001764 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1765 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1766 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1767 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001768 }
1769
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001770 @Override
1771 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1772 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1773 != PackageManager.PERMISSION_GRANTED) {
1774
1775 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1776 + Binder.getCallingPid()
1777 + ", uid=" + Binder.getCallingUid());
1778 return;
1779 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001780
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001781 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001782
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001783 synchronized (this) {
1784 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001785
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001786 p.println(" Enabled Device Admins:");
1787 final int N = mAdminList.size();
1788 for (int i=0; i<N; i++) {
1789 ActiveAdmin ap = mAdminList.get(i);
1790 if (ap != null) {
1791 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1792 pw.println(":");
1793 ap.dump(" ", pw);
1794 }
1795 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001796
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001797 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001798 pw.print(" mActivePasswordQuality=0x");
1799 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001800 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001801 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1802 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1803 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1804 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1805 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001806 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001807 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1808 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1809 }
1810 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001811}