blob: c0ea68d7319044ac46df11806e4a7833d999258b [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 Hackborn2269d1572010-02-24 19:54:22 -080020import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070021import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080022import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080023import com.android.internal.widget.LockPatternUtils;
Dianne Hackbornd6847842010-01-12 18:14:19 -080024
25import org.xmlpull.v1.XmlPullParser;
26import org.xmlpull.v1.XmlPullParserException;
27import org.xmlpull.v1.XmlSerializer;
28
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080029import android.app.Activity;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080030import android.app.admin.DeviceAdminInfo;
31import android.app.admin.DeviceAdminReceiver;
32import android.app.admin.DevicePolicyManager;
33import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080034import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080035import android.content.ComponentName;
36import android.content.Context;
37import android.content.Intent;
38import android.content.pm.PackageManager;
39import android.content.pm.ResolveInfo;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080040import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080041import android.os.Binder;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080042import android.os.IBinder;
43import android.os.IPowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080044import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080045import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080046import android.os.RemoteException;
47import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080048import android.os.SystemClock;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -070049import android.util.Slog;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080050import android.util.PrintWriterPrinter;
51import android.util.Printer;
Dianne Hackbornd6847842010-01-12 18:14:19 -080052import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080053import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080054
55import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080056import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080057import java.io.FileInputStream;
58import java.io.FileOutputStream;
59import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080060import java.io.PrintWriter;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080061import java.util.ArrayList;
62import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080063import java.util.List;
64
65/**
66 * Implementation of the device policy APIs.
67 */
68public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080069 static final String TAG = "DevicePolicyManagerService";
Konstantin Lopyrev32558232010-05-20 16:18:05 -070070
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080071 final Context mContext;
72 final MyPackageMonitor mMonitor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080073
Dianne Hackborndf83afa2010-01-20 13:37:26 -080074 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070075
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080076 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -070078 int mActivePasswordUpperCase = 0;
79 int mActivePasswordLowerCase = 0;
80 int mActivePasswordLetters = 0;
81 int mActivePasswordNumeric = 0;
82 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -070083 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -080084 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070085
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080086 int mPasswordOwner = -1;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070087
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080088 final HashMap<ComponentName, ActiveAdmin> mAdminMap
89 = new HashMap<ComponentName, ActiveAdmin>();
90 final ArrayList<ActiveAdmin> mAdminList
91 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -070092
Dianne Hackbornd6847842010-01-12 18:14:19 -080093 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -080094 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070095
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080096 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080097 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070098 int passwordHistoryLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -070099 int minimumPasswordUpperCase = 0;
100 int minimumPasswordLowerCase = 0;
101 int minimumPasswordLetters = 1;
102 int minimumPasswordNumeric = 1;
103 int minimumPasswordSymbols = 1;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700104 int minimumPasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800105 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800106 int maximumFailedPasswordsForWipe = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700107
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800108 ActiveAdmin(DeviceAdminInfo _info) {
109 info = _info;
110 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700111
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800112 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700113
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800114 void writeToXml(XmlSerializer out)
115 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800116 out.startTag(null, "policies");
117 info.writePoliciesToXml(out);
118 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800119 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
120 out.startTag(null, "password-quality");
121 out.attribute(null, "value", Integer.toString(passwordQuality));
122 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800123 if (minimumPasswordLength > 0) {
124 out.startTag(null, "min-password-length");
125 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700126 out.endTag(null, "min-password-length");
127 }
128 if(passwordHistoryLength > 0) {
129 out.startTag(null, "password-history-length");
130 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
131 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800132 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700133 if (minimumPasswordUpperCase > 0) {
134 out.startTag(null, "min-password-uppercase");
135 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
136 out.endTag(null, "min-password-uppercase");
137 }
138 if (minimumPasswordLowerCase > 0) {
139 out.startTag(null, "min-password-lowercase");
140 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
141 out.endTag(null, "min-password-lowercase");
142 }
143 if (minimumPasswordLetters > 0) {
144 out.startTag(null, "min-password-letters");
145 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
146 out.endTag(null, "min-password-letters");
147 }
148 if (minimumPasswordNumeric > 0) {
149 out.startTag(null, "min-password-numeric");
150 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
151 out.endTag(null, "min-password-numeric");
152 }
153 if (minimumPasswordSymbols > 0) {
154 out.startTag(null, "min-password-symbols");
155 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
156 out.endTag(null, "min-password-symbols");
157 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700158 if (minimumPasswordNonLetter > 0) {
159 out.startTag(null, "min-password-nonletter");
160 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
161 out.endTag(null, "min-password-nonletter");
162 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800163 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800164 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800165 out.startTag(null, "max-time-to-unlock");
166 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
167 out.endTag(null, "max-time-to-unlock");
168 }
169 if (maximumFailedPasswordsForWipe != 0) {
170 out.startTag(null, "max-failed-password-wipe");
171 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
172 out.endTag(null, "max-failed-password-wipe");
173 }
174 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700175
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800176 void readFromXml(XmlPullParser parser)
177 throws XmlPullParserException, IOException {
178 int outerDepth = parser.getDepth();
179 int type;
180 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
181 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
182 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
183 continue;
184 }
185 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800186 if ("policies".equals(tag)) {
187 info.readPoliciesFromXml(parser);
188 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800189 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800190 parser.getAttributeValue(null, "value"));
191 } else if ("min-password-length".equals(tag)) {
192 minimumPasswordLength = Integer.parseInt(
193 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700194 } else if ("password-history-length".equals(tag)) {
195 passwordHistoryLength = Integer.parseInt(
196 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700197 } else if ("min-password-uppercase".equals(tag)) {
198 minimumPasswordUpperCase = Integer.parseInt(
199 parser.getAttributeValue(null, "value"));
200 } else if ("min-password-lowercase".equals(tag)) {
201 minimumPasswordLowerCase = Integer.parseInt(
202 parser.getAttributeValue(null, "value"));
203 } else if ("min-password-letters".equals(tag)) {
204 minimumPasswordLetters = Integer.parseInt(
205 parser.getAttributeValue(null, "value"));
206 } else if ("min-password-numeric".equals(tag)) {
207 minimumPasswordNumeric = Integer.parseInt(
208 parser.getAttributeValue(null, "value"));
209 } else if ("min-password-symbols".equals(tag)) {
210 minimumPasswordSymbols = Integer.parseInt(
211 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700212 } else if ("min-password-nonletter".equals(tag)) {
213 minimumPasswordNonLetter = Integer.parseInt(
214 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800215 } else if ("max-time-to-unlock".equals(tag)) {
216 maximumTimeToUnlock = Long.parseLong(
217 parser.getAttributeValue(null, "value"));
218 } else if ("max-failed-password-wipe".equals(tag)) {
219 maximumFailedPasswordsForWipe = Integer.parseInt(
220 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800221 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700222 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800223 }
224 XmlUtils.skipCurrentTag(parser);
225 }
226 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700227
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800228 void dump(String prefix, PrintWriter pw) {
229 pw.print(prefix); pw.print("uid="); pw.println(getUid());
230 pw.print(prefix); pw.println("policies:");
231 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
232 if (pols != null) {
233 for (int i=0; i<pols.size(); i++) {
234 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
235 }
236 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700237 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700238 pw.println(Integer.toHexString(passwordQuality));
239 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800240 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700241 pw.print(prefix); pw.print("passwordHistoryLength=");
242 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700243 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
244 pw.println(minimumPasswordUpperCase);
245 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
246 pw.println(minimumPasswordLowerCase);
247 pw.print(prefix); pw.print("minimumPasswordLetters=");
248 pw.println(minimumPasswordLetters);
249 pw.print(prefix); pw.print("minimumPasswordNumeric=");
250 pw.println(minimumPasswordNumeric);
251 pw.print(prefix); pw.print("minimumPasswordSymbols=");
252 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700253 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
254 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800255 pw.print(prefix); pw.print("maximumTimeToUnlock=");
256 pw.println(maximumTimeToUnlock);
257 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
258 pw.println(maximumFailedPasswordsForWipe);
259 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800260 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700261
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800262 class MyPackageMonitor extends PackageMonitor {
263 public void onSomePackagesChanged() {
264 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800265 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800266 for (int i=mAdminList.size()-1; i>=0; i--) {
267 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700268 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800269 if (change == PACKAGE_PERMANENT_CHANGE
270 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700271 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800272 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800273 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800274 mAdminList.remove(i);
275 } else if (isPackageModified(aa.info.getPackageName())) {
276 try {
277 mContext.getPackageManager().getReceiverInfo(
278 aa.info.getComponent(), 0);
279 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700280 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800281 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800282 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800283 mAdminList.remove(i);
284 }
285 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800286 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800287 if (removed) {
288 validatePasswordOwnerLocked();
289 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800290 }
291 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800292 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700293
Dianne Hackbornd6847842010-01-12 18:14:19 -0800294 /**
295 * Instantiates the service.
296 */
297 public DevicePolicyManagerService(Context context) {
298 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800299 mMonitor = new MyPackageMonitor();
300 mMonitor.register(context, true);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800301 }
302
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800303 private IPowerManager getIPowerManager() {
304 if (mIPowerManager == null) {
305 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
306 mIPowerManager = IPowerManager.Stub.asInterface(b);
307 }
308 return mIPowerManager;
309 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700310
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800311 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800312 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800313 if (admin != null
314 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
315 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
316 return admin;
317 }
318 return null;
319 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700320
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800321 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
322 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800323 final int callingUid = Binder.getCallingUid();
324 if (who != null) {
325 ActiveAdmin admin = mAdminMap.get(who);
326 if (admin == null) {
327 throw new SecurityException("No active admin " + who);
328 }
329 if (admin.getUid() != callingUid) {
330 throw new SecurityException("Admin " + who + " is not owned by uid "
331 + Binder.getCallingUid());
332 }
333 if (!admin.info.usesPolicy(reqPolicy)) {
334 throw new SecurityException("Admin " + admin.info.getComponent()
335 + " did not specify uses-policy for: "
336 + admin.info.getTagForPolicy(reqPolicy));
337 }
338 return admin;
339 } else {
340 final int N = mAdminList.size();
341 for (int i=0; i<N; i++) {
342 ActiveAdmin admin = mAdminList.get(i);
343 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
344 return admin;
345 }
346 }
347 throw new SecurityException("No active admin owned by uid "
348 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800349 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800350 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700351
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800352 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800353 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800354 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800355 mContext.sendBroadcast(intent);
356 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700357
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800358 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800359 final int N = mAdminList.size();
360 if (N > 0) {
361 for (int i=0; i<N; i++) {
362 ActiveAdmin admin = mAdminList.get(i);
363 if (admin.info.usesPolicy(reqPolicy)) {
364 sendAdminCommandLocked(admin, action);
365 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800366 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800367 }
368 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700369
Dianne Hackbornd6847842010-01-12 18:14:19 -0800370 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800371 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
372 if (admin != null) {
373 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800374 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800375 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800376 mAdminList.remove(admin);
377 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800378 validatePasswordOwnerLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800379 }
380 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700381
Dianne Hackbornd6847842010-01-12 18:14:19 -0800382 public DeviceAdminInfo findAdmin(ComponentName adminName) {
383 Intent resolveIntent = new Intent();
384 resolveIntent.setComponent(adminName);
385 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
386 resolveIntent, PackageManager.GET_META_DATA);
387 if (infos == null || infos.size() <= 0) {
388 throw new IllegalArgumentException("Unknown admin: " + adminName);
389 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700390
Dianne Hackbornd6847842010-01-12 18:14:19 -0800391 try {
392 return new DeviceAdminInfo(mContext, infos.get(0));
393 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700394 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800395 return null;
396 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700397 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800398 return null;
399 }
400 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700401
Dianne Hackbornd6847842010-01-12 18:14:19 -0800402 private static JournaledFile makeJournaledFile() {
403 final String base = "/data/system/device_policies.xml";
404 return new JournaledFile(new File(base), new File(base + ".tmp"));
405 }
406
407 private void saveSettingsLocked() {
408 JournaledFile journal = makeJournaledFile();
409 FileOutputStream stream = null;
410 try {
411 stream = new FileOutputStream(journal.chooseForWrite(), false);
412 XmlSerializer out = new FastXmlSerializer();
413 out.setOutput(stream, "utf-8");
414 out.startDocument(null, true);
415
416 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700417
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800418 final int N = mAdminList.size();
419 for (int i=0; i<N; i++) {
420 ActiveAdmin ap = mAdminList.get(i);
421 if (ap != null) {
422 out.startTag(null, "admin");
423 out.attribute(null, "name", ap.info.getComponent().flattenToString());
424 ap.writeToXml(out);
425 out.endTag(null, "admin");
426 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800427 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700428
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800429 if (mPasswordOwner >= 0) {
430 out.startTag(null, "password-owner");
431 out.attribute(null, "value", Integer.toString(mPasswordOwner));
432 out.endTag(null, "password-owner");
433 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700434
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800435 if (mFailedPasswordAttempts != 0) {
436 out.startTag(null, "failed-password-attempts");
437 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
438 out.endTag(null, "failed-password-attempts");
439 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700440
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700441 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
442 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
443 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700444 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700445 out.startTag(null, "active-password");
446 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
447 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700448 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
449 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
450 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
451 out.attribute(null, "numeric", Integer
452 .toString(mActivePasswordNumeric));
453 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700454 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700455 out.endTag(null, "active-password");
456 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700457
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700458 out.endTag(null, "policies");
459
Dianne Hackbornd6847842010-01-12 18:14:19 -0800460 out.endDocument();
461 stream.close();
462 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700463 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800464 } catch (IOException e) {
465 try {
466 if (stream != null) {
467 stream.close();
468 }
469 } catch (IOException ex) {
470 // Ignore
471 }
472 journal.rollback();
473 }
474 }
475
Jim Miller284b62e2010-06-08 14:27:42 -0700476 private void sendChangedNotification() {
477 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
478 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
479 mContext.sendBroadcast(intent);
480 }
481
Dianne Hackbornd6847842010-01-12 18:14:19 -0800482 private void loadSettingsLocked() {
483 JournaledFile journal = makeJournaledFile();
484 FileInputStream stream = null;
485 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800486 try {
487 stream = new FileInputStream(file);
488 XmlPullParser parser = Xml.newPullParser();
489 parser.setInput(stream, null);
490
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800491 int type;
492 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
493 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800494 }
495 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800496 if (!"policies".equals(tag)) {
497 throw new XmlPullParserException(
498 "Settings do not start with policies tag: found " + tag);
499 }
500 type = parser.next();
501 int outerDepth = parser.getDepth();
502 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
503 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
504 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
505 continue;
506 }
507 tag = parser.getName();
508 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800509 String name = parser.getAttributeValue(null, "name");
510 try {
511 DeviceAdminInfo dai = findAdmin(
512 ComponentName.unflattenFromString(name));
513 if (dai != null) {
514 ActiveAdmin ap = new ActiveAdmin(dai);
515 ap.readFromXml(parser);
516 mAdminMap.put(ap.info.getComponent(), ap);
517 mAdminList.add(ap);
518 }
519 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700520 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800521 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800522 } else if ("failed-password-attempts".equals(tag)) {
523 mFailedPasswordAttempts = Integer.parseInt(
524 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800525 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800526 } else if ("password-owner".equals(tag)) {
527 mPasswordOwner = Integer.parseInt(
528 parser.getAttributeValue(null, "value"));
529 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700530 } else if ("active-password".equals(tag)) {
531 mActivePasswordQuality = Integer.parseInt(
532 parser.getAttributeValue(null, "quality"));
533 mActivePasswordLength = Integer.parseInt(
534 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700535 mActivePasswordUpperCase = Integer.parseInt(
536 parser.getAttributeValue(null, "uppercase"));
537 mActivePasswordLowerCase = Integer.parseInt(
538 parser.getAttributeValue(null, "lowercase"));
539 mActivePasswordLetters = Integer.parseInt(
540 parser.getAttributeValue(null, "letters"));
541 mActivePasswordNumeric = Integer.parseInt(
542 parser.getAttributeValue(null, "numeric"));
543 mActivePasswordSymbols = Integer.parseInt(
544 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700545 mActivePasswordNonLetter = Integer.parseInt(
546 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700547 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800548 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700549 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800550 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800551 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800552 }
553 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700554 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800555 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700556 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800557 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700558 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800559 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700560 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800561 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700562 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800563 }
564 try {
565 if (stream != null) {
566 stream.close();
567 }
568 } catch (IOException e) {
569 // Ignore
570 }
571
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700572 // Validate that what we stored for the password quality matches
573 // sufficiently what is currently set. Note that this is only
574 // a sanity check in case the two get out of sync; this should
575 // never normally happen.
576 LockPatternUtils utils = new LockPatternUtils(mContext);
577 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
578 Slog.w(TAG, "Active password quality 0x"
579 + Integer.toHexString(mActivePasswordQuality)
580 + " does not match actual quality 0x"
581 + Integer.toHexString(utils.getActivePasswordQuality()));
582 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
583 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700584 mActivePasswordUpperCase = 0;
585 mActivePasswordLowerCase = 0;
586 mActivePasswordLetters = 0;
587 mActivePasswordNumeric = 0;
588 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700589 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700590 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700591
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800592 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700593
Dianne Hackborn254cb442010-01-27 19:23:59 -0800594 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800595 if (timeMs <= 0) {
596 timeMs = Integer.MAX_VALUE;
597 }
598 try {
599 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
600 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700601 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800602 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800603 }
604
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700605 static void validateQualityConstant(int quality) {
606 switch (quality) {
607 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
608 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
609 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
610 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
611 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700612 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700613 return;
614 }
615 throw new IllegalArgumentException("Invalid quality constant: 0x"
616 + Integer.toHexString(quality));
617 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700618
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800619 void validatePasswordOwnerLocked() {
620 if (mPasswordOwner >= 0) {
621 boolean haveOwner = false;
622 for (int i=mAdminList.size()-1; i>=0; i--) {
623 if (mAdminList.get(i).getUid() == mPasswordOwner) {
624 haveOwner = true;
625 break;
626 }
627 }
628 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700629 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800630 + " no longer active; disabling");
631 mPasswordOwner = -1;
632 }
633 }
634 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700635
Dianne Hackbornd6847842010-01-12 18:14:19 -0800636 public void systemReady() {
637 synchronized (this) {
638 loadSettingsLocked();
639 }
640 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700641
Dianne Hackbornd6847842010-01-12 18:14:19 -0800642 public void setActiveAdmin(ComponentName adminReceiver) {
643 mContext.enforceCallingOrSelfPermission(
644 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700645
Dianne Hackbornd6847842010-01-12 18:14:19 -0800646 DeviceAdminInfo info = findAdmin(adminReceiver);
647 if (info == null) {
648 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
649 }
650 synchronized (this) {
651 long ident = Binder.clearCallingIdentity();
652 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800653 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
654 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800655 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800656 ActiveAdmin admin = new ActiveAdmin(info);
657 mAdminMap.put(adminReceiver, admin);
658 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800659 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800660 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800661 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800662 } finally {
663 Binder.restoreCallingIdentity(ident);
664 }
665 }
666 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700667
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800668 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800669 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800670 return getActiveAdminUncheckedLocked(adminReceiver) != null;
671 }
672 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700673
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800674 public List<ComponentName> getActiveAdmins() {
675 synchronized (this) {
676 final int N = mAdminList.size();
677 if (N <= 0) {
678 return null;
679 }
680 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
681 for (int i=0; i<N; i++) {
682 res.add(mAdminList.get(i).info.getComponent());
683 }
684 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800685 }
686 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700687
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800688 public boolean packageHasActiveAdmins(String packageName) {
689 synchronized (this) {
690 final int N = mAdminList.size();
691 for (int i=0; i<N; i++) {
692 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
693 return true;
694 }
695 }
696 return false;
697 }
698 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700699
Dianne Hackbornd6847842010-01-12 18:14:19 -0800700 public void removeActiveAdmin(ComponentName adminReceiver) {
701 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800702 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
703 if (admin == null) {
704 return;
705 }
706 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800707 mContext.enforceCallingOrSelfPermission(
708 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
709 }
710 long ident = Binder.clearCallingIdentity();
711 try {
712 removeActiveAdminLocked(adminReceiver);
713 } finally {
714 Binder.restoreCallingIdentity(ident);
715 }
716 }
717 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700718
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700719 public void setPasswordQuality(ComponentName who, int quality) {
720 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700721
Dianne Hackbornd6847842010-01-12 18:14:19 -0800722 synchronized (this) {
723 if (who == null) {
724 throw new NullPointerException("ComponentName is null");
725 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800726 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
727 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700728 if (ap.passwordQuality != quality) {
729 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800730 saveSettingsLocked();
731 }
732 }
733 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700734
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800735 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800736 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800737 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700738
Dianne Hackborn254cb442010-01-27 19:23:59 -0800739 if (who != null) {
740 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800741 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800742 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700743
Dianne Hackborn254cb442010-01-27 19:23:59 -0800744 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800745 for (int i=0; i<N; i++) {
746 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800747 if (mode < admin.passwordQuality) {
748 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800749 }
750 }
751 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800752 }
753 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700754
Dianne Hackborn254cb442010-01-27 19:23:59 -0800755 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800756 synchronized (this) {
757 if (who == null) {
758 throw new NullPointerException("ComponentName is null");
759 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800760 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
761 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800762 if (ap.minimumPasswordLength != length) {
763 ap.minimumPasswordLength = length;
764 saveSettingsLocked();
765 }
766 }
767 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700768
Dianne Hackborn254cb442010-01-27 19:23:59 -0800769 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800770 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800771 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700772
Dianne Hackborn254cb442010-01-27 19:23:59 -0800773 if (who != null) {
774 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
775 return admin != null ? admin.minimumPasswordLength : length;
776 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700777
Dianne Hackborn254cb442010-01-27 19:23:59 -0800778 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800779 for (int i=0; i<N; i++) {
780 ActiveAdmin admin = mAdminList.get(i);
781 if (length < admin.minimumPasswordLength) {
782 length = admin.minimumPasswordLength;
783 }
784 }
785 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800786 }
787 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700788
789 public void setPasswordHistoryLength(ComponentName who, int length) {
790 synchronized (this) {
791 if (who == null) {
792 throw new NullPointerException("ComponentName is null");
793 }
794 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
795 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
796 if (ap.passwordHistoryLength != length) {
797 ap.passwordHistoryLength = length;
798 saveSettingsLocked();
799 }
800 }
801 }
802
803 public int getPasswordHistoryLength(ComponentName who) {
804 synchronized (this) {
805 int length = 0;
806
807 if (who != null) {
808 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
809 return admin != null ? admin.passwordHistoryLength : length;
810 }
811
812 final int N = mAdminList.size();
813 for (int i = 0; i < N; i++) {
814 ActiveAdmin admin = mAdminList.get(i);
815 if (length < admin.passwordHistoryLength) {
816 length = admin.passwordHistoryLength;
817 }
818 }
819 return length;
820 }
821 }
822
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700823 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
824 synchronized (this) {
825 if (who == null) {
826 throw new NullPointerException("ComponentName is null");
827 }
828 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
829 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
830 if (ap.minimumPasswordUpperCase != length) {
831 ap.minimumPasswordUpperCase = length;
832 saveSettingsLocked();
833 }
834 }
835 }
836
837 public int getPasswordMinimumUpperCase(ComponentName who) {
838 synchronized (this) {
839 int length = 0;
840
841 if (who != null) {
842 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
843 return admin != null ? admin.minimumPasswordUpperCase : length;
844 }
845
846 final int N = mAdminList.size();
847 for (int i=0; i<N; i++) {
848 ActiveAdmin admin = mAdminList.get(i);
849 if (length < admin.minimumPasswordUpperCase) {
850 length = admin.minimumPasswordUpperCase;
851 }
852 }
853 return length;
854 }
855 }
856
857 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
858 synchronized (this) {
859 if (who == null) {
860 throw new NullPointerException("ComponentName is null");
861 }
862 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
863 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
864 if (ap.minimumPasswordLowerCase != length) {
865 ap.minimumPasswordLowerCase = length;
866 saveSettingsLocked();
867 }
868 }
869 }
870
871 public int getPasswordMinimumLowerCase(ComponentName who) {
872 synchronized (this) {
873 int length = 0;
874
875 if (who != null) {
876 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
877 return admin != null ? admin.minimumPasswordLowerCase : length;
878 }
879
880 final int N = mAdminList.size();
881 for (int i=0; i<N; i++) {
882 ActiveAdmin admin = mAdminList.get(i);
883 if (length < admin.minimumPasswordLowerCase) {
884 length = admin.minimumPasswordLowerCase;
885 }
886 }
887 return length;
888 }
889 }
890
891 public void setPasswordMinimumLetters(ComponentName who, int length) {
892 synchronized (this) {
893 if (who == null) {
894 throw new NullPointerException("ComponentName is null");
895 }
896 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
897 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
898 if (ap.minimumPasswordLetters != length) {
899 ap.minimumPasswordLetters = length;
900 saveSettingsLocked();
901 }
902 }
903 }
904
905 public int getPasswordMinimumLetters(ComponentName who) {
906 synchronized (this) {
907 int length = 0;
908
909 if (who != null) {
910 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
911 return admin != null ? admin.minimumPasswordLetters : length;
912 }
913
914 final int N = mAdminList.size();
915 for (int i=0; i<N; i++) {
916 ActiveAdmin admin = mAdminList.get(i);
917 if (length < admin.minimumPasswordLetters) {
918 length = admin.minimumPasswordLetters;
919 }
920 }
921 return length;
922 }
923 }
924
925 public void setPasswordMinimumNumeric(ComponentName who, int length) {
926 synchronized (this) {
927 if (who == null) {
928 throw new NullPointerException("ComponentName is null");
929 }
930 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
931 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
932 if (ap.minimumPasswordNumeric != length) {
933 ap.minimumPasswordNumeric = length;
934 saveSettingsLocked();
935 }
936 }
937 }
938
939 public int getPasswordMinimumNumeric(ComponentName who) {
940 synchronized (this) {
941 int length = 0;
942
943 if (who != null) {
944 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
945 return admin != null ? admin.minimumPasswordNumeric : length;
946 }
947
948 final int N = mAdminList.size();
949 for (int i = 0; i < N; i++) {
950 ActiveAdmin admin = mAdminList.get(i);
951 if (length < admin.minimumPasswordNumeric) {
952 length = admin.minimumPasswordNumeric;
953 }
954 }
955 return length;
956 }
957 }
958
959 public void setPasswordMinimumSymbols(ComponentName who, int length) {
960 synchronized (this) {
961 if (who == null) {
962 throw new NullPointerException("ComponentName is null");
963 }
964 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
965 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
966 if (ap.minimumPasswordSymbols != length) {
967 ap.minimumPasswordSymbols = length;
968 saveSettingsLocked();
969 }
970 }
971 }
972
973 public int getPasswordMinimumSymbols(ComponentName who) {
974 synchronized (this) {
975 int length = 0;
976
977 if (who != null) {
978 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
979 return admin != null ? admin.minimumPasswordSymbols : length;
980 }
981
982 final int N = mAdminList.size();
983 for (int i=0; i<N; i++) {
984 ActiveAdmin admin = mAdminList.get(i);
985 if (length < admin.minimumPasswordSymbols) {
986 length = admin.minimumPasswordSymbols;
987 }
988 }
989 return length;
990 }
991 }
992
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700993 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
994 synchronized (this) {
995 if (who == null) {
996 throw new NullPointerException("ComponentName is null");
997 }
998 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
999 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1000 if (ap.minimumPasswordNonLetter != length) {
1001 ap.minimumPasswordNonLetter = length;
1002 saveSettingsLocked();
1003 }
1004 }
1005 }
1006
1007 public int getPasswordMinimumNonLetter(ComponentName who) {
1008 synchronized (this) {
1009 int length = 0;
1010
1011 if (who != null) {
1012 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1013 return admin != null ? admin.minimumPasswordNonLetter : length;
1014 }
1015
1016 final int N = mAdminList.size();
1017 for (int i=0; i<N; i++) {
1018 ActiveAdmin admin = mAdminList.get(i);
1019 if (length < admin.minimumPasswordNonLetter) {
1020 length = admin.minimumPasswordNonLetter;
1021 }
1022 }
1023 return length;
1024 }
1025 }
1026
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001027 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001028 synchronized (this) {
1029 // This API can only be called by an active device admin,
1030 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001031 getActiveAdminForCallerLocked(null,
1032 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001033 if (mActivePasswordQuality < getPasswordQuality(null)
1034 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1035 return false;
1036 }
1037 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1038 return true;
1039 }
1040 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1041 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1042 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1043 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001044 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1045 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001046 }
1047 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001048
Dianne Hackbornd6847842010-01-12 18:14:19 -08001049 public int getCurrentFailedPasswordAttempts() {
1050 synchronized (this) {
1051 // This API can only be called by an active device admin,
1052 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001053 getActiveAdminForCallerLocked(null,
1054 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001055 return mFailedPasswordAttempts;
1056 }
1057 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001058
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001059 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1060 synchronized (this) {
1061 // This API can only be called by an active device admin,
1062 // so try to retrieve it to check that the caller is one.
1063 getActiveAdminForCallerLocked(who,
1064 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1065 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1066 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1067 if (ap.maximumFailedPasswordsForWipe != num) {
1068 ap.maximumFailedPasswordsForWipe = num;
1069 saveSettingsLocked();
1070 }
1071 }
1072 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001073
Dianne Hackborn254cb442010-01-27 19:23:59 -08001074 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001075 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001076 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001077
Dianne Hackborn254cb442010-01-27 19:23:59 -08001078 if (who != null) {
1079 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1080 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1081 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001082
Dianne Hackborn254cb442010-01-27 19:23:59 -08001083 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001084 for (int i=0; i<N; i++) {
1085 ActiveAdmin admin = mAdminList.get(i);
1086 if (count == 0) {
1087 count = admin.maximumFailedPasswordsForWipe;
1088 } else if (admin.maximumFailedPasswordsForWipe != 0
1089 && count > admin.maximumFailedPasswordsForWipe) {
1090 count = admin.maximumFailedPasswordsForWipe;
1091 }
1092 }
1093 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001094 }
1095 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001096
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001097 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001098 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001099 synchronized (this) {
1100 // This API can only be called by an active device admin,
1101 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001102 getActiveAdminForCallerLocked(null,
1103 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001104 quality = getPasswordQuality(null);
1105 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001106 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001107 if (realQuality < quality
1108 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001109 Slog.w(TAG, "resetPassword: password quality 0x"
1110 + Integer.toHexString(quality)
1111 + " does not meet required quality 0x"
1112 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001113 return false;
1114 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001115 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001116 }
1117 int length = getPasswordMinimumLength(null);
1118 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001119 Slog.w(TAG, "resetPassword: password length " + password.length()
1120 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001121 return false;
1122 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001123 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1124 int letters = 0;
1125 int uppercase = 0;
1126 int lowercase = 0;
1127 int numbers = 0;
1128 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001129 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001130 for (int i = 0; i < password.length(); i++) {
1131 char c = password.charAt(i);
1132 if (c >= 'A' && c <= 'Z') {
1133 letters++;
1134 uppercase++;
1135 } else if (c >= 'a' && c <= 'z') {
1136 letters++;
1137 lowercase++;
1138 } else if (c >= '0' && c <= '9') {
1139 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001140 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001141 } else {
1142 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001143 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001144 }
1145 }
1146 int neededLetters = getPasswordMinimumLetters(null);
1147 if(letters < neededLetters) {
1148 Slog.w(TAG, "resetPassword: number of letters " + letters
1149 + " does not meet required number of letters " + neededLetters);
1150 return false;
1151 }
1152 int neededNumbers = getPasswordMinimumNumeric(null);
1153 if (numbers < neededNumbers) {
1154 Slog
1155 .w(TAG, "resetPassword: number of numerical digits " + numbers
1156 + " does not meet required number of numerical digits "
1157 + neededNumbers);
1158 return false;
1159 }
1160 int neededLowerCase = getPasswordMinimumLowerCase(null);
1161 if (lowercase < neededLowerCase) {
1162 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1163 + " does not meet required number of lowercase letters "
1164 + neededLowerCase);
1165 return false;
1166 }
1167 int neededUpperCase = getPasswordMinimumUpperCase(null);
1168 if (uppercase < neededUpperCase) {
1169 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1170 + " does not meet required number of uppercase letters "
1171 + neededUpperCase);
1172 return false;
1173 }
1174 int neededSymbols = getPasswordMinimumSymbols(null);
1175 if (symbols < neededSymbols) {
1176 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1177 + " does not meet required number of special symbols " + neededSymbols);
1178 return false;
1179 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001180 int neededNonLetter = getPasswordMinimumNonLetter(null);
1181 if (nonletter < neededNonLetter) {
1182 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1183 + " does not meet required number of non-letter characters "
1184 + neededNonLetter);
1185 return false;
1186 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001187 }
1188
1189 LockPatternUtils utils = new LockPatternUtils(mContext);
1190 if(utils.checkPasswordHistory(password)) {
1191 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1192 + getPasswordHistoryLength(null) + " passwords");
1193 return false;
1194 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001195 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001196
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001197 int callingUid = Binder.getCallingUid();
1198 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001199 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001200 return false;
1201 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001202
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001203 // Don't do this with the lock held, because it is going to call
1204 // back in to the service.
1205 long ident = Binder.clearCallingIdentity();
1206 try {
1207 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001208 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001209 synchronized (this) {
1210 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1211 != 0 ? callingUid : -1;
1212 if (mPasswordOwner != newOwner) {
1213 mPasswordOwner = newOwner;
1214 saveSettingsLocked();
1215 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001216 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001217 } finally {
1218 Binder.restoreCallingIdentity(ident);
1219 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001220
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001221 return true;
1222 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001223
Dianne Hackbornd6847842010-01-12 18:14:19 -08001224 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1225 synchronized (this) {
1226 if (who == null) {
1227 throw new NullPointerException("ComponentName is null");
1228 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001229 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001230 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001231 if (ap.maximumTimeToUnlock != timeMs) {
1232 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001233
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001234 long ident = Binder.clearCallingIdentity();
1235 try {
1236 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001237
Dianne Hackborn254cb442010-01-27 19:23:59 -08001238 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001239 if (timeMs <= 0) {
1240 timeMs = Integer.MAX_VALUE;
1241 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001242
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001243 try {
1244 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1245 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001246 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001247 }
1248 } finally {
1249 Binder.restoreCallingIdentity(ident);
1250 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001251 }
1252 }
1253 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001254
Dianne Hackborn254cb442010-01-27 19:23:59 -08001255 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001256 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001257 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001258
Dianne Hackborn254cb442010-01-27 19:23:59 -08001259 if (who != null) {
1260 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1261 return admin != null ? admin.maximumTimeToUnlock : time;
1262 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001263
Dianne Hackborn254cb442010-01-27 19:23:59 -08001264 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001265 for (int i=0; i<N; i++) {
1266 ActiveAdmin admin = mAdminList.get(i);
1267 if (time == 0) {
1268 time = admin.maximumTimeToUnlock;
1269 } else if (admin.maximumTimeToUnlock != 0
1270 && time > admin.maximumTimeToUnlock) {
1271 time = admin.maximumTimeToUnlock;
1272 }
1273 }
1274 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001275 }
1276 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001277
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001278 public void lockNow() {
1279 synchronized (this) {
1280 // This API can only be called by an active device admin,
1281 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001282 getActiveAdminForCallerLocked(null,
1283 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001284 long ident = Binder.clearCallingIdentity();
1285 try {
1286 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1287 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1288 } catch (RemoteException e) {
1289 } finally {
1290 Binder.restoreCallingIdentity(ident);
1291 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001292 }
1293 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001294
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001295 void wipeDataLocked(int flags) {
1296 try {
1297 RecoverySystem.rebootWipeUserData(mContext);
1298 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001299 Slog.w(TAG, "Failed requesting data wipe", e);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001300 }
1301 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001302
Dianne Hackbornd6847842010-01-12 18:14:19 -08001303 public void wipeData(int flags) {
1304 synchronized (this) {
1305 // This API can only be called by an active device admin,
1306 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001307 getActiveAdminForCallerLocked(null,
1308 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001309 long ident = Binder.clearCallingIdentity();
1310 try {
1311 wipeDataLocked(flags);
1312 } finally {
1313 Binder.restoreCallingIdentity(ident);
1314 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001315 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001316 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001317
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001318 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1319 mContext.enforceCallingOrSelfPermission(
1320 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001321
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001322 synchronized (this) {
1323 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1324 if (admin == null) {
1325 try {
1326 result.sendResult(null);
1327 } catch (RemoteException e) {
1328 }
1329 return;
1330 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001331 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001332 intent.setComponent(admin.info.getComponent());
1333 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1334 @Override
1335 public void onReceive(Context context, Intent intent) {
1336 try {
1337 result.sendResult(getResultExtras(false));
1338 } catch (RemoteException e) {
1339 }
1340 }
1341 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001342 }
1343 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001344
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001345 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001346 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001347 mContext.enforceCallingOrSelfPermission(
1348 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001349
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001350 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001351
Dianne Hackbornd6847842010-01-12 18:14:19 -08001352 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001353 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001354 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1355 || mActivePasswordUpperCase != uppercase
1356 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001357 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001358 long ident = Binder.clearCallingIdentity();
1359 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001360 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001361 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001362 mActivePasswordLetters = letters;
1363 mActivePasswordLowerCase = lowercase;
1364 mActivePasswordUpperCase = uppercase;
1365 mActivePasswordNumeric = numbers;
1366 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001367 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001368 mFailedPasswordAttempts = 0;
1369 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001370 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001371 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001372 } finally {
1373 Binder.restoreCallingIdentity(ident);
1374 }
1375 }
1376 }
1377 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001378
Dianne Hackbornd6847842010-01-12 18:14:19 -08001379 public void reportFailedPasswordAttempt() {
1380 mContext.enforceCallingOrSelfPermission(
1381 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001382
Dianne Hackbornd6847842010-01-12 18:14:19 -08001383 synchronized (this) {
1384 long ident = Binder.clearCallingIdentity();
1385 try {
1386 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001387 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001388 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001389 if (max > 0 && mFailedPasswordAttempts >= max) {
1390 wipeDataLocked(0);
1391 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001392 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001393 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001394 } finally {
1395 Binder.restoreCallingIdentity(ident);
1396 }
1397 }
1398 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001399
Dianne Hackbornd6847842010-01-12 18:14:19 -08001400 public void reportSuccessfulPasswordAttempt() {
1401 mContext.enforceCallingOrSelfPermission(
1402 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001403
Dianne Hackbornd6847842010-01-12 18:14:19 -08001404 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001405 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001406 long ident = Binder.clearCallingIdentity();
1407 try {
1408 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001409 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001410 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001411 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001412 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001413 } finally {
1414 Binder.restoreCallingIdentity(ident);
1415 }
1416 }
1417 }
1418 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001419
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001420 @Override
1421 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1422 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1423 != PackageManager.PERMISSION_GRANTED) {
1424
1425 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1426 + Binder.getCallingPid()
1427 + ", uid=" + Binder.getCallingUid());
1428 return;
1429 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001430
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001431 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001432
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001433 synchronized (this) {
1434 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001435
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001436 p.println(" Enabled Device Admins:");
1437 final int N = mAdminList.size();
1438 for (int i=0; i<N; i++) {
1439 ActiveAdmin ap = mAdminList.get(i);
1440 if (ap != null) {
1441 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1442 pw.println(":");
1443 ap.dump(" ", pw);
1444 }
1445 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001446
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001447 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001448 pw.print(" mActivePasswordQuality=0x");
1449 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001450 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001451 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1452 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1453 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1454 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1455 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001456 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001457 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1458 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1459 }
1460 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001461}