blob: d2add10b58a083b660d1c5bc71c818ff04906764 [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;
Dianne Hackbornd6847842010-01-12 18:14:19 -080083 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070084
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080085 int mPasswordOwner = -1;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070086
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080087 final HashMap<ComponentName, ActiveAdmin> mAdminMap
88 = new HashMap<ComponentName, ActiveAdmin>();
89 final ArrayList<ActiveAdmin> mAdminList
90 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -070091
Dianne Hackbornd6847842010-01-12 18:14:19 -080092 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -080093 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070094
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080095 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080096 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070097 int passwordHistoryLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -070098 int minimumPasswordUpperCase = 0;
99 int minimumPasswordLowerCase = 0;
100 int minimumPasswordLetters = 1;
101 int minimumPasswordNumeric = 1;
102 int minimumPasswordSymbols = 1;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800103 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800104 int maximumFailedPasswordsForWipe = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700105
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800106 ActiveAdmin(DeviceAdminInfo _info) {
107 info = _info;
108 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700109
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800110 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700111
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800112 void writeToXml(XmlSerializer out)
113 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800114 out.startTag(null, "policies");
115 info.writePoliciesToXml(out);
116 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800117 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
118 out.startTag(null, "password-quality");
119 out.attribute(null, "value", Integer.toString(passwordQuality));
120 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800121 if (minimumPasswordLength > 0) {
122 out.startTag(null, "min-password-length");
123 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700124 out.endTag(null, "min-password-length");
125 }
126 if(passwordHistoryLength > 0) {
127 out.startTag(null, "password-history-length");
128 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
129 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800130 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700131 if (minimumPasswordUpperCase > 0) {
132 out.startTag(null, "min-password-uppercase");
133 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
134 out.endTag(null, "min-password-uppercase");
135 }
136 if (minimumPasswordLowerCase > 0) {
137 out.startTag(null, "min-password-lowercase");
138 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
139 out.endTag(null, "min-password-lowercase");
140 }
141 if (minimumPasswordLetters > 0) {
142 out.startTag(null, "min-password-letters");
143 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
144 out.endTag(null, "min-password-letters");
145 }
146 if (minimumPasswordNumeric > 0) {
147 out.startTag(null, "min-password-numeric");
148 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
149 out.endTag(null, "min-password-numeric");
150 }
151 if (minimumPasswordSymbols > 0) {
152 out.startTag(null, "min-password-symbols");
153 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
154 out.endTag(null, "min-password-symbols");
155 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800156 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800157 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800158 out.startTag(null, "max-time-to-unlock");
159 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
160 out.endTag(null, "max-time-to-unlock");
161 }
162 if (maximumFailedPasswordsForWipe != 0) {
163 out.startTag(null, "max-failed-password-wipe");
164 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
165 out.endTag(null, "max-failed-password-wipe");
166 }
167 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700168
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800169 void readFromXml(XmlPullParser parser)
170 throws XmlPullParserException, IOException {
171 int outerDepth = parser.getDepth();
172 int type;
173 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
174 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
175 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
176 continue;
177 }
178 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800179 if ("policies".equals(tag)) {
180 info.readPoliciesFromXml(parser);
181 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800182 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800183 parser.getAttributeValue(null, "value"));
184 } else if ("min-password-length".equals(tag)) {
185 minimumPasswordLength = Integer.parseInt(
186 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700187 } else if ("password-history-length".equals(tag)) {
188 passwordHistoryLength = Integer.parseInt(
189 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700190 } else if ("min-password-uppercase".equals(tag)) {
191 minimumPasswordUpperCase = Integer.parseInt(
192 parser.getAttributeValue(null, "value"));
193 } else if ("min-password-lowercase".equals(tag)) {
194 minimumPasswordLowerCase = Integer.parseInt(
195 parser.getAttributeValue(null, "value"));
196 } else if ("min-password-letters".equals(tag)) {
197 minimumPasswordLetters = Integer.parseInt(
198 parser.getAttributeValue(null, "value"));
199 } else if ("min-password-numeric".equals(tag)) {
200 minimumPasswordNumeric = Integer.parseInt(
201 parser.getAttributeValue(null, "value"));
202 } else if ("min-password-symbols".equals(tag)) {
203 minimumPasswordSymbols = Integer.parseInt(
204 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800205 } else if ("max-time-to-unlock".equals(tag)) {
206 maximumTimeToUnlock = Long.parseLong(
207 parser.getAttributeValue(null, "value"));
208 } else if ("max-failed-password-wipe".equals(tag)) {
209 maximumFailedPasswordsForWipe = Integer.parseInt(
210 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800211 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700212 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800213 }
214 XmlUtils.skipCurrentTag(parser);
215 }
216 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700217
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800218 void dump(String prefix, PrintWriter pw) {
219 pw.print(prefix); pw.print("uid="); pw.println(getUid());
220 pw.print(prefix); pw.println("policies:");
221 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
222 if (pols != null) {
223 for (int i=0; i<pols.size(); i++) {
224 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
225 }
226 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700227 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700228 pw.println(Integer.toHexString(passwordQuality));
229 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800230 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700231 pw.print(prefix); pw.print("passwordHistoryLength=");
232 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700233 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
234 pw.println(minimumPasswordUpperCase);
235 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
236 pw.println(minimumPasswordLowerCase);
237 pw.print(prefix); pw.print("minimumPasswordLetters=");
238 pw.println(minimumPasswordLetters);
239 pw.print(prefix); pw.print("minimumPasswordNumeric=");
240 pw.println(minimumPasswordNumeric);
241 pw.print(prefix); pw.print("minimumPasswordSymbols=");
242 pw.println(minimumPasswordSymbols);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800243 pw.print(prefix); pw.print("maximumTimeToUnlock=");
244 pw.println(maximumTimeToUnlock);
245 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
246 pw.println(maximumFailedPasswordsForWipe);
247 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800248 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700249
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800250 class MyPackageMonitor extends PackageMonitor {
251 public void onSomePackagesChanged() {
252 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800253 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800254 for (int i=mAdminList.size()-1; i>=0; i--) {
255 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700256 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800257 if (change == PACKAGE_PERMANENT_CHANGE
258 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700259 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800260 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800261 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800262 mAdminList.remove(i);
263 } else if (isPackageModified(aa.info.getPackageName())) {
264 try {
265 mContext.getPackageManager().getReceiverInfo(
266 aa.info.getComponent(), 0);
267 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700268 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800269 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800270 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800271 mAdminList.remove(i);
272 }
273 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800274 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800275 if (removed) {
276 validatePasswordOwnerLocked();
277 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800278 }
279 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800280 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700281
Dianne Hackbornd6847842010-01-12 18:14:19 -0800282 /**
283 * Instantiates the service.
284 */
285 public DevicePolicyManagerService(Context context) {
286 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800287 mMonitor = new MyPackageMonitor();
288 mMonitor.register(context, true);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800289 }
290
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800291 private IPowerManager getIPowerManager() {
292 if (mIPowerManager == null) {
293 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
294 mIPowerManager = IPowerManager.Stub.asInterface(b);
295 }
296 return mIPowerManager;
297 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700298
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800299 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800300 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800301 if (admin != null
302 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
303 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
304 return admin;
305 }
306 return null;
307 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700308
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800309 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
310 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800311 final int callingUid = Binder.getCallingUid();
312 if (who != null) {
313 ActiveAdmin admin = mAdminMap.get(who);
314 if (admin == null) {
315 throw new SecurityException("No active admin " + who);
316 }
317 if (admin.getUid() != callingUid) {
318 throw new SecurityException("Admin " + who + " is not owned by uid "
319 + Binder.getCallingUid());
320 }
321 if (!admin.info.usesPolicy(reqPolicy)) {
322 throw new SecurityException("Admin " + admin.info.getComponent()
323 + " did not specify uses-policy for: "
324 + admin.info.getTagForPolicy(reqPolicy));
325 }
326 return admin;
327 } else {
328 final int N = mAdminList.size();
329 for (int i=0; i<N; i++) {
330 ActiveAdmin admin = mAdminList.get(i);
331 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
332 return admin;
333 }
334 }
335 throw new SecurityException("No active admin owned by uid "
336 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800337 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800338 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700339
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800340 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800341 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800342 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800343 mContext.sendBroadcast(intent);
344 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700345
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800346 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800347 final int N = mAdminList.size();
348 if (N > 0) {
349 for (int i=0; i<N; i++) {
350 ActiveAdmin admin = mAdminList.get(i);
351 if (admin.info.usesPolicy(reqPolicy)) {
352 sendAdminCommandLocked(admin, action);
353 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800354 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800355 }
356 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700357
Dianne Hackbornd6847842010-01-12 18:14:19 -0800358 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800359 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
360 if (admin != null) {
361 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800362 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800363 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800364 mAdminList.remove(admin);
365 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800366 validatePasswordOwnerLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800367 }
368 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700369
Dianne Hackbornd6847842010-01-12 18:14:19 -0800370 public DeviceAdminInfo findAdmin(ComponentName adminName) {
371 Intent resolveIntent = new Intent();
372 resolveIntent.setComponent(adminName);
373 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
374 resolveIntent, PackageManager.GET_META_DATA);
375 if (infos == null || infos.size() <= 0) {
376 throw new IllegalArgumentException("Unknown admin: " + adminName);
377 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700378
Dianne Hackbornd6847842010-01-12 18:14:19 -0800379 try {
380 return new DeviceAdminInfo(mContext, infos.get(0));
381 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700382 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800383 return null;
384 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700385 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800386 return null;
387 }
388 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700389
Dianne Hackbornd6847842010-01-12 18:14:19 -0800390 private static JournaledFile makeJournaledFile() {
391 final String base = "/data/system/device_policies.xml";
392 return new JournaledFile(new File(base), new File(base + ".tmp"));
393 }
394
395 private void saveSettingsLocked() {
396 JournaledFile journal = makeJournaledFile();
397 FileOutputStream stream = null;
398 try {
399 stream = new FileOutputStream(journal.chooseForWrite(), false);
400 XmlSerializer out = new FastXmlSerializer();
401 out.setOutput(stream, "utf-8");
402 out.startDocument(null, true);
403
404 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700405
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800406 final int N = mAdminList.size();
407 for (int i=0; i<N; i++) {
408 ActiveAdmin ap = mAdminList.get(i);
409 if (ap != null) {
410 out.startTag(null, "admin");
411 out.attribute(null, "name", ap.info.getComponent().flattenToString());
412 ap.writeToXml(out);
413 out.endTag(null, "admin");
414 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800415 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700416
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800417 if (mPasswordOwner >= 0) {
418 out.startTag(null, "password-owner");
419 out.attribute(null, "value", Integer.toString(mPasswordOwner));
420 out.endTag(null, "password-owner");
421 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700422
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800423 if (mFailedPasswordAttempts != 0) {
424 out.startTag(null, "failed-password-attempts");
425 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
426 out.endTag(null, "failed-password-attempts");
427 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700428
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700429 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
430 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
431 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
432 || mActivePasswordSymbols != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700433 out.startTag(null, "active-password");
434 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
435 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700436 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
437 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
438 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
439 out.attribute(null, "numeric", Integer
440 .toString(mActivePasswordNumeric));
441 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700442 out.endTag(null, "active-password");
443 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700444
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700445 out.endTag(null, "policies");
446
Dianne Hackbornd6847842010-01-12 18:14:19 -0800447 out.endDocument();
448 stream.close();
449 journal.commit();
450 } catch (IOException e) {
451 try {
452 if (stream != null) {
453 stream.close();
454 }
455 } catch (IOException ex) {
456 // Ignore
457 }
458 journal.rollback();
459 }
460 }
461
462 private void loadSettingsLocked() {
463 JournaledFile journal = makeJournaledFile();
464 FileInputStream stream = null;
465 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800466 try {
467 stream = new FileInputStream(file);
468 XmlPullParser parser = Xml.newPullParser();
469 parser.setInput(stream, null);
470
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800471 int type;
472 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
473 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800474 }
475 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800476 if (!"policies".equals(tag)) {
477 throw new XmlPullParserException(
478 "Settings do not start with policies tag: found " + tag);
479 }
480 type = parser.next();
481 int outerDepth = parser.getDepth();
482 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
483 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
484 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
485 continue;
486 }
487 tag = parser.getName();
488 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800489 String name = parser.getAttributeValue(null, "name");
490 try {
491 DeviceAdminInfo dai = findAdmin(
492 ComponentName.unflattenFromString(name));
493 if (dai != null) {
494 ActiveAdmin ap = new ActiveAdmin(dai);
495 ap.readFromXml(parser);
496 mAdminMap.put(ap.info.getComponent(), ap);
497 mAdminList.add(ap);
498 }
499 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700500 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800501 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800502 } else if ("failed-password-attempts".equals(tag)) {
503 mFailedPasswordAttempts = Integer.parseInt(
504 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800505 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800506 } else if ("password-owner".equals(tag)) {
507 mPasswordOwner = Integer.parseInt(
508 parser.getAttributeValue(null, "value"));
509 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700510 } else if ("active-password".equals(tag)) {
511 mActivePasswordQuality = Integer.parseInt(
512 parser.getAttributeValue(null, "quality"));
513 mActivePasswordLength = Integer.parseInt(
514 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700515 mActivePasswordUpperCase = Integer.parseInt(
516 parser.getAttributeValue(null, "uppercase"));
517 mActivePasswordLowerCase = Integer.parseInt(
518 parser.getAttributeValue(null, "lowercase"));
519 mActivePasswordLetters = Integer.parseInt(
520 parser.getAttributeValue(null, "letters"));
521 mActivePasswordNumeric = Integer.parseInt(
522 parser.getAttributeValue(null, "numeric"));
523 mActivePasswordSymbols = Integer.parseInt(
524 parser.getAttributeValue(null, "symbols"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700525 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800526 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700527 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800528 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800529 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800530 }
531 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700532 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800533 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700534 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800535 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700536 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800537 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700538 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800539 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700540 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800541 }
542 try {
543 if (stream != null) {
544 stream.close();
545 }
546 } catch (IOException e) {
547 // Ignore
548 }
549
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700550 // Validate that what we stored for the password quality matches
551 // sufficiently what is currently set. Note that this is only
552 // a sanity check in case the two get out of sync; this should
553 // never normally happen.
554 LockPatternUtils utils = new LockPatternUtils(mContext);
555 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
556 Slog.w(TAG, "Active password quality 0x"
557 + Integer.toHexString(mActivePasswordQuality)
558 + " does not match actual quality 0x"
559 + Integer.toHexString(utils.getActivePasswordQuality()));
560 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
561 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700562 mActivePasswordUpperCase = 0;
563 mActivePasswordLowerCase = 0;
564 mActivePasswordLetters = 0;
565 mActivePasswordNumeric = 0;
566 mActivePasswordSymbols = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700567 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700568
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800569 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700570
Dianne Hackborn254cb442010-01-27 19:23:59 -0800571 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800572 if (timeMs <= 0) {
573 timeMs = Integer.MAX_VALUE;
574 }
575 try {
576 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
577 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700578 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800579 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800580 }
581
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700582 static void validateQualityConstant(int quality) {
583 switch (quality) {
584 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
585 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
586 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
587 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
588 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700589 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700590 return;
591 }
592 throw new IllegalArgumentException("Invalid quality constant: 0x"
593 + Integer.toHexString(quality));
594 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700595
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800596 void validatePasswordOwnerLocked() {
597 if (mPasswordOwner >= 0) {
598 boolean haveOwner = false;
599 for (int i=mAdminList.size()-1; i>=0; i--) {
600 if (mAdminList.get(i).getUid() == mPasswordOwner) {
601 haveOwner = true;
602 break;
603 }
604 }
605 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700606 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800607 + " no longer active; disabling");
608 mPasswordOwner = -1;
609 }
610 }
611 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700612
Dianne Hackbornd6847842010-01-12 18:14:19 -0800613 public void systemReady() {
614 synchronized (this) {
615 loadSettingsLocked();
616 }
617 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700618
Dianne Hackbornd6847842010-01-12 18:14:19 -0800619 public void setActiveAdmin(ComponentName adminReceiver) {
620 mContext.enforceCallingOrSelfPermission(
621 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700622
Dianne Hackbornd6847842010-01-12 18:14:19 -0800623 DeviceAdminInfo info = findAdmin(adminReceiver);
624 if (info == null) {
625 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
626 }
627 synchronized (this) {
628 long ident = Binder.clearCallingIdentity();
629 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800630 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
631 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800632 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800633 ActiveAdmin admin = new ActiveAdmin(info);
634 mAdminMap.put(adminReceiver, admin);
635 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800636 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800637 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800638 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800639 } finally {
640 Binder.restoreCallingIdentity(ident);
641 }
642 }
643 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700644
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800645 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800646 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800647 return getActiveAdminUncheckedLocked(adminReceiver) != null;
648 }
649 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700650
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800651 public List<ComponentName> getActiveAdmins() {
652 synchronized (this) {
653 final int N = mAdminList.size();
654 if (N <= 0) {
655 return null;
656 }
657 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
658 for (int i=0; i<N; i++) {
659 res.add(mAdminList.get(i).info.getComponent());
660 }
661 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800662 }
663 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700664
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800665 public boolean packageHasActiveAdmins(String packageName) {
666 synchronized (this) {
667 final int N = mAdminList.size();
668 for (int i=0; i<N; i++) {
669 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
670 return true;
671 }
672 }
673 return false;
674 }
675 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700676
Dianne Hackbornd6847842010-01-12 18:14:19 -0800677 public void removeActiveAdmin(ComponentName adminReceiver) {
678 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800679 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
680 if (admin == null) {
681 return;
682 }
683 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800684 mContext.enforceCallingOrSelfPermission(
685 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
686 }
687 long ident = Binder.clearCallingIdentity();
688 try {
689 removeActiveAdminLocked(adminReceiver);
690 } finally {
691 Binder.restoreCallingIdentity(ident);
692 }
693 }
694 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700695
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700696 public void setPasswordQuality(ComponentName who, int quality) {
697 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700698
Dianne Hackbornd6847842010-01-12 18:14:19 -0800699 synchronized (this) {
700 if (who == null) {
701 throw new NullPointerException("ComponentName is null");
702 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800703 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
704 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700705 if (ap.passwordQuality != quality) {
706 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800707 saveSettingsLocked();
708 }
709 }
710 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700711
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800712 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800713 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800714 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700715
Dianne Hackborn254cb442010-01-27 19:23:59 -0800716 if (who != null) {
717 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800718 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800719 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700720
Dianne Hackborn254cb442010-01-27 19:23:59 -0800721 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800722 for (int i=0; i<N; i++) {
723 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800724 if (mode < admin.passwordQuality) {
725 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800726 }
727 }
728 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800729 }
730 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700731
Dianne Hackborn254cb442010-01-27 19:23:59 -0800732 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800733 synchronized (this) {
734 if (who == null) {
735 throw new NullPointerException("ComponentName is null");
736 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800737 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
738 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800739 if (ap.minimumPasswordLength != length) {
740 ap.minimumPasswordLength = length;
741 saveSettingsLocked();
742 }
743 }
744 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700745
Dianne Hackborn254cb442010-01-27 19:23:59 -0800746 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800747 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800748 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700749
Dianne Hackborn254cb442010-01-27 19:23:59 -0800750 if (who != null) {
751 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
752 return admin != null ? admin.minimumPasswordLength : length;
753 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700754
Dianne Hackborn254cb442010-01-27 19:23:59 -0800755 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800756 for (int i=0; i<N; i++) {
757 ActiveAdmin admin = mAdminList.get(i);
758 if (length < admin.minimumPasswordLength) {
759 length = admin.minimumPasswordLength;
760 }
761 }
762 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800763 }
764 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700765
766 public void setPasswordHistoryLength(ComponentName who, int length) {
767 synchronized (this) {
768 if (who == null) {
769 throw new NullPointerException("ComponentName is null");
770 }
771 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
772 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
773 if (ap.passwordHistoryLength != length) {
774 ap.passwordHistoryLength = length;
775 saveSettingsLocked();
776 }
777 }
778 }
779
780 public int getPasswordHistoryLength(ComponentName who) {
781 synchronized (this) {
782 int length = 0;
783
784 if (who != null) {
785 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
786 return admin != null ? admin.passwordHistoryLength : length;
787 }
788
789 final int N = mAdminList.size();
790 for (int i = 0; i < N; i++) {
791 ActiveAdmin admin = mAdminList.get(i);
792 if (length < admin.passwordHistoryLength) {
793 length = admin.passwordHistoryLength;
794 }
795 }
796 return length;
797 }
798 }
799
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700800 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
801 synchronized (this) {
802 if (who == null) {
803 throw new NullPointerException("ComponentName is null");
804 }
805 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
806 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
807 if (ap.minimumPasswordUpperCase != length) {
808 ap.minimumPasswordUpperCase = length;
809 saveSettingsLocked();
810 }
811 }
812 }
813
814 public int getPasswordMinimumUpperCase(ComponentName who) {
815 synchronized (this) {
816 int length = 0;
817
818 if (who != null) {
819 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
820 return admin != null ? admin.minimumPasswordUpperCase : length;
821 }
822
823 final int N = mAdminList.size();
824 for (int i=0; i<N; i++) {
825 ActiveAdmin admin = mAdminList.get(i);
826 if (length < admin.minimumPasswordUpperCase) {
827 length = admin.minimumPasswordUpperCase;
828 }
829 }
830 return length;
831 }
832 }
833
834 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
835 synchronized (this) {
836 if (who == null) {
837 throw new NullPointerException("ComponentName is null");
838 }
839 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
840 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
841 if (ap.minimumPasswordLowerCase != length) {
842 ap.minimumPasswordLowerCase = length;
843 saveSettingsLocked();
844 }
845 }
846 }
847
848 public int getPasswordMinimumLowerCase(ComponentName who) {
849 synchronized (this) {
850 int length = 0;
851
852 if (who != null) {
853 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
854 return admin != null ? admin.minimumPasswordLowerCase : length;
855 }
856
857 final int N = mAdminList.size();
858 for (int i=0; i<N; i++) {
859 ActiveAdmin admin = mAdminList.get(i);
860 if (length < admin.minimumPasswordLowerCase) {
861 length = admin.minimumPasswordLowerCase;
862 }
863 }
864 return length;
865 }
866 }
867
868 public void setPasswordMinimumLetters(ComponentName who, int length) {
869 synchronized (this) {
870 if (who == null) {
871 throw new NullPointerException("ComponentName is null");
872 }
873 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
874 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
875 if (ap.minimumPasswordLetters != length) {
876 ap.minimumPasswordLetters = length;
877 saveSettingsLocked();
878 }
879 }
880 }
881
882 public int getPasswordMinimumLetters(ComponentName who) {
883 synchronized (this) {
884 int length = 0;
885
886 if (who != null) {
887 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
888 return admin != null ? admin.minimumPasswordLetters : length;
889 }
890
891 final int N = mAdminList.size();
892 for (int i=0; i<N; i++) {
893 ActiveAdmin admin = mAdminList.get(i);
894 if (length < admin.minimumPasswordLetters) {
895 length = admin.minimumPasswordLetters;
896 }
897 }
898 return length;
899 }
900 }
901
902 public void setPasswordMinimumNumeric(ComponentName who, int length) {
903 synchronized (this) {
904 if (who == null) {
905 throw new NullPointerException("ComponentName is null");
906 }
907 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
908 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
909 if (ap.minimumPasswordNumeric != length) {
910 ap.minimumPasswordNumeric = length;
911 saveSettingsLocked();
912 }
913 }
914 }
915
916 public int getPasswordMinimumNumeric(ComponentName who) {
917 synchronized (this) {
918 int length = 0;
919
920 if (who != null) {
921 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
922 return admin != null ? admin.minimumPasswordNumeric : length;
923 }
924
925 final int N = mAdminList.size();
926 for (int i = 0; i < N; i++) {
927 ActiveAdmin admin = mAdminList.get(i);
928 if (length < admin.minimumPasswordNumeric) {
929 length = admin.minimumPasswordNumeric;
930 }
931 }
932 return length;
933 }
934 }
935
936 public void setPasswordMinimumSymbols(ComponentName who, int length) {
937 synchronized (this) {
938 if (who == null) {
939 throw new NullPointerException("ComponentName is null");
940 }
941 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
942 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
943 if (ap.minimumPasswordSymbols != length) {
944 ap.minimumPasswordSymbols = length;
945 saveSettingsLocked();
946 }
947 }
948 }
949
950 public int getPasswordMinimumSymbols(ComponentName who) {
951 synchronized (this) {
952 int length = 0;
953
954 if (who != null) {
955 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
956 return admin != null ? admin.minimumPasswordSymbols : length;
957 }
958
959 final int N = mAdminList.size();
960 for (int i=0; i<N; i++) {
961 ActiveAdmin admin = mAdminList.get(i);
962 if (length < admin.minimumPasswordSymbols) {
963 length = admin.minimumPasswordSymbols;
964 }
965 }
966 return length;
967 }
968 }
969
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800970 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800971 synchronized (this) {
972 // This API can only be called by an active device admin,
973 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800974 getActiveAdminForCallerLocked(null,
975 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700976 if (mActivePasswordQuality < getPasswordQuality(null)
977 || mActivePasswordLength < getPasswordMinimumLength(null)) {
978 return false;
979 }
980 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
981 return true;
982 }
983 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
984 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
985 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
986 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
987 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800988 }
989 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700990
Dianne Hackbornd6847842010-01-12 18:14:19 -0800991 public int getCurrentFailedPasswordAttempts() {
992 synchronized (this) {
993 // This API can only be called by an active device admin,
994 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800995 getActiveAdminForCallerLocked(null,
996 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800997 return mFailedPasswordAttempts;
998 }
999 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001000
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001001 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1002 synchronized (this) {
1003 // This API can only be called by an active device admin,
1004 // so try to retrieve it to check that the caller is one.
1005 getActiveAdminForCallerLocked(who,
1006 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1007 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1008 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1009 if (ap.maximumFailedPasswordsForWipe != num) {
1010 ap.maximumFailedPasswordsForWipe = num;
1011 saveSettingsLocked();
1012 }
1013 }
1014 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001015
Dianne Hackborn254cb442010-01-27 19:23:59 -08001016 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001017 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001018 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001019
Dianne Hackborn254cb442010-01-27 19:23:59 -08001020 if (who != null) {
1021 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1022 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1023 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001024
Dianne Hackborn254cb442010-01-27 19:23:59 -08001025 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001026 for (int i=0; i<N; i++) {
1027 ActiveAdmin admin = mAdminList.get(i);
1028 if (count == 0) {
1029 count = admin.maximumFailedPasswordsForWipe;
1030 } else if (admin.maximumFailedPasswordsForWipe != 0
1031 && count > admin.maximumFailedPasswordsForWipe) {
1032 count = admin.maximumFailedPasswordsForWipe;
1033 }
1034 }
1035 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001036 }
1037 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001038
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001039 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001040 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001041 synchronized (this) {
1042 // This API can only be called by an active device admin,
1043 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001044 getActiveAdminForCallerLocked(null,
1045 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001046 quality = getPasswordQuality(null);
1047 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001048 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001049 if (realQuality < quality
1050 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001051 Slog.w(TAG, "resetPassword: password quality 0x"
1052 + Integer.toHexString(quality)
1053 + " does not meet required quality 0x"
1054 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001055 return false;
1056 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001057 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001058 }
1059 int length = getPasswordMinimumLength(null);
1060 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001061 Slog.w(TAG, "resetPassword: password length " + password.length()
1062 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001063 return false;
1064 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001065 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1066 int letters = 0;
1067 int uppercase = 0;
1068 int lowercase = 0;
1069 int numbers = 0;
1070 int symbols = 0;
1071 for (int i = 0; i < password.length(); i++) {
1072 char c = password.charAt(i);
1073 if (c >= 'A' && c <= 'Z') {
1074 letters++;
1075 uppercase++;
1076 } else if (c >= 'a' && c <= 'z') {
1077 letters++;
1078 lowercase++;
1079 } else if (c >= '0' && c <= '9') {
1080 numbers++;
1081 } else {
1082 symbols++;
1083 }
1084 }
1085 int neededLetters = getPasswordMinimumLetters(null);
1086 if(letters < neededLetters) {
1087 Slog.w(TAG, "resetPassword: number of letters " + letters
1088 + " does not meet required number of letters " + neededLetters);
1089 return false;
1090 }
1091 int neededNumbers = getPasswordMinimumNumeric(null);
1092 if (numbers < neededNumbers) {
1093 Slog
1094 .w(TAG, "resetPassword: number of numerical digits " + numbers
1095 + " does not meet required number of numerical digits "
1096 + neededNumbers);
1097 return false;
1098 }
1099 int neededLowerCase = getPasswordMinimumLowerCase(null);
1100 if (lowercase < neededLowerCase) {
1101 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1102 + " does not meet required number of lowercase letters "
1103 + neededLowerCase);
1104 return false;
1105 }
1106 int neededUpperCase = getPasswordMinimumUpperCase(null);
1107 if (uppercase < neededUpperCase) {
1108 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1109 + " does not meet required number of uppercase letters "
1110 + neededUpperCase);
1111 return false;
1112 }
1113 int neededSymbols = getPasswordMinimumSymbols(null);
1114 if (symbols < neededSymbols) {
1115 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1116 + " does not meet required number of special symbols " + neededSymbols);
1117 return false;
1118 }
1119 }
1120
1121 LockPatternUtils utils = new LockPatternUtils(mContext);
1122 if(utils.checkPasswordHistory(password)) {
1123 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1124 + getPasswordHistoryLength(null) + " passwords");
1125 return false;
1126 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001127 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001128
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001129 int callingUid = Binder.getCallingUid();
1130 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001131 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001132 return false;
1133 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001134
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001135 // Don't do this with the lock held, because it is going to call
1136 // back in to the service.
1137 long ident = Binder.clearCallingIdentity();
1138 try {
1139 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001140 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001141 synchronized (this) {
1142 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1143 != 0 ? callingUid : -1;
1144 if (mPasswordOwner != newOwner) {
1145 mPasswordOwner = newOwner;
1146 saveSettingsLocked();
1147 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001148 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001149 } finally {
1150 Binder.restoreCallingIdentity(ident);
1151 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001152
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001153 return true;
1154 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001155
Dianne Hackbornd6847842010-01-12 18:14:19 -08001156 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1157 synchronized (this) {
1158 if (who == null) {
1159 throw new NullPointerException("ComponentName is null");
1160 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001161 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001162 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001163 if (ap.maximumTimeToUnlock != timeMs) {
1164 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001165
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001166 long ident = Binder.clearCallingIdentity();
1167 try {
1168 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001169
Dianne Hackborn254cb442010-01-27 19:23:59 -08001170 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001171 if (timeMs <= 0) {
1172 timeMs = Integer.MAX_VALUE;
1173 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001174
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001175 try {
1176 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1177 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001178 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001179 }
1180 } finally {
1181 Binder.restoreCallingIdentity(ident);
1182 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001183 }
1184 }
1185 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001186
Dianne Hackborn254cb442010-01-27 19:23:59 -08001187 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001188 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001189 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001190
Dianne Hackborn254cb442010-01-27 19:23:59 -08001191 if (who != null) {
1192 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1193 return admin != null ? admin.maximumTimeToUnlock : time;
1194 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001195
Dianne Hackborn254cb442010-01-27 19:23:59 -08001196 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001197 for (int i=0; i<N; i++) {
1198 ActiveAdmin admin = mAdminList.get(i);
1199 if (time == 0) {
1200 time = admin.maximumTimeToUnlock;
1201 } else if (admin.maximumTimeToUnlock != 0
1202 && time > admin.maximumTimeToUnlock) {
1203 time = admin.maximumTimeToUnlock;
1204 }
1205 }
1206 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001207 }
1208 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001209
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001210 public void lockNow() {
1211 synchronized (this) {
1212 // This API can only be called by an active device admin,
1213 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001214 getActiveAdminForCallerLocked(null,
1215 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001216 long ident = Binder.clearCallingIdentity();
1217 try {
1218 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1219 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1220 } catch (RemoteException e) {
1221 } finally {
1222 Binder.restoreCallingIdentity(ident);
1223 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001224 }
1225 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001226
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001227 void wipeDataLocked(int flags) {
1228 try {
1229 RecoverySystem.rebootWipeUserData(mContext);
1230 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001231 Slog.w(TAG, "Failed requesting data wipe", e);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001232 }
1233 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001234
Dianne Hackbornd6847842010-01-12 18:14:19 -08001235 public void wipeData(int flags) {
1236 synchronized (this) {
1237 // This API can only be called by an active device admin,
1238 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001239 getActiveAdminForCallerLocked(null,
1240 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001241 long ident = Binder.clearCallingIdentity();
1242 try {
1243 wipeDataLocked(flags);
1244 } finally {
1245 Binder.restoreCallingIdentity(ident);
1246 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001247 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001248 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001249
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001250 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1251 mContext.enforceCallingOrSelfPermission(
1252 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001253
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001254 synchronized (this) {
1255 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1256 if (admin == null) {
1257 try {
1258 result.sendResult(null);
1259 } catch (RemoteException e) {
1260 }
1261 return;
1262 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001263 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001264 intent.setComponent(admin.info.getComponent());
1265 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1266 @Override
1267 public void onReceive(Context context, Intent intent) {
1268 try {
1269 result.sendResult(getResultExtras(false));
1270 } catch (RemoteException e) {
1271 }
1272 }
1273 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001274 }
1275 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001276
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001277 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
1278 int lowercase, int numbers, int symbols) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001279 mContext.enforceCallingOrSelfPermission(
1280 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001281
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001282 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001283
Dianne Hackbornd6847842010-01-12 18:14:19 -08001284 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001285 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001286 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1287 || mActivePasswordUpperCase != uppercase
1288 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
1289 || mActivePasswordSymbols != symbols) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001290 long ident = Binder.clearCallingIdentity();
1291 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001292 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001293 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001294 mActivePasswordLetters = letters;
1295 mActivePasswordLowerCase = lowercase;
1296 mActivePasswordUpperCase = uppercase;
1297 mActivePasswordNumeric = numbers;
1298 mActivePasswordSymbols = symbols;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001299 mFailedPasswordAttempts = 0;
1300 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001301 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001302 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001303 } finally {
1304 Binder.restoreCallingIdentity(ident);
1305 }
1306 }
1307 }
1308 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001309
Dianne Hackbornd6847842010-01-12 18:14:19 -08001310 public void reportFailedPasswordAttempt() {
1311 mContext.enforceCallingOrSelfPermission(
1312 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001313
Dianne Hackbornd6847842010-01-12 18:14:19 -08001314 synchronized (this) {
1315 long ident = Binder.clearCallingIdentity();
1316 try {
1317 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001318 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001319 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001320 if (max > 0 && mFailedPasswordAttempts >= max) {
1321 wipeDataLocked(0);
1322 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001323 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001324 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001325 } finally {
1326 Binder.restoreCallingIdentity(ident);
1327 }
1328 }
1329 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001330
Dianne Hackbornd6847842010-01-12 18:14:19 -08001331 public void reportSuccessfulPasswordAttempt() {
1332 mContext.enforceCallingOrSelfPermission(
1333 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001334
Dianne Hackbornd6847842010-01-12 18:14:19 -08001335 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001336 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001337 long ident = Binder.clearCallingIdentity();
1338 try {
1339 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001340 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001341 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001342 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001343 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001344 } finally {
1345 Binder.restoreCallingIdentity(ident);
1346 }
1347 }
1348 }
1349 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001350
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001351 @Override
1352 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1353 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1354 != PackageManager.PERMISSION_GRANTED) {
1355
1356 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1357 + Binder.getCallingPid()
1358 + ", uid=" + Binder.getCallingUid());
1359 return;
1360 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001361
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001362 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001363
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001364 synchronized (this) {
1365 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001366
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001367 p.println(" Enabled Device Admins:");
1368 final int N = mAdminList.size();
1369 for (int i=0; i<N; i++) {
1370 ActiveAdmin ap = mAdminList.get(i);
1371 if (ap != null) {
1372 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1373 pw.println(":");
1374 ap.dump(" ", pw);
1375 }
1376 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001377
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001378 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001379 pw.print(" mActivePasswordQuality=0x");
1380 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001381 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001382 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1383 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1384 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1385 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1386 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001387 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1388 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1389 }
1390 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001391}