blob: 7de510ec5763ad7a9250cda37b90ff209f588ff1 [file] [log] [blame]
Dianne Hackbornd6847842010-01-12 18:14:19 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080019import com.android.internal.content.PackageMonitor;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080020import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070021import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080022import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080023import com.android.internal.widget.LockPatternUtils;
Dianne Hackbornd6847842010-01-12 18:14:19 -080024
25import org.xmlpull.v1.XmlPullParser;
26import org.xmlpull.v1.XmlPullParserException;
27import org.xmlpull.v1.XmlSerializer;
28
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080029import android.app.Activity;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080030import android.app.admin.DeviceAdminInfo;
31import android.app.admin.DeviceAdminReceiver;
32import android.app.admin.DevicePolicyManager;
33import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080034import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080035import android.content.ComponentName;
36import android.content.Context;
37import android.content.Intent;
38import android.content.pm.PackageManager;
39import android.content.pm.ResolveInfo;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080040import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080041import android.os.Binder;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080042import android.os.IBinder;
43import android.os.IPowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080044import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080045import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080046import android.os.RemoteException;
47import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080048import android.os.SystemClock;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -070049import android.util.Slog;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080050import android.util.PrintWriterPrinter;
51import android.util.Printer;
Dianne Hackbornd6847842010-01-12 18:14:19 -080052import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080053import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080054
55import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080056import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080057import java.io.FileInputStream;
58import java.io.FileOutputStream;
59import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080060import java.io.PrintWriter;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080061import java.util.ArrayList;
62import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080063import java.util.List;
64
65/**
66 * Implementation of the device policy APIs.
67 */
68public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080069 static final String TAG = "DevicePolicyManagerService";
Konstantin Lopyrev32558232010-05-20 16:18:05 -070070
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080071 final Context mContext;
72 final MyPackageMonitor mMonitor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080073
Dianne Hackborndf83afa2010-01-20 13:37:26 -080074 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070075
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080076 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077 int mActivePasswordLength = 0;
78 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070079
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080080 int mPasswordOwner = -1;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070081
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080082 final HashMap<ComponentName, ActiveAdmin> mAdminMap
83 = new HashMap<ComponentName, ActiveAdmin>();
84 final ArrayList<ActiveAdmin> mAdminList
85 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -070086
Dianne Hackbornd6847842010-01-12 18:14:19 -080087 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -080088 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070089
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080090 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080091 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070092 int passwordHistoryLength = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -080093 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080094 int maximumFailedPasswordsForWipe = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070095
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080096 ActiveAdmin(DeviceAdminInfo _info) {
97 info = _info;
98 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -070099
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800100 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700101
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800102 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));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700114 out.endTag(null, "min-password-length");
115 }
116 if(passwordHistoryLength > 0) {
117 out.startTag(null, "password-history-length");
118 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
119 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800120 }
121 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800122 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800123 out.startTag(null, "max-time-to-unlock");
124 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
125 out.endTag(null, "max-time-to-unlock");
126 }
127 if (maximumFailedPasswordsForWipe != 0) {
128 out.startTag(null, "max-failed-password-wipe");
129 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
130 out.endTag(null, "max-failed-password-wipe");
131 }
132 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700133
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800134 void readFromXml(XmlPullParser parser)
135 throws XmlPullParserException, IOException {
136 int outerDepth = parser.getDepth();
137 int type;
138 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
139 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
140 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
141 continue;
142 }
143 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800144 if ("policies".equals(tag)) {
145 info.readPoliciesFromXml(parser);
146 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800147 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800148 parser.getAttributeValue(null, "value"));
149 } else if ("min-password-length".equals(tag)) {
150 minimumPasswordLength = Integer.parseInt(
151 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700152 } else if ("password-history-length".equals(tag)) {
153 passwordHistoryLength = Integer.parseInt(
154 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800155 } else if ("max-time-to-unlock".equals(tag)) {
156 maximumTimeToUnlock = Long.parseLong(
157 parser.getAttributeValue(null, "value"));
158 } else if ("max-failed-password-wipe".equals(tag)) {
159 maximumFailedPasswordsForWipe = Integer.parseInt(
160 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800161 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700162 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800163 }
164 XmlUtils.skipCurrentTag(parser);
165 }
166 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700167
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800168 void dump(String prefix, PrintWriter pw) {
169 pw.print(prefix); pw.print("uid="); pw.println(getUid());
170 pw.print(prefix); pw.println("policies:");
171 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
172 if (pols != null) {
173 for (int i=0; i<pols.size(); i++) {
174 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
175 }
176 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700177 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700178 pw.println(Integer.toHexString(passwordQuality));
179 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800180 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700181 pw.print(prefix); pw.print("passwordHistoryLength=");
182 pw.println(passwordHistoryLength);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800183 pw.print(prefix); pw.print("maximumTimeToUnlock=");
184 pw.println(maximumTimeToUnlock);
185 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
186 pw.println(maximumFailedPasswordsForWipe);
187 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800188 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700189
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800190 class MyPackageMonitor extends PackageMonitor {
191 public void onSomePackagesChanged() {
192 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800193 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800194 for (int i=mAdminList.size()-1; i>=0; i--) {
195 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700196 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800197 if (change == PACKAGE_PERMANENT_CHANGE
198 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700199 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800200 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800201 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800202 mAdminList.remove(i);
203 } else if (isPackageModified(aa.info.getPackageName())) {
204 try {
205 mContext.getPackageManager().getReceiverInfo(
206 aa.info.getComponent(), 0);
207 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700208 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800209 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800210 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800211 mAdminList.remove(i);
212 }
213 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800214 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800215 if (removed) {
216 validatePasswordOwnerLocked();
217 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800218 }
219 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800220 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700221
Dianne Hackbornd6847842010-01-12 18:14:19 -0800222 /**
223 * Instantiates the service.
224 */
225 public DevicePolicyManagerService(Context context) {
226 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800227 mMonitor = new MyPackageMonitor();
228 mMonitor.register(context, true);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800229 }
230
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800231 private IPowerManager getIPowerManager() {
232 if (mIPowerManager == null) {
233 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
234 mIPowerManager = IPowerManager.Stub.asInterface(b);
235 }
236 return mIPowerManager;
237 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700238
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800239 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800240 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800241 if (admin != null
242 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
243 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
244 return admin;
245 }
246 return null;
247 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700248
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800249 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
250 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800251 final int callingUid = Binder.getCallingUid();
252 if (who != null) {
253 ActiveAdmin admin = mAdminMap.get(who);
254 if (admin == null) {
255 throw new SecurityException("No active admin " + who);
256 }
257 if (admin.getUid() != callingUid) {
258 throw new SecurityException("Admin " + who + " is not owned by uid "
259 + Binder.getCallingUid());
260 }
261 if (!admin.info.usesPolicy(reqPolicy)) {
262 throw new SecurityException("Admin " + admin.info.getComponent()
263 + " did not specify uses-policy for: "
264 + admin.info.getTagForPolicy(reqPolicy));
265 }
266 return admin;
267 } else {
268 final int N = mAdminList.size();
269 for (int i=0; i<N; i++) {
270 ActiveAdmin admin = mAdminList.get(i);
271 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
272 return admin;
273 }
274 }
275 throw new SecurityException("No active admin owned by uid "
276 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800277 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800278 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700279
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800280 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800281 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800282 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800283 mContext.sendBroadcast(intent);
284 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700285
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800286 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800287 final int N = mAdminList.size();
288 if (N > 0) {
289 for (int i=0; i<N; i++) {
290 ActiveAdmin admin = mAdminList.get(i);
291 if (admin.info.usesPolicy(reqPolicy)) {
292 sendAdminCommandLocked(admin, action);
293 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800294 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800295 }
296 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700297
Dianne Hackbornd6847842010-01-12 18:14:19 -0800298 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800299 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
300 if (admin != null) {
301 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800302 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800303 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800304 mAdminList.remove(admin);
305 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800306 validatePasswordOwnerLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800307 }
308 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700309
Dianne Hackbornd6847842010-01-12 18:14:19 -0800310 public DeviceAdminInfo findAdmin(ComponentName adminName) {
311 Intent resolveIntent = new Intent();
312 resolveIntent.setComponent(adminName);
313 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
314 resolveIntent, PackageManager.GET_META_DATA);
315 if (infos == null || infos.size() <= 0) {
316 throw new IllegalArgumentException("Unknown admin: " + adminName);
317 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700318
Dianne Hackbornd6847842010-01-12 18:14:19 -0800319 try {
320 return new DeviceAdminInfo(mContext, infos.get(0));
321 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700322 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800323 return null;
324 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700325 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800326 return null;
327 }
328 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700329
Dianne Hackbornd6847842010-01-12 18:14:19 -0800330 private static JournaledFile makeJournaledFile() {
331 final String base = "/data/system/device_policies.xml";
332 return new JournaledFile(new File(base), new File(base + ".tmp"));
333 }
334
335 private void saveSettingsLocked() {
336 JournaledFile journal = makeJournaledFile();
337 FileOutputStream stream = null;
338 try {
339 stream = new FileOutputStream(journal.chooseForWrite(), false);
340 XmlSerializer out = new FastXmlSerializer();
341 out.setOutput(stream, "utf-8");
342 out.startDocument(null, true);
343
344 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700345
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800346 final int N = mAdminList.size();
347 for (int i=0; i<N; i++) {
348 ActiveAdmin ap = mAdminList.get(i);
349 if (ap != null) {
350 out.startTag(null, "admin");
351 out.attribute(null, "name", ap.info.getComponent().flattenToString());
352 ap.writeToXml(out);
353 out.endTag(null, "admin");
354 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800355 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700356
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800357 if (mPasswordOwner >= 0) {
358 out.startTag(null, "password-owner");
359 out.attribute(null, "value", Integer.toString(mPasswordOwner));
360 out.endTag(null, "password-owner");
361 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700362
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800363 if (mFailedPasswordAttempts != 0) {
364 out.startTag(null, "failed-password-attempts");
365 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
366 out.endTag(null, "failed-password-attempts");
367 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700368
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700369 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
370 out.startTag(null, "active-password");
371 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
372 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
373 out.endTag(null, "active-password");
374 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700375
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700376 out.endTag(null, "policies");
377
Dianne Hackbornd6847842010-01-12 18:14:19 -0800378 out.endDocument();
379 stream.close();
380 journal.commit();
381 } catch (IOException e) {
382 try {
383 if (stream != null) {
384 stream.close();
385 }
386 } catch (IOException ex) {
387 // Ignore
388 }
389 journal.rollback();
390 }
391 }
392
393 private void loadSettingsLocked() {
394 JournaledFile journal = makeJournaledFile();
395 FileInputStream stream = null;
396 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800397 try {
398 stream = new FileInputStream(file);
399 XmlPullParser parser = Xml.newPullParser();
400 parser.setInput(stream, null);
401
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800402 int type;
403 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
404 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800405 }
406 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800407 if (!"policies".equals(tag)) {
408 throw new XmlPullParserException(
409 "Settings do not start with policies tag: found " + tag);
410 }
411 type = parser.next();
412 int outerDepth = parser.getDepth();
413 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
414 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
415 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
416 continue;
417 }
418 tag = parser.getName();
419 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800420 String name = parser.getAttributeValue(null, "name");
421 try {
422 DeviceAdminInfo dai = findAdmin(
423 ComponentName.unflattenFromString(name));
424 if (dai != null) {
425 ActiveAdmin ap = new ActiveAdmin(dai);
426 ap.readFromXml(parser);
427 mAdminMap.put(ap.info.getComponent(), ap);
428 mAdminList.add(ap);
429 }
430 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700431 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800432 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800433 } else if ("failed-password-attempts".equals(tag)) {
434 mFailedPasswordAttempts = Integer.parseInt(
435 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800436 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800437 } else if ("password-owner".equals(tag)) {
438 mPasswordOwner = Integer.parseInt(
439 parser.getAttributeValue(null, "value"));
440 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700441 } else if ("active-password".equals(tag)) {
442 mActivePasswordQuality = Integer.parseInt(
443 parser.getAttributeValue(null, "quality"));
444 mActivePasswordLength = Integer.parseInt(
445 parser.getAttributeValue(null, "length"));
446 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800447 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700448 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800449 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800450 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800451 }
452 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700453 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800454 } catch (NumberFormatException 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 (XmlPullParserException 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 (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700459 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800460 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700461 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800462 }
463 try {
464 if (stream != null) {
465 stream.close();
466 }
467 } catch (IOException e) {
468 // Ignore
469 }
470
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700471 // Validate that what we stored for the password quality matches
472 // sufficiently what is currently set. Note that this is only
473 // a sanity check in case the two get out of sync; this should
474 // never normally happen.
475 LockPatternUtils utils = new LockPatternUtils(mContext);
476 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
477 Slog.w(TAG, "Active password quality 0x"
478 + Integer.toHexString(mActivePasswordQuality)
479 + " does not match actual quality 0x"
480 + Integer.toHexString(utils.getActivePasswordQuality()));
481 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
482 mActivePasswordLength = 0;
483 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700484
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800485 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700486
Dianne Hackborn254cb442010-01-27 19:23:59 -0800487 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800488 if (timeMs <= 0) {
489 timeMs = Integer.MAX_VALUE;
490 }
491 try {
492 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
493 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700494 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800495 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800496 }
497
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700498 static void validateQualityConstant(int quality) {
499 switch (quality) {
500 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
501 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
502 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
503 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
504 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
505 return;
506 }
507 throw new IllegalArgumentException("Invalid quality constant: 0x"
508 + Integer.toHexString(quality));
509 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700510
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800511 void validatePasswordOwnerLocked() {
512 if (mPasswordOwner >= 0) {
513 boolean haveOwner = false;
514 for (int i=mAdminList.size()-1; i>=0; i--) {
515 if (mAdminList.get(i).getUid() == mPasswordOwner) {
516 haveOwner = true;
517 break;
518 }
519 }
520 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700521 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800522 + " no longer active; disabling");
523 mPasswordOwner = -1;
524 }
525 }
526 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700527
Dianne Hackbornd6847842010-01-12 18:14:19 -0800528 public void systemReady() {
529 synchronized (this) {
530 loadSettingsLocked();
531 }
532 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700533
Dianne Hackbornd6847842010-01-12 18:14:19 -0800534 public void setActiveAdmin(ComponentName adminReceiver) {
535 mContext.enforceCallingOrSelfPermission(
536 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700537
Dianne Hackbornd6847842010-01-12 18:14:19 -0800538 DeviceAdminInfo info = findAdmin(adminReceiver);
539 if (info == null) {
540 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
541 }
542 synchronized (this) {
543 long ident = Binder.clearCallingIdentity();
544 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800545 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
546 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800547 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800548 ActiveAdmin admin = new ActiveAdmin(info);
549 mAdminMap.put(adminReceiver, admin);
550 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800551 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800552 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800553 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800554 } finally {
555 Binder.restoreCallingIdentity(ident);
556 }
557 }
558 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700559
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800560 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800561 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800562 return getActiveAdminUncheckedLocked(adminReceiver) != null;
563 }
564 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700565
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800566 public List<ComponentName> getActiveAdmins() {
567 synchronized (this) {
568 final int N = mAdminList.size();
569 if (N <= 0) {
570 return null;
571 }
572 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
573 for (int i=0; i<N; i++) {
574 res.add(mAdminList.get(i).info.getComponent());
575 }
576 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800577 }
578 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700579
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800580 public boolean packageHasActiveAdmins(String packageName) {
581 synchronized (this) {
582 final int N = mAdminList.size();
583 for (int i=0; i<N; i++) {
584 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
585 return true;
586 }
587 }
588 return false;
589 }
590 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700591
Dianne Hackbornd6847842010-01-12 18:14:19 -0800592 public void removeActiveAdmin(ComponentName adminReceiver) {
593 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800594 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
595 if (admin == null) {
596 return;
597 }
598 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800599 mContext.enforceCallingOrSelfPermission(
600 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
601 }
602 long ident = Binder.clearCallingIdentity();
603 try {
604 removeActiveAdminLocked(adminReceiver);
605 } finally {
606 Binder.restoreCallingIdentity(ident);
607 }
608 }
609 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700610
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700611 public void setPasswordQuality(ComponentName who, int quality) {
612 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700613
Dianne Hackbornd6847842010-01-12 18:14:19 -0800614 synchronized (this) {
615 if (who == null) {
616 throw new NullPointerException("ComponentName is null");
617 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800618 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
619 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700620 if (ap.passwordQuality != quality) {
621 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800622 saveSettingsLocked();
623 }
624 }
625 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700626
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800627 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800628 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800629 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700630
Dianne Hackborn254cb442010-01-27 19:23:59 -0800631 if (who != null) {
632 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800633 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800634 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700635
Dianne Hackborn254cb442010-01-27 19:23:59 -0800636 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800637 for (int i=0; i<N; i++) {
638 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800639 if (mode < admin.passwordQuality) {
640 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800641 }
642 }
643 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800644 }
645 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700646
Dianne Hackborn254cb442010-01-27 19:23:59 -0800647 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800648 synchronized (this) {
649 if (who == null) {
650 throw new NullPointerException("ComponentName is null");
651 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800652 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
653 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800654 if (ap.minimumPasswordLength != length) {
655 ap.minimumPasswordLength = length;
656 saveSettingsLocked();
657 }
658 }
659 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700660
Dianne Hackborn254cb442010-01-27 19:23:59 -0800661 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800662 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800663 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700664
Dianne Hackborn254cb442010-01-27 19:23:59 -0800665 if (who != null) {
666 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
667 return admin != null ? admin.minimumPasswordLength : length;
668 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700669
Dianne Hackborn254cb442010-01-27 19:23:59 -0800670 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800671 for (int i=0; i<N; i++) {
672 ActiveAdmin admin = mAdminList.get(i);
673 if (length < admin.minimumPasswordLength) {
674 length = admin.minimumPasswordLength;
675 }
676 }
677 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800678 }
679 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700680
681 public void setPasswordHistoryLength(ComponentName who, int length) {
682 synchronized (this) {
683 if (who == null) {
684 throw new NullPointerException("ComponentName is null");
685 }
686 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
687 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
688 if (ap.passwordHistoryLength != length) {
689 ap.passwordHistoryLength = length;
690 saveSettingsLocked();
691 }
692 }
693 }
694
695 public int getPasswordHistoryLength(ComponentName who) {
696 synchronized (this) {
697 int length = 0;
698
699 if (who != null) {
700 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
701 return admin != null ? admin.passwordHistoryLength : length;
702 }
703
704 final int N = mAdminList.size();
705 for (int i = 0; i < N; i++) {
706 ActiveAdmin admin = mAdminList.get(i);
707 if (length < admin.passwordHistoryLength) {
708 length = admin.passwordHistoryLength;
709 }
710 }
711 return length;
712 }
713 }
714
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800715 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800716 synchronized (this) {
717 // This API can only be called by an active device admin,
718 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800719 getActiveAdminForCallerLocked(null,
720 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800721 return mActivePasswordQuality >= getPasswordQuality(null)
Dianne Hackborn254cb442010-01-27 19:23:59 -0800722 && mActivePasswordLength >= getPasswordMinimumLength(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800723 }
724 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700725
Dianne Hackbornd6847842010-01-12 18:14:19 -0800726 public int getCurrentFailedPasswordAttempts() {
727 synchronized (this) {
728 // This API can only be called by an active device admin,
729 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800730 getActiveAdminForCallerLocked(null,
731 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800732 return mFailedPasswordAttempts;
733 }
734 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700735
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800736 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
737 synchronized (this) {
738 // This API can only be called by an active device admin,
739 // so try to retrieve it to check that the caller is one.
740 getActiveAdminForCallerLocked(who,
741 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
742 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
743 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
744 if (ap.maximumFailedPasswordsForWipe != num) {
745 ap.maximumFailedPasswordsForWipe = num;
746 saveSettingsLocked();
747 }
748 }
749 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700750
Dianne Hackborn254cb442010-01-27 19:23:59 -0800751 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800752 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800753 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700754
Dianne Hackborn254cb442010-01-27 19:23:59 -0800755 if (who != null) {
756 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
757 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
758 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700759
Dianne Hackborn254cb442010-01-27 19:23:59 -0800760 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800761 for (int i=0; i<N; i++) {
762 ActiveAdmin admin = mAdminList.get(i);
763 if (count == 0) {
764 count = admin.maximumFailedPasswordsForWipe;
765 } else if (admin.maximumFailedPasswordsForWipe != 0
766 && count > admin.maximumFailedPasswordsForWipe) {
767 count = admin.maximumFailedPasswordsForWipe;
768 }
769 }
770 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800771 }
772 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700773
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800774 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800775 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800776 synchronized (this) {
777 // This API can only be called by an active device admin,
778 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800779 getActiveAdminForCallerLocked(null,
780 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800781 quality = getPasswordQuality(null);
782 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700783 int realQuality = LockPatternUtils.computePasswordQuality(password);
784 if (realQuality < quality) {
785 Slog.w(TAG, "resetPassword: password quality 0x"
786 + Integer.toHexString(quality)
787 + " does not meet required quality 0x"
788 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800789 return false;
790 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700791 quality = realQuality;
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800792 }
793 int length = getPasswordMinimumLength(null);
794 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700795 Slog.w(TAG, "resetPassword: password length " + password.length()
796 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800797 return false;
798 }
799 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700800
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800801 int callingUid = Binder.getCallingUid();
802 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700803 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800804 return false;
805 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700806
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800807 // Don't do this with the lock held, because it is going to call
808 // back in to the service.
809 long ident = Binder.clearCallingIdentity();
810 try {
811 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800812 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700813 synchronized (this) {
814 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
815 != 0 ? callingUid : -1;
816 if (mPasswordOwner != newOwner) {
817 mPasswordOwner = newOwner;
818 saveSettingsLocked();
819 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800820 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800821 } finally {
822 Binder.restoreCallingIdentity(ident);
823 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700824
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800825 return true;
826 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700827
Dianne Hackbornd6847842010-01-12 18:14:19 -0800828 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
829 synchronized (this) {
830 if (who == null) {
831 throw new NullPointerException("ComponentName is null");
832 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800833 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -0800834 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800835 if (ap.maximumTimeToUnlock != timeMs) {
836 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700837
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800838 long ident = Binder.clearCallingIdentity();
839 try {
840 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700841
Dianne Hackborn254cb442010-01-27 19:23:59 -0800842 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800843 if (timeMs <= 0) {
844 timeMs = Integer.MAX_VALUE;
845 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700846
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800847 try {
848 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
849 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700850 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800851 }
852 } finally {
853 Binder.restoreCallingIdentity(ident);
854 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800855 }
856 }
857 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700858
Dianne Hackborn254cb442010-01-27 19:23:59 -0800859 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800860 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800861 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700862
Dianne Hackborn254cb442010-01-27 19:23:59 -0800863 if (who != null) {
864 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
865 return admin != null ? admin.maximumTimeToUnlock : time;
866 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700867
Dianne Hackborn254cb442010-01-27 19:23:59 -0800868 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800869 for (int i=0; i<N; i++) {
870 ActiveAdmin admin = mAdminList.get(i);
871 if (time == 0) {
872 time = admin.maximumTimeToUnlock;
873 } else if (admin.maximumTimeToUnlock != 0
874 && time > admin.maximumTimeToUnlock) {
875 time = admin.maximumTimeToUnlock;
876 }
877 }
878 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800879 }
880 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700881
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800882 public void lockNow() {
883 synchronized (this) {
884 // This API can only be called by an active device admin,
885 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800886 getActiveAdminForCallerLocked(null,
887 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800888 long ident = Binder.clearCallingIdentity();
889 try {
890 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
891 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
892 } catch (RemoteException e) {
893 } finally {
894 Binder.restoreCallingIdentity(ident);
895 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800896 }
897 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700898
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800899 void wipeDataLocked(int flags) {
900 try {
901 RecoverySystem.rebootWipeUserData(mContext);
902 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700903 Slog.w(TAG, "Failed requesting data wipe", e);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800904 }
905 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700906
Dianne Hackbornd6847842010-01-12 18:14:19 -0800907 public void wipeData(int flags) {
908 synchronized (this) {
909 // This API can only be called by an active device admin,
910 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800911 getActiveAdminForCallerLocked(null,
912 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800913 long ident = Binder.clearCallingIdentity();
914 try {
915 wipeDataLocked(flags);
916 } finally {
917 Binder.restoreCallingIdentity(ident);
918 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800919 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800920 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700921
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800922 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
923 mContext.enforceCallingOrSelfPermission(
924 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700925
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800926 synchronized (this) {
927 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
928 if (admin == null) {
929 try {
930 result.sendResult(null);
931 } catch (RemoteException e) {
932 }
933 return;
934 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800935 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800936 intent.setComponent(admin.info.getComponent());
937 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
938 @Override
939 public void onReceive(Context context, Intent intent) {
940 try {
941 result.sendResult(getResultExtras(false));
942 } catch (RemoteException e) {
943 }
944 }
945 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800946 }
947 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700948
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800949 public void setActivePasswordState(int quality, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800950 mContext.enforceCallingOrSelfPermission(
951 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700952
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700953 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700954
Dianne Hackbornd6847842010-01-12 18:14:19 -0800955 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800956 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Dianne Hackbornd6847842010-01-12 18:14:19 -0800957 || mFailedPasswordAttempts != 0) {
958 long ident = Binder.clearCallingIdentity();
959 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800960 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800961 mActivePasswordLength = length;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700962 mFailedPasswordAttempts = 0;
963 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800964 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800965 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800966 } finally {
967 Binder.restoreCallingIdentity(ident);
968 }
969 }
970 }
971 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700972
Dianne Hackbornd6847842010-01-12 18:14:19 -0800973 public void reportFailedPasswordAttempt() {
974 mContext.enforceCallingOrSelfPermission(
975 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700976
Dianne Hackbornd6847842010-01-12 18:14:19 -0800977 synchronized (this) {
978 long ident = Binder.clearCallingIdentity();
979 try {
980 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800981 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800982 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800983 if (max > 0 && mFailedPasswordAttempts >= max) {
984 wipeDataLocked(0);
985 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800986 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800987 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800988 } finally {
989 Binder.restoreCallingIdentity(ident);
990 }
991 }
992 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700993
Dianne Hackbornd6847842010-01-12 18:14:19 -0800994 public void reportSuccessfulPasswordAttempt() {
995 mContext.enforceCallingOrSelfPermission(
996 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700997
Dianne Hackbornd6847842010-01-12 18:14:19 -0800998 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800999 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001000 long ident = Binder.clearCallingIdentity();
1001 try {
1002 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001003 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001004 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001005 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001006 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001007 } finally {
1008 Binder.restoreCallingIdentity(ident);
1009 }
1010 }
1011 }
1012 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001013
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001014 @Override
1015 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1016 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1017 != PackageManager.PERMISSION_GRANTED) {
1018
1019 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1020 + Binder.getCallingPid()
1021 + ", uid=" + Binder.getCallingUid());
1022 return;
1023 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001024
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001025 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001026
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001027 synchronized (this) {
1028 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001029
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001030 p.println(" Enabled Device Admins:");
1031 final int N = mAdminList.size();
1032 for (int i=0; i<N; i++) {
1033 ActiveAdmin ap = mAdminList.get(i);
1034 if (ap != null) {
1035 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1036 pw.println(":");
1037 ap.dump(" ", pw);
1038 }
1039 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001040
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001041 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001042 pw.print(" mActivePasswordQuality=0x");
1043 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001044 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
1045 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1046 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1047 }
1048 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001049}