blob: 21273cce21fb7fecf3dcf9823d7061dc0d8b7c26 [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;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070058import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080059import java.io.FileOutputStream;
60import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080061import java.io.PrintWriter;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080062import java.util.ArrayList;
63import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080064import java.util.List;
65
66/**
67 * Implementation of the device policy APIs.
68 */
69public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080070 static final String TAG = "DevicePolicyManagerService";
Dianne Hackbornd6847842010-01-12 18:14:19 -080071
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080072 final Context mContext;
73 final MyPackageMonitor mMonitor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080074
Dianne Hackborndf83afa2010-01-20 13:37:26 -080075 IPowerManager mIPowerManager;
76
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080077 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080078 int mActivePasswordLength = 0;
79 int mFailedPasswordAttempts = 0;
80
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080081 int mPasswordOwner = -1;
82
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080083 final HashMap<ComponentName, ActiveAdmin> mAdminMap
84 = new HashMap<ComponentName, ActiveAdmin>();
85 final ArrayList<ActiveAdmin> mAdminList
86 = new ArrayList<ActiveAdmin>();
Dianne Hackbornd6847842010-01-12 18:14:19 -080087
88 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -080089 final DeviceAdminInfo info;
Dianne Hackbornd6847842010-01-12 18:14:19 -080090
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080091 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080092 int minimumPasswordLength = 0;
93 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080094 int maximumFailedPasswordsForWipe = 0;
95
96 ActiveAdmin(DeviceAdminInfo _info) {
97 info = _info;
98 }
99
100 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
101
102 void writeToXml(XmlSerializer out)
103 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800104 out.startTag(null, "policies");
105 info.writePoliciesToXml(out);
106 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800107 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
108 out.startTag(null, "password-quality");
109 out.attribute(null, "value", Integer.toString(passwordQuality));
110 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800111 if (minimumPasswordLength > 0) {
112 out.startTag(null, "min-password-length");
113 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
114 out.endTag(null, "mn-password-length");
115 }
116 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800117 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800118 out.startTag(null, "max-time-to-unlock");
119 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
120 out.endTag(null, "max-time-to-unlock");
121 }
122 if (maximumFailedPasswordsForWipe != 0) {
123 out.startTag(null, "max-failed-password-wipe");
124 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
125 out.endTag(null, "max-failed-password-wipe");
126 }
127 }
128
129 void readFromXml(XmlPullParser parser)
130 throws XmlPullParserException, IOException {
131 int outerDepth = parser.getDepth();
132 int type;
133 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
134 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
135 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
136 continue;
137 }
138 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800139 if ("policies".equals(tag)) {
140 info.readPoliciesFromXml(parser);
141 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800142 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800143 parser.getAttributeValue(null, "value"));
144 } else if ("min-password-length".equals(tag)) {
145 minimumPasswordLength = Integer.parseInt(
146 parser.getAttributeValue(null, "value"));
147 } else if ("max-time-to-unlock".equals(tag)) {
148 maximumTimeToUnlock = Long.parseLong(
149 parser.getAttributeValue(null, "value"));
150 } else if ("max-failed-password-wipe".equals(tag)) {
151 maximumFailedPasswordsForWipe = Integer.parseInt(
152 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800153 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700154 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800155 }
156 XmlUtils.skipCurrentTag(parser);
157 }
158 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800159
160 void dump(String prefix, PrintWriter pw) {
161 pw.print(prefix); pw.print("uid="); pw.println(getUid());
162 pw.print(prefix); pw.println("policies:");
163 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
164 if (pols != null) {
165 for (int i=0; i<pols.size(); i++) {
166 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
167 }
168 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700169 pw.print(prefix); pw.print("passwordQuality=0x");
170 pw.print(Integer.toHexString(passwordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800171 pw.print(" minimumPasswordLength=");
172 pw.println(minimumPasswordLength);
173 pw.print(prefix); pw.print("maximumTimeToUnlock=");
174 pw.println(maximumTimeToUnlock);
175 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
176 pw.println(maximumFailedPasswordsForWipe);
177 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800178 }
179
180 class MyPackageMonitor extends PackageMonitor {
181 public void onSomePackagesChanged() {
182 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800183 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800184 for (int i=mAdminList.size()-1; i>=0; i--) {
185 ActiveAdmin aa = mAdminList.get(i);
186 int change = isPackageDisappearing(aa.info.getPackageName());
187 if (change == PACKAGE_PERMANENT_CHANGE
188 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700189 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800190 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800191 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800192 mAdminList.remove(i);
193 } else if (isPackageModified(aa.info.getPackageName())) {
194 try {
195 mContext.getPackageManager().getReceiverInfo(
196 aa.info.getComponent(), 0);
197 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700198 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800199 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800200 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800201 mAdminList.remove(i);
202 }
203 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800204 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800205 if (removed) {
206 validatePasswordOwnerLocked();
207 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800208 }
209 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800210 }
211
212 /**
213 * Instantiates the service.
214 */
215 public DevicePolicyManagerService(Context context) {
216 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800217 mMonitor = new MyPackageMonitor();
218 mMonitor.register(context, true);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800219 }
220
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800221 private IPowerManager getIPowerManager() {
222 if (mIPowerManager == null) {
223 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
224 mIPowerManager = IPowerManager.Stub.asInterface(b);
225 }
226 return mIPowerManager;
227 }
228
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800229 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800230 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800231 if (admin != null
232 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
233 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
234 return admin;
235 }
236 return null;
237 }
238
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800239 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
240 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800241 final int callingUid = Binder.getCallingUid();
242 if (who != null) {
243 ActiveAdmin admin = mAdminMap.get(who);
244 if (admin == null) {
245 throw new SecurityException("No active admin " + who);
246 }
247 if (admin.getUid() != callingUid) {
248 throw new SecurityException("Admin " + who + " is not owned by uid "
249 + Binder.getCallingUid());
250 }
251 if (!admin.info.usesPolicy(reqPolicy)) {
252 throw new SecurityException("Admin " + admin.info.getComponent()
253 + " did not specify uses-policy for: "
254 + admin.info.getTagForPolicy(reqPolicy));
255 }
256 return admin;
257 } else {
258 final int N = mAdminList.size();
259 for (int i=0; i<N; i++) {
260 ActiveAdmin admin = mAdminList.get(i);
261 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
262 return admin;
263 }
264 }
265 throw new SecurityException("No active admin owned by uid "
266 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800267 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800268 }
269
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800270 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800271 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800272 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800273 mContext.sendBroadcast(intent);
274 }
275
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800276 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800277 final int N = mAdminList.size();
278 if (N > 0) {
279 for (int i=0; i<N; i++) {
280 ActiveAdmin admin = mAdminList.get(i);
281 if (admin.info.usesPolicy(reqPolicy)) {
282 sendAdminCommandLocked(admin, action);
283 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800284 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800285 }
286 }
287
Dianne Hackbornd6847842010-01-12 18:14:19 -0800288 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800289 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
290 if (admin != null) {
291 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800292 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800293 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800294 mAdminList.remove(admin);
295 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800296 validatePasswordOwnerLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800297 }
298 }
299
300 public DeviceAdminInfo findAdmin(ComponentName adminName) {
301 Intent resolveIntent = new Intent();
302 resolveIntent.setComponent(adminName);
303 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
304 resolveIntent, PackageManager.GET_META_DATA);
305 if (infos == null || infos.size() <= 0) {
306 throw new IllegalArgumentException("Unknown admin: " + adminName);
307 }
308
309 try {
310 return new DeviceAdminInfo(mContext, infos.get(0));
311 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700312 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800313 return null;
314 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700315 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800316 return null;
317 }
318 }
319
320 private static JournaledFile makeJournaledFile() {
321 final String base = "/data/system/device_policies.xml";
322 return new JournaledFile(new File(base), new File(base + ".tmp"));
323 }
324
325 private void saveSettingsLocked() {
326 JournaledFile journal = makeJournaledFile();
327 FileOutputStream stream = null;
328 try {
329 stream = new FileOutputStream(journal.chooseForWrite(), false);
330 XmlSerializer out = new FastXmlSerializer();
331 out.setOutput(stream, "utf-8");
332 out.startDocument(null, true);
333
334 out.startTag(null, "policies");
335
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800336 final int N = mAdminList.size();
337 for (int i=0; i<N; i++) {
338 ActiveAdmin ap = mAdminList.get(i);
339 if (ap != null) {
340 out.startTag(null, "admin");
341 out.attribute(null, "name", ap.info.getComponent().flattenToString());
342 ap.writeToXml(out);
343 out.endTag(null, "admin");
344 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800345 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800346
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800347 if (mPasswordOwner >= 0) {
348 out.startTag(null, "password-owner");
349 out.attribute(null, "value", Integer.toString(mPasswordOwner));
350 out.endTag(null, "password-owner");
351 }
352
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800353 if (mFailedPasswordAttempts != 0) {
354 out.startTag(null, "failed-password-attempts");
355 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
356 out.endTag(null, "failed-password-attempts");
357 }
358
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700359 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
360 out.startTag(null, "active-password");
361 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
362 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
363 out.endTag(null, "active-password");
364 }
365
366 out.endTag(null, "policies");
367
Dianne Hackbornd6847842010-01-12 18:14:19 -0800368 out.endDocument();
369 stream.close();
370 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700371 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800372 } catch (IOException e) {
373 try {
374 if (stream != null) {
375 stream.close();
376 }
377 } catch (IOException ex) {
378 // Ignore
379 }
380 journal.rollback();
381 }
382 }
383
Jim Miller284b62e2010-06-08 14:27:42 -0700384 private void sendChangedNotification() {
385 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
386 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
387 mContext.sendBroadcast(intent);
388 }
389
Dianne Hackbornd6847842010-01-12 18:14:19 -0800390 private void loadSettingsLocked() {
391 JournaledFile journal = makeJournaledFile();
392 FileInputStream stream = null;
393 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800394 try {
395 stream = new FileInputStream(file);
396 XmlPullParser parser = Xml.newPullParser();
397 parser.setInput(stream, null);
398
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800399 int type;
400 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
401 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800402 }
403 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800404 if (!"policies".equals(tag)) {
405 throw new XmlPullParserException(
406 "Settings do not start with policies tag: found " + tag);
407 }
408 type = parser.next();
409 int outerDepth = parser.getDepth();
410 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
411 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
412 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
413 continue;
414 }
415 tag = parser.getName();
416 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800417 String name = parser.getAttributeValue(null, "name");
418 try {
419 DeviceAdminInfo dai = findAdmin(
420 ComponentName.unflattenFromString(name));
421 if (dai != null) {
422 ActiveAdmin ap = new ActiveAdmin(dai);
423 ap.readFromXml(parser);
424 mAdminMap.put(ap.info.getComponent(), ap);
425 mAdminList.add(ap);
426 }
427 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700428 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800429 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800430 } else if ("failed-password-attempts".equals(tag)) {
431 mFailedPasswordAttempts = Integer.parseInt(
432 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800433 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800434 } else if ("password-owner".equals(tag)) {
435 mPasswordOwner = Integer.parseInt(
436 parser.getAttributeValue(null, "value"));
437 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700438 } else if ("active-password".equals(tag)) {
439 mActivePasswordQuality = Integer.parseInt(
440 parser.getAttributeValue(null, "quality"));
441 mActivePasswordLength = Integer.parseInt(
442 parser.getAttributeValue(null, "length"));
443 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800444 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700445 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800446 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800447 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800448 }
449 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700450 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800451 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700452 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800453 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700454 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700455 } catch (FileNotFoundException e) {
456 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800457 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700458 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800459 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700460 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800461 }
462 try {
463 if (stream != null) {
464 stream.close();
465 }
466 } catch (IOException e) {
467 // Ignore
468 }
469
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700470 // Validate that what we stored for the password quality matches
471 // sufficiently what is currently set. Note that this is only
472 // a sanity check in case the two get out of sync; this should
473 // never normally happen.
474 LockPatternUtils utils = new LockPatternUtils(mContext);
475 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
476 Slog.w(TAG, "Active password quality 0x"
477 + Integer.toHexString(mActivePasswordQuality)
478 + " does not match actual quality 0x"
479 + Integer.toHexString(utils.getActivePasswordQuality()));
480 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
481 mActivePasswordLength = 0;
482 }
483
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800484 validatePasswordOwnerLocked();
485
Dianne Hackborn254cb442010-01-27 19:23:59 -0800486 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800487 if (timeMs <= 0) {
488 timeMs = Integer.MAX_VALUE;
489 }
490 try {
491 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
492 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700493 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800494 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800495 }
496
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700497 static void validateQualityConstant(int quality) {
498 switch (quality) {
499 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
500 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
501 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
502 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
503 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
504 return;
505 }
506 throw new IllegalArgumentException("Invalid quality constant: 0x"
507 + Integer.toHexString(quality));
508 }
509
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800510 void validatePasswordOwnerLocked() {
511 if (mPasswordOwner >= 0) {
512 boolean haveOwner = false;
513 for (int i=mAdminList.size()-1; i>=0; i--) {
514 if (mAdminList.get(i).getUid() == mPasswordOwner) {
515 haveOwner = true;
516 break;
517 }
518 }
519 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700520 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800521 + " no longer active; disabling");
522 mPasswordOwner = -1;
523 }
524 }
525 }
526
Dianne Hackbornd6847842010-01-12 18:14:19 -0800527 public void systemReady() {
528 synchronized (this) {
529 loadSettingsLocked();
530 }
531 }
532
533 public void setActiveAdmin(ComponentName adminReceiver) {
534 mContext.enforceCallingOrSelfPermission(
535 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
536
537 DeviceAdminInfo info = findAdmin(adminReceiver);
538 if (info == null) {
539 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
540 }
541 synchronized (this) {
542 long ident = Binder.clearCallingIdentity();
543 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800544 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
545 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800546 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800547 ActiveAdmin admin = new ActiveAdmin(info);
548 mAdminMap.put(adminReceiver, admin);
549 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800550 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800551 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800552 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800553 } finally {
554 Binder.restoreCallingIdentity(ident);
555 }
556 }
557 }
558
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800559 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800560 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800561 return getActiveAdminUncheckedLocked(adminReceiver) != null;
562 }
563 }
564
565 public List<ComponentName> getActiveAdmins() {
566 synchronized (this) {
567 final int N = mAdminList.size();
568 if (N <= 0) {
569 return null;
570 }
571 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
572 for (int i=0; i<N; i++) {
573 res.add(mAdminList.get(i).info.getComponent());
574 }
575 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800576 }
577 }
578
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800579 public boolean packageHasActiveAdmins(String packageName) {
580 synchronized (this) {
581 final int N = mAdminList.size();
582 for (int i=0; i<N; i++) {
583 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
584 return true;
585 }
586 }
587 return false;
588 }
589 }
590
Dianne Hackbornd6847842010-01-12 18:14:19 -0800591 public void removeActiveAdmin(ComponentName adminReceiver) {
592 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800593 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
594 if (admin == null) {
595 return;
596 }
597 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800598 mContext.enforceCallingOrSelfPermission(
599 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
600 }
601 long ident = Binder.clearCallingIdentity();
602 try {
603 removeActiveAdminLocked(adminReceiver);
604 } finally {
605 Binder.restoreCallingIdentity(ident);
606 }
607 }
608 }
609
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700610 public void setPasswordQuality(ComponentName who, int quality) {
611 validateQualityConstant(quality);
612
Dianne Hackbornd6847842010-01-12 18:14:19 -0800613 synchronized (this) {
614 if (who == null) {
615 throw new NullPointerException("ComponentName is null");
616 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800617 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
618 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700619 if (ap.passwordQuality != quality) {
620 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800621 saveSettingsLocked();
622 }
623 }
624 }
625
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800626 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800627 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800628 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800629
630 if (who != null) {
631 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800632 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800633 }
634
635 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800636 for (int i=0; i<N; i++) {
637 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800638 if (mode < admin.passwordQuality) {
639 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800640 }
641 }
642 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800643 }
644 }
645
Dianne Hackborn254cb442010-01-27 19:23:59 -0800646 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800647 synchronized (this) {
648 if (who == null) {
649 throw new NullPointerException("ComponentName is null");
650 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800651 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
652 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800653 if (ap.minimumPasswordLength != length) {
654 ap.minimumPasswordLength = length;
655 saveSettingsLocked();
656 }
657 }
658 }
659
Dianne Hackborn254cb442010-01-27 19:23:59 -0800660 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800661 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800662 int length = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800663
664 if (who != null) {
665 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
666 return admin != null ? admin.minimumPasswordLength : length;
667 }
668
669 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800670 for (int i=0; i<N; i++) {
671 ActiveAdmin admin = mAdminList.get(i);
672 if (length < admin.minimumPasswordLength) {
673 length = admin.minimumPasswordLength;
674 }
675 }
676 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800677 }
678 }
679
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800680 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800681 synchronized (this) {
682 // This API can only be called by an active device admin,
683 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800684 getActiveAdminForCallerLocked(null,
685 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800686 return mActivePasswordQuality >= getPasswordQuality(null)
Dianne Hackborn254cb442010-01-27 19:23:59 -0800687 && mActivePasswordLength >= getPasswordMinimumLength(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800688 }
689 }
690
691 public int getCurrentFailedPasswordAttempts() {
692 synchronized (this) {
693 // This API can only be called by an active device admin,
694 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800695 getActiveAdminForCallerLocked(null,
696 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800697 return mFailedPasswordAttempts;
698 }
699 }
700
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800701 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
702 synchronized (this) {
703 // This API can only be called by an active device admin,
704 // so try to retrieve it to check that the caller is one.
705 getActiveAdminForCallerLocked(who,
706 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
707 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
708 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
709 if (ap.maximumFailedPasswordsForWipe != num) {
710 ap.maximumFailedPasswordsForWipe = num;
711 saveSettingsLocked();
712 }
713 }
714 }
715
Dianne Hackborn254cb442010-01-27 19:23:59 -0800716 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800717 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800718 int count = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800719
720 if (who != null) {
721 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
722 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
723 }
724
725 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800726 for (int i=0; i<N; i++) {
727 ActiveAdmin admin = mAdminList.get(i);
728 if (count == 0) {
729 count = admin.maximumFailedPasswordsForWipe;
730 } else if (admin.maximumFailedPasswordsForWipe != 0
731 && count > admin.maximumFailedPasswordsForWipe) {
732 count = admin.maximumFailedPasswordsForWipe;
733 }
734 }
735 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800736 }
737 }
738
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800739 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800740 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800741 synchronized (this) {
742 // This API can only be called by an active device admin,
743 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800744 getActiveAdminForCallerLocked(null,
745 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800746 quality = getPasswordQuality(null);
747 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700748 int realQuality = LockPatternUtils.computePasswordQuality(password);
749 if (realQuality < quality) {
750 Slog.w(TAG, "resetPassword: password quality 0x"
751 + Integer.toHexString(quality)
752 + " does not meet required quality 0x"
753 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800754 return false;
755 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700756 quality = realQuality;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800757 }
758 int length = getPasswordMinimumLength(null);
759 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700760 Slog.w(TAG, "resetPassword: password length " + password.length()
761 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800762 return false;
763 }
764 }
765
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800766 int callingUid = Binder.getCallingUid();
767 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700768 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800769 return false;
770 }
771
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800772 // Don't do this with the lock held, because it is going to call
773 // back in to the service.
774 long ident = Binder.clearCallingIdentity();
775 try {
776 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800777 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700778 synchronized (this) {
779 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
780 != 0 ? callingUid : -1;
781 if (mPasswordOwner != newOwner) {
782 mPasswordOwner = newOwner;
783 saveSettingsLocked();
784 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800785 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800786 } finally {
787 Binder.restoreCallingIdentity(ident);
788 }
789
790 return true;
791 }
792
Dianne Hackbornd6847842010-01-12 18:14:19 -0800793 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
794 synchronized (this) {
795 if (who == null) {
796 throw new NullPointerException("ComponentName is null");
797 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800798 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -0800799 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800800 if (ap.maximumTimeToUnlock != timeMs) {
801 ap.maximumTimeToUnlock = timeMs;
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800802
803 long ident = Binder.clearCallingIdentity();
804 try {
805 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800806
807 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800808 if (timeMs <= 0) {
809 timeMs = Integer.MAX_VALUE;
810 }
Dianne Hackborn254cb442010-01-27 19:23:59 -0800811
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800812 try {
813 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
814 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700815 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800816 }
817 } finally {
818 Binder.restoreCallingIdentity(ident);
819 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800820 }
821 }
822 }
823
Dianne Hackborn254cb442010-01-27 19:23:59 -0800824 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800825 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800826 long time = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800827
828 if (who != null) {
829 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
830 return admin != null ? admin.maximumTimeToUnlock : time;
831 }
832
833 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800834 for (int i=0; i<N; i++) {
835 ActiveAdmin admin = mAdminList.get(i);
836 if (time == 0) {
837 time = admin.maximumTimeToUnlock;
838 } else if (admin.maximumTimeToUnlock != 0
839 && time > admin.maximumTimeToUnlock) {
840 time = admin.maximumTimeToUnlock;
841 }
842 }
843 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800844 }
845 }
846
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800847 public void lockNow() {
848 synchronized (this) {
849 // This API can only be called by an active device admin,
850 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800851 getActiveAdminForCallerLocked(null,
852 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800853 long ident = Binder.clearCallingIdentity();
854 try {
855 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
856 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
857 } catch (RemoteException e) {
858 } finally {
859 Binder.restoreCallingIdentity(ident);
860 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800861 }
862 }
863
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800864 void wipeDataLocked(int flags) {
865 try {
866 RecoverySystem.rebootWipeUserData(mContext);
867 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700868 Slog.w(TAG, "Failed requesting data wipe", e);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800869 }
870 }
871
Dianne Hackbornd6847842010-01-12 18:14:19 -0800872 public void wipeData(int flags) {
873 synchronized (this) {
874 // This API can only be called by an active device admin,
875 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800876 getActiveAdminForCallerLocked(null,
877 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800878 long ident = Binder.clearCallingIdentity();
879 try {
880 wipeDataLocked(flags);
881 } finally {
882 Binder.restoreCallingIdentity(ident);
883 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800884 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800885 }
886
887 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
888 mContext.enforceCallingOrSelfPermission(
889 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
890
891 synchronized (this) {
892 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
893 if (admin == null) {
894 try {
895 result.sendResult(null);
896 } catch (RemoteException e) {
897 }
898 return;
899 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800900 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800901 intent.setComponent(admin.info.getComponent());
902 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
903 @Override
904 public void onReceive(Context context, Intent intent) {
905 try {
906 result.sendResult(getResultExtras(false));
907 } catch (RemoteException e) {
908 }
909 }
910 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800911 }
912 }
913
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800914 public void setActivePasswordState(int quality, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800915 mContext.enforceCallingOrSelfPermission(
916 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
917
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700918 validateQualityConstant(quality);
919
Dianne Hackbornd6847842010-01-12 18:14:19 -0800920 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800921 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Dianne Hackbornd6847842010-01-12 18:14:19 -0800922 || mFailedPasswordAttempts != 0) {
923 long ident = Binder.clearCallingIdentity();
924 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800925 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800926 mActivePasswordLength = length;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700927 mFailedPasswordAttempts = 0;
928 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800929 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800930 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800931 } finally {
932 Binder.restoreCallingIdentity(ident);
933 }
934 }
935 }
936 }
937
938 public void reportFailedPasswordAttempt() {
939 mContext.enforceCallingOrSelfPermission(
940 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
941
942 synchronized (this) {
943 long ident = Binder.clearCallingIdentity();
944 try {
945 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800946 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800947 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800948 if (max > 0 && mFailedPasswordAttempts >= max) {
949 wipeDataLocked(0);
950 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800951 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800952 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800953 } finally {
954 Binder.restoreCallingIdentity(ident);
955 }
956 }
957 }
958
959 public void reportSuccessfulPasswordAttempt() {
960 mContext.enforceCallingOrSelfPermission(
961 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
962
963 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800964 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800965 long ident = Binder.clearCallingIdentity();
966 try {
967 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800968 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800969 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800970 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800971 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800972 } finally {
973 Binder.restoreCallingIdentity(ident);
974 }
975 }
976 }
977 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800978
979 @Override
980 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
981 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
982 != PackageManager.PERMISSION_GRANTED) {
983
984 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
985 + Binder.getCallingPid()
986 + ", uid=" + Binder.getCallingUid());
987 return;
988 }
989
990 final Printer p = new PrintWriterPrinter(pw);
991
992 synchronized (this) {
993 p.println("Current Device Policy Manager state:");
994
995 p.println(" Enabled Device Admins:");
996 final int N = mAdminList.size();
997 for (int i=0; i<N; i++) {
998 ActiveAdmin ap = mAdminList.get(i);
999 if (ap != null) {
1000 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1001 pw.println(":");
1002 ap.dump(" ", pw);
1003 }
1004 }
1005
1006 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001007 pw.print(" mActivePasswordQuality=0x");
1008 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001009 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
1010 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1011 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1012 }
1013 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001014}