blob: 1538003450bcaf1e5000744dc98cebeb7390750a [file] [log] [blame]
Dianne Hackbornd6847842010-01-12 18:14:19 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080019import com.android.internal.content.PackageMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070020import com.android.internal.os.storage.ExternalStorageFormatter;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080021import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070022import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080023import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080024import com.android.internal.widget.LockPatternUtils;
Dianne Hackbornd6847842010-01-12 18:14:19 -080025
26import org.xmlpull.v1.XmlPullParser;
27import org.xmlpull.v1.XmlPullParserException;
28import org.xmlpull.v1.XmlSerializer;
29
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080030import android.app.Activity;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080031import android.app.admin.DeviceAdminInfo;
32import android.app.admin.DeviceAdminReceiver;
33import android.app.admin.DevicePolicyManager;
34import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080035import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080036import android.content.ComponentName;
37import android.content.Context;
38import android.content.Intent;
39import android.content.pm.PackageManager;
40import android.content.pm.ResolveInfo;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080041import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080042import android.os.Binder;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080043import android.os.IBinder;
44import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070045import android.os.PowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080046import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080047import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080048import android.os.RemoteException;
49import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080050import android.os.SystemClock;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -070051import android.util.Slog;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080052import android.util.PrintWriterPrinter;
53import android.util.Printer;
Dianne Hackbornd6847842010-01-12 18:14:19 -080054import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080055import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080056
57import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080058import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080059import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070060import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080061import java.io.FileOutputStream;
62import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080063import java.io.PrintWriter;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080064import java.util.ArrayList;
65import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080066import java.util.List;
67
68/**
69 * Implementation of the device policy APIs.
70 */
71public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080072 static final String TAG = "DevicePolicyManagerService";
Dianne Hackbornd6847842010-01-12 18:14:19 -080073
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080074 final Context mContext;
75 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070076 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077
Dianne Hackborndf83afa2010-01-20 13:37:26 -080078 IPowerManager mIPowerManager;
79
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080080 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080081 int mActivePasswordLength = 0;
82 int mFailedPasswordAttempts = 0;
83
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080084 int mPasswordOwner = -1;
85
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080086 final HashMap<ComponentName, ActiveAdmin> mAdminMap
87 = new HashMap<ComponentName, ActiveAdmin>();
88 final ArrayList<ActiveAdmin> mAdminList
89 = new ArrayList<ActiveAdmin>();
Dianne Hackbornd6847842010-01-12 18:14:19 -080090
91 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -080092 final DeviceAdminInfo info;
Dianne Hackbornd6847842010-01-12 18:14:19 -080093
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080094 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080095 int minimumPasswordLength = 0;
96 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080097 int maximumFailedPasswordsForWipe = 0;
98
99 ActiveAdmin(DeviceAdminInfo _info) {
100 info = _info;
101 }
102
103 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
104
105 void writeToXml(XmlSerializer out)
106 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800107 out.startTag(null, "policies");
108 info.writePoliciesToXml(out);
109 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800110 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
111 out.startTag(null, "password-quality");
112 out.attribute(null, "value", Integer.toString(passwordQuality));
113 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800114 if (minimumPasswordLength > 0) {
115 out.startTag(null, "min-password-length");
116 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
117 out.endTag(null, "mn-password-length");
118 }
119 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800120 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800121 out.startTag(null, "max-time-to-unlock");
122 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
123 out.endTag(null, "max-time-to-unlock");
124 }
125 if (maximumFailedPasswordsForWipe != 0) {
126 out.startTag(null, "max-failed-password-wipe");
127 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
128 out.endTag(null, "max-failed-password-wipe");
129 }
130 }
131
132 void readFromXml(XmlPullParser parser)
133 throws XmlPullParserException, IOException {
134 int outerDepth = parser.getDepth();
135 int type;
136 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
137 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
138 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
139 continue;
140 }
141 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800142 if ("policies".equals(tag)) {
143 info.readPoliciesFromXml(parser);
144 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800145 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800146 parser.getAttributeValue(null, "value"));
147 } else if ("min-password-length".equals(tag)) {
148 minimumPasswordLength = Integer.parseInt(
149 parser.getAttributeValue(null, "value"));
150 } else if ("max-time-to-unlock".equals(tag)) {
151 maximumTimeToUnlock = Long.parseLong(
152 parser.getAttributeValue(null, "value"));
153 } else if ("max-failed-password-wipe".equals(tag)) {
154 maximumFailedPasswordsForWipe = Integer.parseInt(
155 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800156 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700157 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800158 }
159 XmlUtils.skipCurrentTag(parser);
160 }
161 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800162
163 void dump(String prefix, PrintWriter pw) {
164 pw.print(prefix); pw.print("uid="); pw.println(getUid());
165 pw.print(prefix); pw.println("policies:");
166 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
167 if (pols != null) {
168 for (int i=0; i<pols.size(); i++) {
169 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
170 }
171 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700172 pw.print(prefix); pw.print("passwordQuality=0x");
173 pw.print(Integer.toHexString(passwordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800174 pw.print(" minimumPasswordLength=");
175 pw.println(minimumPasswordLength);
176 pw.print(prefix); pw.print("maximumTimeToUnlock=");
177 pw.println(maximumTimeToUnlock);
178 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
179 pw.println(maximumFailedPasswordsForWipe);
180 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800181 }
182
183 class MyPackageMonitor extends PackageMonitor {
184 public void onSomePackagesChanged() {
185 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800186 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800187 for (int i=mAdminList.size()-1; i>=0; i--) {
188 ActiveAdmin aa = mAdminList.get(i);
189 int change = isPackageDisappearing(aa.info.getPackageName());
190 if (change == PACKAGE_PERMANENT_CHANGE
191 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700192 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800193 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800194 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800195 mAdminList.remove(i);
196 } else if (isPackageModified(aa.info.getPackageName())) {
197 try {
198 mContext.getPackageManager().getReceiverInfo(
199 aa.info.getComponent(), 0);
200 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700201 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800202 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800203 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800204 mAdminList.remove(i);
205 }
206 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800207 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800208 if (removed) {
209 validatePasswordOwnerLocked();
210 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800211 }
212 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800213 }
214
215 /**
216 * Instantiates the service.
217 */
218 public DevicePolicyManagerService(Context context) {
219 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800220 mMonitor = new MyPackageMonitor();
221 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700222 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
223 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800224 }
225
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800226 private IPowerManager getIPowerManager() {
227 if (mIPowerManager == null) {
228 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
229 mIPowerManager = IPowerManager.Stub.asInterface(b);
230 }
231 return mIPowerManager;
232 }
233
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800234 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800235 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800236 if (admin != null
237 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
238 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
239 return admin;
240 }
241 return null;
242 }
243
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800244 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
245 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800246 final int callingUid = Binder.getCallingUid();
247 if (who != null) {
248 ActiveAdmin admin = mAdminMap.get(who);
249 if (admin == null) {
250 throw new SecurityException("No active admin " + who);
251 }
252 if (admin.getUid() != callingUid) {
253 throw new SecurityException("Admin " + who + " is not owned by uid "
254 + Binder.getCallingUid());
255 }
256 if (!admin.info.usesPolicy(reqPolicy)) {
257 throw new SecurityException("Admin " + admin.info.getComponent()
258 + " did not specify uses-policy for: "
259 + admin.info.getTagForPolicy(reqPolicy));
260 }
261 return admin;
262 } else {
263 final int N = mAdminList.size();
264 for (int i=0; i<N; i++) {
265 ActiveAdmin admin = mAdminList.get(i);
266 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
267 return admin;
268 }
269 }
270 throw new SecurityException("No active admin owned by uid "
271 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800272 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800273 }
274
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800275 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800276 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800277 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800278 mContext.sendBroadcast(intent);
279 }
280
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800281 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800282 final int N = mAdminList.size();
283 if (N > 0) {
284 for (int i=0; i<N; i++) {
285 ActiveAdmin admin = mAdminList.get(i);
286 if (admin.info.usesPolicy(reqPolicy)) {
287 sendAdminCommandLocked(admin, action);
288 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800289 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800290 }
291 }
292
Dianne Hackbornd6847842010-01-12 18:14:19 -0800293 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800294 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
295 if (admin != null) {
296 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800297 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800298 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800299 mAdminList.remove(admin);
300 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800301 validatePasswordOwnerLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800302 }
303 }
304
305 public DeviceAdminInfo findAdmin(ComponentName adminName) {
306 Intent resolveIntent = new Intent();
307 resolveIntent.setComponent(adminName);
308 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
309 resolveIntent, PackageManager.GET_META_DATA);
310 if (infos == null || infos.size() <= 0) {
311 throw new IllegalArgumentException("Unknown admin: " + adminName);
312 }
313
314 try {
315 return new DeviceAdminInfo(mContext, infos.get(0));
316 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700317 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800318 return null;
319 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700320 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800321 return null;
322 }
323 }
324
325 private static JournaledFile makeJournaledFile() {
326 final String base = "/data/system/device_policies.xml";
327 return new JournaledFile(new File(base), new File(base + ".tmp"));
328 }
329
330 private void saveSettingsLocked() {
331 JournaledFile journal = makeJournaledFile();
332 FileOutputStream stream = null;
333 try {
334 stream = new FileOutputStream(journal.chooseForWrite(), false);
335 XmlSerializer out = new FastXmlSerializer();
336 out.setOutput(stream, "utf-8");
337 out.startDocument(null, true);
338
339 out.startTag(null, "policies");
340
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800341 final int N = mAdminList.size();
342 for (int i=0; i<N; i++) {
343 ActiveAdmin ap = mAdminList.get(i);
344 if (ap != null) {
345 out.startTag(null, "admin");
346 out.attribute(null, "name", ap.info.getComponent().flattenToString());
347 ap.writeToXml(out);
348 out.endTag(null, "admin");
349 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800350 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800351
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800352 if (mPasswordOwner >= 0) {
353 out.startTag(null, "password-owner");
354 out.attribute(null, "value", Integer.toString(mPasswordOwner));
355 out.endTag(null, "password-owner");
356 }
357
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800358 if (mFailedPasswordAttempts != 0) {
359 out.startTag(null, "failed-password-attempts");
360 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
361 out.endTag(null, "failed-password-attempts");
362 }
363
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700364 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
365 out.startTag(null, "active-password");
366 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
367 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
368 out.endTag(null, "active-password");
369 }
370
371 out.endTag(null, "policies");
372
Dianne Hackbornd6847842010-01-12 18:14:19 -0800373 out.endDocument();
374 stream.close();
375 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700376 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800377 } catch (IOException e) {
378 try {
379 if (stream != null) {
380 stream.close();
381 }
382 } catch (IOException ex) {
383 // Ignore
384 }
385 journal.rollback();
386 }
387 }
388
Jim Miller284b62e2010-06-08 14:27:42 -0700389 private void sendChangedNotification() {
390 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
391 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
392 mContext.sendBroadcast(intent);
393 }
394
Dianne Hackbornd6847842010-01-12 18:14:19 -0800395 private void loadSettingsLocked() {
396 JournaledFile journal = makeJournaledFile();
397 FileInputStream stream = null;
398 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800399 try {
400 stream = new FileInputStream(file);
401 XmlPullParser parser = Xml.newPullParser();
402 parser.setInput(stream, null);
403
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800404 int type;
405 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
406 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800407 }
408 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800409 if (!"policies".equals(tag)) {
410 throw new XmlPullParserException(
411 "Settings do not start with policies tag: found " + tag);
412 }
413 type = parser.next();
414 int outerDepth = parser.getDepth();
415 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
416 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
417 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
418 continue;
419 }
420 tag = parser.getName();
421 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800422 String name = parser.getAttributeValue(null, "name");
423 try {
424 DeviceAdminInfo dai = findAdmin(
425 ComponentName.unflattenFromString(name));
426 if (dai != null) {
427 ActiveAdmin ap = new ActiveAdmin(dai);
428 ap.readFromXml(parser);
429 mAdminMap.put(ap.info.getComponent(), ap);
430 mAdminList.add(ap);
431 }
432 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700433 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800434 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800435 } else if ("failed-password-attempts".equals(tag)) {
436 mFailedPasswordAttempts = Integer.parseInt(
437 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800438 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800439 } else if ("password-owner".equals(tag)) {
440 mPasswordOwner = Integer.parseInt(
441 parser.getAttributeValue(null, "value"));
442 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700443 } else if ("active-password".equals(tag)) {
444 mActivePasswordQuality = Integer.parseInt(
445 parser.getAttributeValue(null, "quality"));
446 mActivePasswordLength = Integer.parseInt(
447 parser.getAttributeValue(null, "length"));
448 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800449 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700450 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800451 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800452 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800453 }
454 } catch (NullPointerException 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 (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700457 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800458 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700459 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700460 } catch (FileNotFoundException e) {
461 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800462 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700463 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800464 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700465 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800466 }
467 try {
468 if (stream != null) {
469 stream.close();
470 }
471 } catch (IOException e) {
472 // Ignore
473 }
474
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700475 // Validate that what we stored for the password quality matches
476 // sufficiently what is currently set. Note that this is only
477 // a sanity check in case the two get out of sync; this should
478 // never normally happen.
479 LockPatternUtils utils = new LockPatternUtils(mContext);
480 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
481 Slog.w(TAG, "Active password quality 0x"
482 + Integer.toHexString(mActivePasswordQuality)
483 + " does not match actual quality 0x"
484 + Integer.toHexString(utils.getActivePasswordQuality()));
485 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
486 mActivePasswordLength = 0;
487 }
488
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800489 validatePasswordOwnerLocked();
490
Dianne Hackborn254cb442010-01-27 19:23:59 -0800491 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800492 if (timeMs <= 0) {
493 timeMs = Integer.MAX_VALUE;
494 }
495 try {
496 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
497 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700498 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800499 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800500 }
501
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700502 static void validateQualityConstant(int quality) {
503 switch (quality) {
504 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
505 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
506 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
507 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
508 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
509 return;
510 }
511 throw new IllegalArgumentException("Invalid quality constant: 0x"
512 + Integer.toHexString(quality));
513 }
514
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800515 void validatePasswordOwnerLocked() {
516 if (mPasswordOwner >= 0) {
517 boolean haveOwner = false;
518 for (int i=mAdminList.size()-1; i>=0; i--) {
519 if (mAdminList.get(i).getUid() == mPasswordOwner) {
520 haveOwner = true;
521 break;
522 }
523 }
524 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700525 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800526 + " no longer active; disabling");
527 mPasswordOwner = -1;
528 }
529 }
530 }
531
Dianne Hackbornd6847842010-01-12 18:14:19 -0800532 public void systemReady() {
533 synchronized (this) {
534 loadSettingsLocked();
535 }
536 }
537
538 public void setActiveAdmin(ComponentName adminReceiver) {
539 mContext.enforceCallingOrSelfPermission(
540 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
541
542 DeviceAdminInfo info = findAdmin(adminReceiver);
543 if (info == null) {
544 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
545 }
546 synchronized (this) {
547 long ident = Binder.clearCallingIdentity();
548 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800549 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
550 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800551 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800552 ActiveAdmin admin = new ActiveAdmin(info);
553 mAdminMap.put(adminReceiver, admin);
554 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800555 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800556 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800557 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800558 } finally {
559 Binder.restoreCallingIdentity(ident);
560 }
561 }
562 }
563
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800564 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800565 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800566 return getActiveAdminUncheckedLocked(adminReceiver) != null;
567 }
568 }
569
570 public List<ComponentName> getActiveAdmins() {
571 synchronized (this) {
572 final int N = mAdminList.size();
573 if (N <= 0) {
574 return null;
575 }
576 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
577 for (int i=0; i<N; i++) {
578 res.add(mAdminList.get(i).info.getComponent());
579 }
580 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800581 }
582 }
583
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800584 public boolean packageHasActiveAdmins(String packageName) {
585 synchronized (this) {
586 final int N = mAdminList.size();
587 for (int i=0; i<N; i++) {
588 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
589 return true;
590 }
591 }
592 return false;
593 }
594 }
595
Dianne Hackbornd6847842010-01-12 18:14:19 -0800596 public void removeActiveAdmin(ComponentName adminReceiver) {
597 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800598 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
599 if (admin == null) {
600 return;
601 }
602 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800603 mContext.enforceCallingOrSelfPermission(
604 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
605 }
606 long ident = Binder.clearCallingIdentity();
607 try {
608 removeActiveAdminLocked(adminReceiver);
609 } finally {
610 Binder.restoreCallingIdentity(ident);
611 }
612 }
613 }
614
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700615 public void setPasswordQuality(ComponentName who, int quality) {
616 validateQualityConstant(quality);
617
Dianne Hackbornd6847842010-01-12 18:14:19 -0800618 synchronized (this) {
619 if (who == null) {
620 throw new NullPointerException("ComponentName is null");
621 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800622 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
623 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700624 if (ap.passwordQuality != quality) {
625 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800626 saveSettingsLocked();
627 }
628 }
629 }
630
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800631 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800632 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800633 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800634
635 if (who != null) {
636 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800637 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800638 }
639
640 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800641 for (int i=0; i<N; i++) {
642 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800643 if (mode < admin.passwordQuality) {
644 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800645 }
646 }
647 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800648 }
649 }
650
Dianne Hackborn254cb442010-01-27 19:23:59 -0800651 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800652 synchronized (this) {
653 if (who == null) {
654 throw new NullPointerException("ComponentName is null");
655 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800656 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
657 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800658 if (ap.minimumPasswordLength != length) {
659 ap.minimumPasswordLength = length;
660 saveSettingsLocked();
661 }
662 }
663 }
664
Dianne Hackborn254cb442010-01-27 19:23:59 -0800665 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800666 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800667 int length = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800668
669 if (who != null) {
670 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
671 return admin != null ? admin.minimumPasswordLength : length;
672 }
673
674 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800675 for (int i=0; i<N; i++) {
676 ActiveAdmin admin = mAdminList.get(i);
677 if (length < admin.minimumPasswordLength) {
678 length = admin.minimumPasswordLength;
679 }
680 }
681 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800682 }
683 }
684
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800685 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800686 synchronized (this) {
687 // This API can only be called by an active device admin,
688 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800689 getActiveAdminForCallerLocked(null,
690 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800691 return mActivePasswordQuality >= getPasswordQuality(null)
Dianne Hackborn254cb442010-01-27 19:23:59 -0800692 && mActivePasswordLength >= getPasswordMinimumLength(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800693 }
694 }
695
696 public int getCurrentFailedPasswordAttempts() {
697 synchronized (this) {
698 // This API can only be called by an active device admin,
699 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800700 getActiveAdminForCallerLocked(null,
701 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800702 return mFailedPasswordAttempts;
703 }
704 }
705
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800706 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
707 synchronized (this) {
708 // This API can only be called by an active device admin,
709 // so try to retrieve it to check that the caller is one.
710 getActiveAdminForCallerLocked(who,
711 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
712 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
713 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
714 if (ap.maximumFailedPasswordsForWipe != num) {
715 ap.maximumFailedPasswordsForWipe = num;
716 saveSettingsLocked();
717 }
718 }
719 }
720
Dianne Hackborn254cb442010-01-27 19:23:59 -0800721 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800722 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800723 int count = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800724
725 if (who != null) {
726 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
727 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
728 }
729
730 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800731 for (int i=0; i<N; i++) {
732 ActiveAdmin admin = mAdminList.get(i);
733 if (count == 0) {
734 count = admin.maximumFailedPasswordsForWipe;
735 } else if (admin.maximumFailedPasswordsForWipe != 0
736 && count > admin.maximumFailedPasswordsForWipe) {
737 count = admin.maximumFailedPasswordsForWipe;
738 }
739 }
740 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800741 }
742 }
743
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800744 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800745 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800746 synchronized (this) {
747 // This API can only be called by an active device admin,
748 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800749 getActiveAdminForCallerLocked(null,
750 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800751 quality = getPasswordQuality(null);
752 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700753 int realQuality = LockPatternUtils.computePasswordQuality(password);
754 if (realQuality < quality) {
755 Slog.w(TAG, "resetPassword: password quality 0x"
756 + Integer.toHexString(quality)
757 + " does not meet required quality 0x"
758 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800759 return false;
760 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700761 quality = realQuality;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800762 }
763 int length = getPasswordMinimumLength(null);
764 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700765 Slog.w(TAG, "resetPassword: password length " + password.length()
766 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800767 return false;
768 }
769 }
770
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800771 int callingUid = Binder.getCallingUid();
772 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700773 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800774 return false;
775 }
776
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800777 // Don't do this with the lock held, because it is going to call
778 // back in to the service.
779 long ident = Binder.clearCallingIdentity();
780 try {
781 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800782 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700783 synchronized (this) {
784 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
785 != 0 ? callingUid : -1;
786 if (mPasswordOwner != newOwner) {
787 mPasswordOwner = newOwner;
788 saveSettingsLocked();
789 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800790 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800791 } finally {
792 Binder.restoreCallingIdentity(ident);
793 }
794
795 return true;
796 }
797
Dianne Hackbornd6847842010-01-12 18:14:19 -0800798 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
799 synchronized (this) {
800 if (who == null) {
801 throw new NullPointerException("ComponentName is null");
802 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800803 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -0800804 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800805 if (ap.maximumTimeToUnlock != timeMs) {
806 ap.maximumTimeToUnlock = timeMs;
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800807
808 long ident = Binder.clearCallingIdentity();
809 try {
810 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800811
812 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800813 if (timeMs <= 0) {
814 timeMs = Integer.MAX_VALUE;
815 }
Dianne Hackborn254cb442010-01-27 19:23:59 -0800816
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800817 try {
818 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
819 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700820 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800821 }
822 } finally {
823 Binder.restoreCallingIdentity(ident);
824 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800825 }
826 }
827 }
828
Dianne Hackborn254cb442010-01-27 19:23:59 -0800829 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800830 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800831 long time = 0;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800832
833 if (who != null) {
834 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
835 return admin != null ? admin.maximumTimeToUnlock : time;
836 }
837
838 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800839 for (int i=0; i<N; i++) {
840 ActiveAdmin admin = mAdminList.get(i);
841 if (time == 0) {
842 time = admin.maximumTimeToUnlock;
843 } else if (admin.maximumTimeToUnlock != 0
844 && time > admin.maximumTimeToUnlock) {
845 time = admin.maximumTimeToUnlock;
846 }
847 }
848 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800849 }
850 }
851
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800852 public void lockNow() {
853 synchronized (this) {
854 // This API can only be called by an active device admin,
855 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800856 getActiveAdminForCallerLocked(null,
857 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800858 long ident = Binder.clearCallingIdentity();
859 try {
860 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
861 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
862 } catch (RemoteException e) {
863 } finally {
864 Binder.restoreCallingIdentity(ident);
865 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800866 }
867 }
868
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800869 void wipeDataLocked(int flags) {
Dianne Hackborn42499172010-10-15 18:45:07 -0700870 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
871 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
872 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
873 mWakeLock.acquire(10000);
874 mContext.startService(intent);
875 } else {
876 try {
877 RecoverySystem.rebootWipeUserData(mContext);
878 } catch (IOException e) {
879 Slog.w(TAG, "Failed requesting data wipe", e);
880 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800881 }
882 }
883
Dianne Hackbornd6847842010-01-12 18:14:19 -0800884 public void wipeData(int flags) {
885 synchronized (this) {
886 // This API can only be called by an active device admin,
887 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800888 getActiveAdminForCallerLocked(null,
889 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800890 long ident = Binder.clearCallingIdentity();
891 try {
892 wipeDataLocked(flags);
893 } finally {
894 Binder.restoreCallingIdentity(ident);
895 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800896 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800897 }
898
899 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
900 mContext.enforceCallingOrSelfPermission(
901 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
902
903 synchronized (this) {
904 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
905 if (admin == null) {
906 try {
907 result.sendResult(null);
908 } catch (RemoteException e) {
909 }
910 return;
911 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800912 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800913 intent.setComponent(admin.info.getComponent());
914 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
915 @Override
916 public void onReceive(Context context, Intent intent) {
917 try {
918 result.sendResult(getResultExtras(false));
919 } catch (RemoteException e) {
920 }
921 }
922 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800923 }
924 }
925
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800926 public void setActivePasswordState(int quality, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800927 mContext.enforceCallingOrSelfPermission(
928 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
929
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700930 validateQualityConstant(quality);
931
Dianne Hackbornd6847842010-01-12 18:14:19 -0800932 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800933 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Dianne Hackbornd6847842010-01-12 18:14:19 -0800934 || mFailedPasswordAttempts != 0) {
935 long ident = Binder.clearCallingIdentity();
936 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800937 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800938 mActivePasswordLength = length;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700939 mFailedPasswordAttempts = 0;
940 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800941 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800942 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800943 } finally {
944 Binder.restoreCallingIdentity(ident);
945 }
946 }
947 }
948 }
949
950 public void reportFailedPasswordAttempt() {
951 mContext.enforceCallingOrSelfPermission(
952 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
953
954 synchronized (this) {
955 long ident = Binder.clearCallingIdentity();
956 try {
957 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800958 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800959 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800960 if (max > 0 && mFailedPasswordAttempts >= max) {
961 wipeDataLocked(0);
962 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800963 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800964 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800965 } finally {
966 Binder.restoreCallingIdentity(ident);
967 }
968 }
969 }
970
971 public void reportSuccessfulPasswordAttempt() {
972 mContext.enforceCallingOrSelfPermission(
973 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
974
975 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800976 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800977 long ident = Binder.clearCallingIdentity();
978 try {
979 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800980 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800981 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800982 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800983 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800984 } finally {
985 Binder.restoreCallingIdentity(ident);
986 }
987 }
988 }
989 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800990
991 @Override
992 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
993 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
994 != PackageManager.PERMISSION_GRANTED) {
995
996 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
997 + Binder.getCallingPid()
998 + ", uid=" + Binder.getCallingUid());
999 return;
1000 }
1001
1002 final Printer p = new PrintWriterPrinter(pw);
1003
1004 synchronized (this) {
1005 p.println("Current Device Policy Manager state:");
1006
1007 p.println(" Enabled Device Admins:");
1008 final int N = mAdminList.size();
1009 for (int i=0; i<N; i++) {
1010 ActiveAdmin ap = mAdminList.get(i);
1011 if (ap != null) {
1012 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1013 pw.println(":");
1014 ap.dump(" ", pw);
1015 }
1016 }
1017
1018 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001019 pw.print(" mActivePasswordQuality=0x");
1020 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001021 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
1022 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1023 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1024 }
1025 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001026}