blob: 19d146ddd36860873b0d7bbbaae45c1b7b50ce8c [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";
Dianne Hackbornd6847842010-01-12 18:14:19 -080070
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;
75
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;
78 int mFailedPasswordAttempts = 0;
79
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080080 int mPasswordOwner = -1;
81
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080082 final HashMap<ComponentName, ActiveAdmin> mAdminMap
83 = new HashMap<ComponentName, ActiveAdmin>();
84 final ArrayList<ActiveAdmin> mAdminList
85 = new ArrayList<ActiveAdmin>();
Dianne Hackbornd6847842010-01-12 18:14:19 -080086
87 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -080088 final DeviceAdminInfo info;
Dianne Hackbornd6847842010-01-12 18:14:19 -080089
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080090 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080091 int minimumPasswordLength = 0;
92 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080093 int maximumFailedPasswordsForWipe = 0;
94
95 ActiveAdmin(DeviceAdminInfo _info) {
96 info = _info;
97 }
98
99 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
100
101 void writeToXml(XmlSerializer out)
102 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800103 out.startTag(null, "policies");
104 info.writePoliciesToXml(out);
105 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800106 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
107 out.startTag(null, "password-quality");
108 out.attribute(null, "value", Integer.toString(passwordQuality));
109 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800110 if (minimumPasswordLength > 0) {
111 out.startTag(null, "min-password-length");
112 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
113 out.endTag(null, "mn-password-length");
114 }
115 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800116 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800117 out.startTag(null, "max-time-to-unlock");
118 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
119 out.endTag(null, "max-time-to-unlock");
120 }
121 if (maximumFailedPasswordsForWipe != 0) {
122 out.startTag(null, "max-failed-password-wipe");
123 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
124 out.endTag(null, "max-failed-password-wipe");
125 }
126 }
127
128 void readFromXml(XmlPullParser parser)
129 throws XmlPullParserException, IOException {
130 int outerDepth = parser.getDepth();
131 int type;
132 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
133 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
134 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
135 continue;
136 }
137 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800138 if ("policies".equals(tag)) {
139 info.readPoliciesFromXml(parser);
140 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800141 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800142 parser.getAttributeValue(null, "value"));
143 } else if ("min-password-length".equals(tag)) {
144 minimumPasswordLength = Integer.parseInt(
145 parser.getAttributeValue(null, "value"));
146 } else if ("max-time-to-unlock".equals(tag)) {
147 maximumTimeToUnlock = Long.parseLong(
148 parser.getAttributeValue(null, "value"));
149 } else if ("max-failed-password-wipe".equals(tag)) {
150 maximumFailedPasswordsForWipe = Integer.parseInt(
151 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800152 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700153 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800154 }
155 XmlUtils.skipCurrentTag(parser);
156 }
157 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800158
159 void dump(String prefix, PrintWriter pw) {
160 pw.print(prefix); pw.print("uid="); pw.println(getUid());
161 pw.print(prefix); pw.println("policies:");
162 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
163 if (pols != null) {
164 for (int i=0; i<pols.size(); i++) {
165 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
166 }
167 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700168 pw.print(prefix); pw.print("passwordQuality=0x");
169 pw.print(Integer.toHexString(passwordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800170 pw.print(" minimumPasswordLength=");
171 pw.println(minimumPasswordLength);
172 pw.print(prefix); pw.print("maximumTimeToUnlock=");
173 pw.println(maximumTimeToUnlock);
174 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
175 pw.println(maximumFailedPasswordsForWipe);
176 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800177 }
178
179 class MyPackageMonitor extends PackageMonitor {
180 public void onSomePackagesChanged() {
181 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800182 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800183 for (int i=mAdminList.size()-1; i>=0; i--) {
184 ActiveAdmin aa = mAdminList.get(i);
185 int change = isPackageDisappearing(aa.info.getPackageName());
186 if (change == PACKAGE_PERMANENT_CHANGE
187 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700188 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800189 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800190 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800191 mAdminList.remove(i);
192 } else if (isPackageModified(aa.info.getPackageName())) {
193 try {
194 mContext.getPackageManager().getReceiverInfo(
195 aa.info.getComponent(), 0);
196 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700197 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800198 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800199 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800200 mAdminList.remove(i);
201 }
202 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800203 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800204 if (removed) {
205 validatePasswordOwnerLocked();
206 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800207 }
208 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800209 }
210
211 /**
212 * Instantiates the service.
213 */
214 public DevicePolicyManagerService(Context context) {
215 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800216 mMonitor = new MyPackageMonitor();
217 mMonitor.register(context, true);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800218 }
219
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800220 private IPowerManager getIPowerManager() {
221 if (mIPowerManager == null) {
222 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
223 mIPowerManager = IPowerManager.Stub.asInterface(b);
224 }
225 return mIPowerManager;
226 }
227
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800228 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800229 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800230 if (admin != null
231 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
232 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
233 return admin;
234 }
235 return null;
236 }
237
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800238 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
239 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800240 final int callingUid = Binder.getCallingUid();
241 if (who != null) {
242 ActiveAdmin admin = mAdminMap.get(who);
243 if (admin == null) {
244 throw new SecurityException("No active admin " + who);
245 }
246 if (admin.getUid() != callingUid) {
247 throw new SecurityException("Admin " + who + " is not owned by uid "
248 + Binder.getCallingUid());
249 }
250 if (!admin.info.usesPolicy(reqPolicy)) {
251 throw new SecurityException("Admin " + admin.info.getComponent()
252 + " did not specify uses-policy for: "
253 + admin.info.getTagForPolicy(reqPolicy));
254 }
255 return admin;
256 } else {
257 final int N = mAdminList.size();
258 for (int i=0; i<N; i++) {
259 ActiveAdmin admin = mAdminList.get(i);
260 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
261 return admin;
262 }
263 }
264 throw new SecurityException("No active admin owned by uid "
265 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800266 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800267 }
268
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800269 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800270 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800271 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800272 mContext.sendBroadcast(intent);
273 }
274
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800275 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800276 final int N = mAdminList.size();
277 if (N > 0) {
278 for (int i=0; i<N; i++) {
279 ActiveAdmin admin = mAdminList.get(i);
280 if (admin.info.usesPolicy(reqPolicy)) {
281 sendAdminCommandLocked(admin, action);
282 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800283 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800284 }
285 }
286
Dianne Hackbornd6847842010-01-12 18:14:19 -0800287 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800288 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
289 if (admin != null) {
290 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800291 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800292 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800293 mAdminList.remove(admin);
294 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800295 validatePasswordOwnerLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800296 }
297 }
298
299 public DeviceAdminInfo findAdmin(ComponentName adminName) {
300 Intent resolveIntent = new Intent();
301 resolveIntent.setComponent(adminName);
302 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
303 resolveIntent, PackageManager.GET_META_DATA);
304 if (infos == null || infos.size() <= 0) {
305 throw new IllegalArgumentException("Unknown admin: " + adminName);
306 }
307
308 try {
309 return new DeviceAdminInfo(mContext, infos.get(0));
310 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700311 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800312 return null;
313 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700314 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800315 return null;
316 }
317 }
318
319 private static JournaledFile makeJournaledFile() {
320 final String base = "/data/system/device_policies.xml";
321 return new JournaledFile(new File(base), new File(base + ".tmp"));
322 }
323
324 private void saveSettingsLocked() {
325 JournaledFile journal = makeJournaledFile();
326 FileOutputStream stream = null;
327 try {
328 stream = new FileOutputStream(journal.chooseForWrite(), false);
329 XmlSerializer out = new FastXmlSerializer();
330 out.setOutput(stream, "utf-8");
331 out.startDocument(null, true);
332
333 out.startTag(null, "policies");
334
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800335 final int N = mAdminList.size();
336 for (int i=0; i<N; i++) {
337 ActiveAdmin ap = mAdminList.get(i);
338 if (ap != null) {
339 out.startTag(null, "admin");
340 out.attribute(null, "name", ap.info.getComponent().flattenToString());
341 ap.writeToXml(out);
342 out.endTag(null, "admin");
343 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800344 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800345
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800346 if (mPasswordOwner >= 0) {
347 out.startTag(null, "password-owner");
348 out.attribute(null, "value", Integer.toString(mPasswordOwner));
349 out.endTag(null, "password-owner");
350 }
351
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800352 if (mFailedPasswordAttempts != 0) {
353 out.startTag(null, "failed-password-attempts");
354 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
355 out.endTag(null, "failed-password-attempts");
356 }
357
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700358 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
359 out.startTag(null, "active-password");
360 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
361 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
362 out.endTag(null, "active-password");
363 }
364
365 out.endTag(null, "policies");
366
Dianne Hackbornd6847842010-01-12 18:14:19 -0800367 out.endDocument();
368 stream.close();
369 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700370 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800371 } catch (IOException e) {
372 try {
373 if (stream != null) {
374 stream.close();
375 }
376 } catch (IOException ex) {
377 // Ignore
378 }
379 journal.rollback();
380 }
381 }
382
Jim Miller284b62e2010-06-08 14:27:42 -0700383 private void sendChangedNotification() {
384 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
385 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
386 mContext.sendBroadcast(intent);
387 }
388
Dianne Hackbornd6847842010-01-12 18:14:19 -0800389 private void loadSettingsLocked() {
390 JournaledFile journal = makeJournaledFile();
391 FileInputStream stream = null;
392 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800393 try {
394 stream = new FileInputStream(file);
395 XmlPullParser parser = Xml.newPullParser();
396 parser.setInput(stream, null);
397
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800398 int type;
399 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
400 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800401 }
402 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800403 if (!"policies".equals(tag)) {
404 throw new XmlPullParserException(
405 "Settings do not start with policies tag: found " + tag);
406 }
407 type = parser.next();
408 int outerDepth = parser.getDepth();
409 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
410 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
411 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
412 continue;
413 }
414 tag = parser.getName();
415 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800416 String name = parser.getAttributeValue(null, "name");
417 try {
418 DeviceAdminInfo dai = findAdmin(
419 ComponentName.unflattenFromString(name));
420 if (dai != null) {
421 ActiveAdmin ap = new ActiveAdmin(dai);
422 ap.readFromXml(parser);
423 mAdminMap.put(ap.info.getComponent(), ap);
424 mAdminList.add(ap);
425 }
426 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700427 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800428 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800429 } else if ("failed-password-attempts".equals(tag)) {
430 mFailedPasswordAttempts = Integer.parseInt(
431 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800432 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800433 } else if ("password-owner".equals(tag)) {
434 mPasswordOwner = Integer.parseInt(
435 parser.getAttributeValue(null, "value"));
436 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700437 } else if ("active-password".equals(tag)) {
438 mActivePasswordQuality = Integer.parseInt(
439 parser.getAttributeValue(null, "quality"));
440 mActivePasswordLength = Integer.parseInt(
441 parser.getAttributeValue(null, "length"));
442 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800443 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700444 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800445 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800446 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800447 }
448 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700449 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800450 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700451 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800452 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700453 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800454 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700455 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800456 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700457 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800458 }
459 try {
460 if (stream != null) {
461 stream.close();
462 }
463 } catch (IOException e) {
464 // Ignore
465 }
466
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700467 // Validate that what we stored for the password quality matches
468 // sufficiently what is currently set. Note that this is only
469 // a sanity check in case the two get out of sync; this should
470 // never normally happen.
471 LockPatternUtils utils = new LockPatternUtils(mContext);
472 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
473 Slog.w(TAG, "Active password quality 0x"
474 + Integer.toHexString(mActivePasswordQuality)
475 + " does not match actual quality 0x"
476 + Integer.toHexString(utils.getActivePasswordQuality()));
477 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
478 mActivePasswordLength = 0;
479 }
480
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800481 validatePasswordOwnerLocked();
482
Dianne Hackborn254cb442010-01-27 19:23:59 -0800483 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800484 if (timeMs <= 0) {
485 timeMs = Integer.MAX_VALUE;
486 }
487 try {
488 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
489 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700490 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800491 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800492 }
493
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700494 static void validateQualityConstant(int quality) {
495 switch (quality) {
496 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
497 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
498 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
499 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
500 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
501 return;
502 }
503 throw new IllegalArgumentException("Invalid quality constant: 0x"
504 + Integer.toHexString(quality));
505 }
506
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800507 void validatePasswordOwnerLocked() {
508 if (mPasswordOwner >= 0) {
509 boolean haveOwner = false;
510 for (int i=mAdminList.size()-1; i>=0; i--) {
511 if (mAdminList.get(i).getUid() == mPasswordOwner) {
512 haveOwner = true;
513 break;
514 }
515 }
516 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700517 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800518 + " no longer active; disabling");
519 mPasswordOwner = -1;
520 }
521 }
522 }
523
Dianne Hackbornd6847842010-01-12 18:14:19 -0800524 public void systemReady() {
525 synchronized (this) {
526 loadSettingsLocked();
527 }
528 }
529
530 public void setActiveAdmin(ComponentName adminReceiver) {
531 mContext.enforceCallingOrSelfPermission(
532 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
533
534 DeviceAdminInfo info = findAdmin(adminReceiver);
535 if (info == null) {
536 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
537 }
538 synchronized (this) {
539 long ident = Binder.clearCallingIdentity();
540 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800541 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
542 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800543 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800544 ActiveAdmin admin = new ActiveAdmin(info);
545 mAdminMap.put(adminReceiver, admin);
546 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800547 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800548 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800549 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800550 } finally {
551 Binder.restoreCallingIdentity(ident);
552 }
553 }
554 }
555
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800556 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800557 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800558 return getActiveAdminUncheckedLocked(adminReceiver) != null;
559 }
560 }
561
562 public List<ComponentName> getActiveAdmins() {
563 synchronized (this) {
564 final int N = mAdminList.size();
565 if (N <= 0) {
566 return null;
567 }
568 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
569 for (int i=0; i<N; i++) {
570 res.add(mAdminList.get(i).info.getComponent());
571 }
572 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800573 }
574 }
575
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800576 public boolean packageHasActiveAdmins(String packageName) {
577 synchronized (this) {
578 final int N = mAdminList.size();
579 for (int i=0; i<N; i++) {
580 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
581 return true;
582 }
583 }
584 return false;
585 }
586 }
587
Dianne Hackbornd6847842010-01-12 18:14:19 -0800588 public void removeActiveAdmin(ComponentName adminReceiver) {
589 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800590 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
591 if (admin == null) {
592 return;
593 }
594 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800595 mContext.enforceCallingOrSelfPermission(
596 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
597 }
598 long ident = Binder.clearCallingIdentity();
599 try {
600 removeActiveAdminLocked(adminReceiver);
601 } finally {
602 Binder.restoreCallingIdentity(ident);
603 }
604 }
605 }
606
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700607 public void setPasswordQuality(ComponentName who, int quality) {
608 validateQualityConstant(quality);
609
Dianne Hackbornd6847842010-01-12 18:14:19 -0800610 synchronized (this) {
611 if (who == null) {
612 throw new NullPointerException("ComponentName is null");
613 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800614 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
615 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700616 if (ap.passwordQuality != quality) {
617 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800618 saveSettingsLocked();
619 }
620 }
621 }
622
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800623 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800624 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800625 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800626
627 if (who != null) {
628 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800629 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800630 }
631
632 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800633 for (int i=0; i<N; i++) {
634 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800635 if (mode < admin.passwordQuality) {
636 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800637 }
638 }
639 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800640 }
641 }
642
Dianne Hackborn254cb442010-01-27 19:23:59 -0800643 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800644 synchronized (this) {
645 if (who == null) {
646 throw new NullPointerException("ComponentName is null");
647 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800648 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
649 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800650 if (ap.minimumPasswordLength != length) {
651 ap.minimumPasswordLength = length;
652 saveSettingsLocked();
653 }
654 }
655 }
656
Dianne Hackborn254cb442010-01-27 19:23:59 -0800657 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800658 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800659 int length = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800660
661 if (who != null) {
662 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
663 return admin != null ? admin.minimumPasswordLength : length;
664 }
665
666 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800667 for (int i=0; i<N; i++) {
668 ActiveAdmin admin = mAdminList.get(i);
669 if (length < admin.minimumPasswordLength) {
670 length = admin.minimumPasswordLength;
671 }
672 }
673 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800674 }
675 }
676
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800677 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800678 synchronized (this) {
679 // This API can only be called by an active device admin,
680 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800681 getActiveAdminForCallerLocked(null,
682 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800683 return mActivePasswordQuality >= getPasswordQuality(null)
Dianne Hackborn254cb442010-01-27 19:23:59 -0800684 && mActivePasswordLength >= getPasswordMinimumLength(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800685 }
686 }
687
688 public int getCurrentFailedPasswordAttempts() {
689 synchronized (this) {
690 // This API can only be called by an active device admin,
691 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800692 getActiveAdminForCallerLocked(null,
693 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800694 return mFailedPasswordAttempts;
695 }
696 }
697
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800698 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
699 synchronized (this) {
700 // This API can only be called by an active device admin,
701 // so try to retrieve it to check that the caller is one.
702 getActiveAdminForCallerLocked(who,
703 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
704 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
705 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
706 if (ap.maximumFailedPasswordsForWipe != num) {
707 ap.maximumFailedPasswordsForWipe = num;
708 saveSettingsLocked();
709 }
710 }
711 }
712
Dianne Hackborn254cb442010-01-27 19:23:59 -0800713 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800714 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800715 int count = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800716
717 if (who != null) {
718 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
719 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
720 }
721
722 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800723 for (int i=0; i<N; i++) {
724 ActiveAdmin admin = mAdminList.get(i);
725 if (count == 0) {
726 count = admin.maximumFailedPasswordsForWipe;
727 } else if (admin.maximumFailedPasswordsForWipe != 0
728 && count > admin.maximumFailedPasswordsForWipe) {
729 count = admin.maximumFailedPasswordsForWipe;
730 }
731 }
732 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800733 }
734 }
735
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800736 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800737 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800738 synchronized (this) {
739 // This API can only be called by an active device admin,
740 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800741 getActiveAdminForCallerLocked(null,
742 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800743 quality = getPasswordQuality(null);
744 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700745 int realQuality = LockPatternUtils.computePasswordQuality(password);
746 if (realQuality < quality) {
747 Slog.w(TAG, "resetPassword: password quality 0x"
748 + Integer.toHexString(quality)
749 + " does not meet required quality 0x"
750 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800751 return false;
752 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700753 quality = realQuality;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800754 }
755 int length = getPasswordMinimumLength(null);
756 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700757 Slog.w(TAG, "resetPassword: password length " + password.length()
758 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800759 return false;
760 }
761 }
762
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800763 int callingUid = Binder.getCallingUid();
764 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700765 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800766 return false;
767 }
768
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800769 // Don't do this with the lock held, because it is going to call
770 // back in to the service.
771 long ident = Binder.clearCallingIdentity();
772 try {
773 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800774 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700775 synchronized (this) {
776 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
777 != 0 ? callingUid : -1;
778 if (mPasswordOwner != newOwner) {
779 mPasswordOwner = newOwner;
780 saveSettingsLocked();
781 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800782 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800783 } finally {
784 Binder.restoreCallingIdentity(ident);
785 }
786
787 return true;
788 }
789
Dianne Hackbornd6847842010-01-12 18:14:19 -0800790 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
791 synchronized (this) {
792 if (who == null) {
793 throw new NullPointerException("ComponentName is null");
794 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800795 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -0800796 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800797 if (ap.maximumTimeToUnlock != timeMs) {
798 ap.maximumTimeToUnlock = timeMs;
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800799
800 long ident = Binder.clearCallingIdentity();
801 try {
802 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800803
804 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800805 if (timeMs <= 0) {
806 timeMs = Integer.MAX_VALUE;
807 }
Dianne Hackborn254cb442010-01-27 19:23:59 -0800808
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800809 try {
810 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
811 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700812 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800813 }
814 } finally {
815 Binder.restoreCallingIdentity(ident);
816 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800817 }
818 }
819 }
820
Dianne Hackborn254cb442010-01-27 19:23:59 -0800821 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800822 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800823 long time = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800824
825 if (who != null) {
826 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
827 return admin != null ? admin.maximumTimeToUnlock : time;
828 }
829
830 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800831 for (int i=0; i<N; i++) {
832 ActiveAdmin admin = mAdminList.get(i);
833 if (time == 0) {
834 time = admin.maximumTimeToUnlock;
835 } else if (admin.maximumTimeToUnlock != 0
836 && time > admin.maximumTimeToUnlock) {
837 time = admin.maximumTimeToUnlock;
838 }
839 }
840 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800841 }
842 }
843
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800844 public void lockNow() {
845 synchronized (this) {
846 // This API can only be called by an active device admin,
847 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800848 getActiveAdminForCallerLocked(null,
849 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800850 long ident = Binder.clearCallingIdentity();
851 try {
852 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
853 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
854 } catch (RemoteException e) {
855 } finally {
856 Binder.restoreCallingIdentity(ident);
857 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800858 }
859 }
860
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800861 void wipeDataLocked(int flags) {
862 try {
863 RecoverySystem.rebootWipeUserData(mContext);
864 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700865 Slog.w(TAG, "Failed requesting data wipe", e);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800866 }
867 }
868
Dianne Hackbornd6847842010-01-12 18:14:19 -0800869 public void wipeData(int flags) {
870 synchronized (this) {
871 // This API can only be called by an active device admin,
872 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800873 getActiveAdminForCallerLocked(null,
874 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800875 long ident = Binder.clearCallingIdentity();
876 try {
877 wipeDataLocked(flags);
878 } finally {
879 Binder.restoreCallingIdentity(ident);
880 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800881 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800882 }
883
884 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
885 mContext.enforceCallingOrSelfPermission(
886 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
887
888 synchronized (this) {
889 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
890 if (admin == null) {
891 try {
892 result.sendResult(null);
893 } catch (RemoteException e) {
894 }
895 return;
896 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800897 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800898 intent.setComponent(admin.info.getComponent());
899 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
900 @Override
901 public void onReceive(Context context, Intent intent) {
902 try {
903 result.sendResult(getResultExtras(false));
904 } catch (RemoteException e) {
905 }
906 }
907 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800908 }
909 }
910
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800911 public void setActivePasswordState(int quality, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800912 mContext.enforceCallingOrSelfPermission(
913 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
914
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700915 validateQualityConstant(quality);
916
Dianne Hackbornd6847842010-01-12 18:14:19 -0800917 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800918 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Dianne Hackbornd6847842010-01-12 18:14:19 -0800919 || mFailedPasswordAttempts != 0) {
920 long ident = Binder.clearCallingIdentity();
921 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800922 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800923 mActivePasswordLength = length;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700924 mFailedPasswordAttempts = 0;
925 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800926 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800927 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800928 } finally {
929 Binder.restoreCallingIdentity(ident);
930 }
931 }
932 }
933 }
934
935 public void reportFailedPasswordAttempt() {
936 mContext.enforceCallingOrSelfPermission(
937 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
938
939 synchronized (this) {
940 long ident = Binder.clearCallingIdentity();
941 try {
942 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800943 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800944 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800945 if (max > 0 && mFailedPasswordAttempts >= max) {
946 wipeDataLocked(0);
947 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800948 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800949 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800950 } finally {
951 Binder.restoreCallingIdentity(ident);
952 }
953 }
954 }
955
956 public void reportSuccessfulPasswordAttempt() {
957 mContext.enforceCallingOrSelfPermission(
958 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
959
960 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800961 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800962 long ident = Binder.clearCallingIdentity();
963 try {
964 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800965 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800966 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800967 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800968 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800969 } finally {
970 Binder.restoreCallingIdentity(ident);
971 }
972 }
973 }
974 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800975
976 @Override
977 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
978 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
979 != PackageManager.PERMISSION_GRANTED) {
980
981 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
982 + Binder.getCallingPid()
983 + ", uid=" + Binder.getCallingUid());
984 return;
985 }
986
987 final Printer p = new PrintWriterPrinter(pw);
988
989 synchronized (this) {
990 p.println("Current Device Policy Manager state:");
991
992 p.println(" Enabled Device Admins:");
993 final int N = mAdminList.size();
994 for (int i=0; i<N; i++) {
995 ActiveAdmin ap = mAdminList.get(i);
996 if (ap != null) {
997 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
998 pw.println(":");
999 ap.dump(" ", pw);
1000 }
1001 }
1002
1003 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001004 pw.print(" mActivePasswordQuality=0x");
1005 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001006 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
1007 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1008 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1009 }
1010 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001011}