blob: 0c3a0e6dde5edf55e4bad22114f093b6d7993805 [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;
Oscar Montemayor69238c62010-08-03 10:51:06 -070036import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080037import 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 Hackborndf83afa2010-01-20 13:37:26 -080045import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080046import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080047import android.os.RemoteException;
48import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080049import android.os.SystemClock;
Oscar Montemayor69238c62010-08-03 10:51:06 -070050import android.net.Proxy;
51import android.provider.Settings;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -070052import android.util.Slog;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080053import android.util.PrintWriterPrinter;
54import android.util.Printer;
Dianne Hackbornd6847842010-01-12 18:14:19 -080055import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080056import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080057
58import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080059import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080060import java.io.FileInputStream;
61import java.io.FileOutputStream;
62import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080063import java.io.PrintWriter;
Oscar Montemayor69238c62010-08-03 10:51:06 -070064import java.net.InetSocketAddress;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080065import java.util.ArrayList;
66import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080067import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070068import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080069
70/**
71 * Implementation of the device policy APIs.
72 */
73public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080074 static final String TAG = "DevicePolicyManagerService";
Konstantin Lopyrev32558232010-05-20 16:18:05 -070075
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080076 final Context mContext;
77 final MyPackageMonitor mMonitor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080078
Dianne Hackborndf83afa2010-01-20 13:37:26 -080079 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070080
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080081 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080082 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -070083 int mActivePasswordUpperCase = 0;
84 int mActivePasswordLowerCase = 0;
85 int mActivePasswordLetters = 0;
86 int mActivePasswordNumeric = 0;
87 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -070088 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -080089 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070090
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080091 int mPasswordOwner = -1;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070092
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080093 final HashMap<ComponentName, ActiveAdmin> mAdminMap
94 = new HashMap<ComponentName, ActiveAdmin>();
95 final ArrayList<ActiveAdmin> mAdminList
96 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -070097
Dianne Hackbornd6847842010-01-12 18:14:19 -080098 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -080099 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700100
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800101 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800102 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700103 int passwordHistoryLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700104 int minimumPasswordUpperCase = 0;
105 int minimumPasswordLowerCase = 0;
106 int minimumPasswordLetters = 1;
107 int minimumPasswordNumeric = 1;
108 int minimumPasswordSymbols = 1;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700109 int minimumPasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800110 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800111 int maximumFailedPasswordsForWipe = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700112
Oscar Montemayor69238c62010-08-03 10:51:06 -0700113 // TODO: review implementation decisions with frameworks team
114 boolean specifiesGlobalProxy = false;
115 String globalProxySpec = null;
116 String globalProxyExclusionList = null;
117
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800118 ActiveAdmin(DeviceAdminInfo _info) {
119 info = _info;
120 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700121
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800122 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700123
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800124 void writeToXml(XmlSerializer out)
125 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800126 out.startTag(null, "policies");
127 info.writePoliciesToXml(out);
128 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800129 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
130 out.startTag(null, "password-quality");
131 out.attribute(null, "value", Integer.toString(passwordQuality));
132 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800133 if (minimumPasswordLength > 0) {
134 out.startTag(null, "min-password-length");
135 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700136 out.endTag(null, "min-password-length");
137 }
138 if(passwordHistoryLength > 0) {
139 out.startTag(null, "password-history-length");
140 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
141 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800142 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700143 if (minimumPasswordUpperCase > 0) {
144 out.startTag(null, "min-password-uppercase");
145 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
146 out.endTag(null, "min-password-uppercase");
147 }
148 if (minimumPasswordLowerCase > 0) {
149 out.startTag(null, "min-password-lowercase");
150 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
151 out.endTag(null, "min-password-lowercase");
152 }
153 if (minimumPasswordLetters > 0) {
154 out.startTag(null, "min-password-letters");
155 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
156 out.endTag(null, "min-password-letters");
157 }
158 if (minimumPasswordNumeric > 0) {
159 out.startTag(null, "min-password-numeric");
160 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
161 out.endTag(null, "min-password-numeric");
162 }
163 if (minimumPasswordSymbols > 0) {
164 out.startTag(null, "min-password-symbols");
165 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
166 out.endTag(null, "min-password-symbols");
167 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700168 if (minimumPasswordNonLetter > 0) {
169 out.startTag(null, "min-password-nonletter");
170 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
171 out.endTag(null, "min-password-nonletter");
172 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800173 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800174 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800175 out.startTag(null, "max-time-to-unlock");
176 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
177 out.endTag(null, "max-time-to-unlock");
178 }
179 if (maximumFailedPasswordsForWipe != 0) {
180 out.startTag(null, "max-failed-password-wipe");
181 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
182 out.endTag(null, "max-failed-password-wipe");
183 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700184 if (specifiesGlobalProxy) {
185 out.startTag(null, "specifies-global-proxy");
186 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
187 out.endTag(null, "specifies_global_proxy");
188 if (globalProxySpec != null) {
189 out.startTag(null, "global-proxy-spec");
190 out.attribute(null, "value", globalProxySpec);
191 out.endTag(null, "global-proxy-spec");
192 }
193 if (globalProxyExclusionList != null) {
194 out.startTag(null, "global-proxy-exclusion-list");
195 out.attribute(null, "value", globalProxyExclusionList);
196 out.endTag(null, "global-proxy-exclusion-list");
197 }
198 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800199 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700200
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800201 void readFromXml(XmlPullParser parser)
202 throws XmlPullParserException, IOException {
203 int outerDepth = parser.getDepth();
204 int type;
205 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
206 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
207 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
208 continue;
209 }
210 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800211 if ("policies".equals(tag)) {
212 info.readPoliciesFromXml(parser);
213 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800214 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800215 parser.getAttributeValue(null, "value"));
216 } else if ("min-password-length".equals(tag)) {
217 minimumPasswordLength = Integer.parseInt(
218 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700219 } else if ("password-history-length".equals(tag)) {
220 passwordHistoryLength = Integer.parseInt(
221 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700222 } else if ("min-password-uppercase".equals(tag)) {
223 minimumPasswordUpperCase = Integer.parseInt(
224 parser.getAttributeValue(null, "value"));
225 } else if ("min-password-lowercase".equals(tag)) {
226 minimumPasswordLowerCase = Integer.parseInt(
227 parser.getAttributeValue(null, "value"));
228 } else if ("min-password-letters".equals(tag)) {
229 minimumPasswordLetters = Integer.parseInt(
230 parser.getAttributeValue(null, "value"));
231 } else if ("min-password-numeric".equals(tag)) {
232 minimumPasswordNumeric = Integer.parseInt(
233 parser.getAttributeValue(null, "value"));
234 } else if ("min-password-symbols".equals(tag)) {
235 minimumPasswordSymbols = Integer.parseInt(
236 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700237 } else if ("min-password-nonletter".equals(tag)) {
238 minimumPasswordNonLetter = Integer.parseInt(
239 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800240 } else if ("max-time-to-unlock".equals(tag)) {
241 maximumTimeToUnlock = Long.parseLong(
242 parser.getAttributeValue(null, "value"));
243 } else if ("max-failed-password-wipe".equals(tag)) {
244 maximumFailedPasswordsForWipe = Integer.parseInt(
245 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700246 } else if ("specifies-global-proxy".equals(tag)) {
247 specifiesGlobalProxy = Boolean.getBoolean(
248 parser.getAttributeValue(null, "value"));
249 } else if ("global-proxy-spec".equals(tag)) {
250 globalProxySpec =
251 parser.getAttributeValue(null, "value");
252 } else if ("global-proxy-exclusion-list".equals(tag)) {
253 globalProxyExclusionList =
254 parser.getAttributeValue(null, "value");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800255 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700256 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800257 }
258 XmlUtils.skipCurrentTag(parser);
259 }
260 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700261
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800262 void dump(String prefix, PrintWriter pw) {
263 pw.print(prefix); pw.print("uid="); pw.println(getUid());
264 pw.print(prefix); pw.println("policies:");
265 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
266 if (pols != null) {
267 for (int i=0; i<pols.size(); i++) {
268 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
269 }
270 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700271 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700272 pw.println(Integer.toHexString(passwordQuality));
273 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800274 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700275 pw.print(prefix); pw.print("passwordHistoryLength=");
276 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700277 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
278 pw.println(minimumPasswordUpperCase);
279 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
280 pw.println(minimumPasswordLowerCase);
281 pw.print(prefix); pw.print("minimumPasswordLetters=");
282 pw.println(minimumPasswordLetters);
283 pw.print(prefix); pw.print("minimumPasswordNumeric=");
284 pw.println(minimumPasswordNumeric);
285 pw.print(prefix); pw.print("minimumPasswordSymbols=");
286 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700287 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
288 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800289 pw.print(prefix); pw.print("maximumTimeToUnlock=");
290 pw.println(maximumTimeToUnlock);
291 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
292 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700293 pw.print(prefix); pw.print("specifiesGlobalProxy=");
294 pw.println(specifiesGlobalProxy);
295 if (globalProxySpec != null) {
296 pw.print(prefix); pw.print("globalProxySpec=");
297 pw.println(globalProxySpec);
298 }
299 if (globalProxyExclusionList != null) {
300 pw.print(prefix); pw.print("globalProxyEclusionList=");
301 pw.println(globalProxyExclusionList);
302 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800303 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800304 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700305
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800306 class MyPackageMonitor extends PackageMonitor {
307 public void onSomePackagesChanged() {
308 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800309 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800310 for (int i=mAdminList.size()-1; i>=0; i--) {
311 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700312 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800313 if (change == PACKAGE_PERMANENT_CHANGE
314 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700315 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800316 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800317 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800318 mAdminList.remove(i);
319 } else if (isPackageModified(aa.info.getPackageName())) {
320 try {
321 mContext.getPackageManager().getReceiverInfo(
322 aa.info.getComponent(), 0);
323 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700324 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800325 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800326 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800327 mAdminList.remove(i);
328 }
329 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800330 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800331 if (removed) {
332 validatePasswordOwnerLocked();
333 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800334 }
335 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800336 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700337
Dianne Hackbornd6847842010-01-12 18:14:19 -0800338 /**
339 * Instantiates the service.
340 */
341 public DevicePolicyManagerService(Context context) {
342 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800343 mMonitor = new MyPackageMonitor();
344 mMonitor.register(context, true);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800345 }
346
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800347 private IPowerManager getIPowerManager() {
348 if (mIPowerManager == null) {
349 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
350 mIPowerManager = IPowerManager.Stub.asInterface(b);
351 }
352 return mIPowerManager;
353 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700354
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800355 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800356 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800357 if (admin != null
358 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
359 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
360 return admin;
361 }
362 return null;
363 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700364
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800365 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
366 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800367 final int callingUid = Binder.getCallingUid();
368 if (who != null) {
369 ActiveAdmin admin = mAdminMap.get(who);
370 if (admin == null) {
371 throw new SecurityException("No active admin " + who);
372 }
373 if (admin.getUid() != callingUid) {
374 throw new SecurityException("Admin " + who + " is not owned by uid "
375 + Binder.getCallingUid());
376 }
377 if (!admin.info.usesPolicy(reqPolicy)) {
378 throw new SecurityException("Admin " + admin.info.getComponent()
379 + " did not specify uses-policy for: "
380 + admin.info.getTagForPolicy(reqPolicy));
381 }
382 return admin;
383 } else {
384 final int N = mAdminList.size();
385 for (int i=0; i<N; i++) {
386 ActiveAdmin admin = mAdminList.get(i);
387 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
388 return admin;
389 }
390 }
391 throw new SecurityException("No active admin owned by uid "
392 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800393 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800394 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700395
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800396 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800397 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800398 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800399 mContext.sendBroadcast(intent);
400 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700401
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800402 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800403 final int N = mAdminList.size();
404 if (N > 0) {
405 for (int i=0; i<N; i++) {
406 ActiveAdmin admin = mAdminList.get(i);
407 if (admin.info.usesPolicy(reqPolicy)) {
408 sendAdminCommandLocked(admin, action);
409 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800410 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800411 }
412 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700413
Dianne Hackbornd6847842010-01-12 18:14:19 -0800414 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800415 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
416 if (admin != null) {
Oscar Montemayor69238c62010-08-03 10:51:06 -0700417 boolean doProxyCleanup =
418 admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800419 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800420 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800421 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800422 mAdminList.remove(admin);
423 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800424 validatePasswordOwnerLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -0700425 if (doProxyCleanup) {
426 resetGlobalProxy();
427 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800428 }
429 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700430
Dianne Hackbornd6847842010-01-12 18:14:19 -0800431 public DeviceAdminInfo findAdmin(ComponentName adminName) {
432 Intent resolveIntent = new Intent();
433 resolveIntent.setComponent(adminName);
434 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
435 resolveIntent, PackageManager.GET_META_DATA);
436 if (infos == null || infos.size() <= 0) {
437 throw new IllegalArgumentException("Unknown admin: " + adminName);
438 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700439
Dianne Hackbornd6847842010-01-12 18:14:19 -0800440 try {
441 return new DeviceAdminInfo(mContext, infos.get(0));
442 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700443 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800444 return null;
445 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700446 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800447 return null;
448 }
449 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700450
Dianne Hackbornd6847842010-01-12 18:14:19 -0800451 private static JournaledFile makeJournaledFile() {
452 final String base = "/data/system/device_policies.xml";
453 return new JournaledFile(new File(base), new File(base + ".tmp"));
454 }
455
456 private void saveSettingsLocked() {
457 JournaledFile journal = makeJournaledFile();
458 FileOutputStream stream = null;
459 try {
460 stream = new FileOutputStream(journal.chooseForWrite(), false);
461 XmlSerializer out = new FastXmlSerializer();
462 out.setOutput(stream, "utf-8");
463 out.startDocument(null, true);
464
465 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700466
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800467 final int N = mAdminList.size();
468 for (int i=0; i<N; i++) {
469 ActiveAdmin ap = mAdminList.get(i);
470 if (ap != null) {
471 out.startTag(null, "admin");
472 out.attribute(null, "name", ap.info.getComponent().flattenToString());
473 ap.writeToXml(out);
474 out.endTag(null, "admin");
475 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800476 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700477
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800478 if (mPasswordOwner >= 0) {
479 out.startTag(null, "password-owner");
480 out.attribute(null, "value", Integer.toString(mPasswordOwner));
481 out.endTag(null, "password-owner");
482 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700483
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800484 if (mFailedPasswordAttempts != 0) {
485 out.startTag(null, "failed-password-attempts");
486 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
487 out.endTag(null, "failed-password-attempts");
488 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700489
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700490 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
491 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
492 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700493 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700494 out.startTag(null, "active-password");
495 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
496 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700497 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
498 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
499 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
500 out.attribute(null, "numeric", Integer
501 .toString(mActivePasswordNumeric));
502 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700503 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700504 out.endTag(null, "active-password");
505 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700506
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700507 out.endTag(null, "policies");
508
Dianne Hackbornd6847842010-01-12 18:14:19 -0800509 out.endDocument();
510 stream.close();
511 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700512 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800513 } catch (IOException e) {
514 try {
515 if (stream != null) {
516 stream.close();
517 }
518 } catch (IOException ex) {
519 // Ignore
520 }
521 journal.rollback();
522 }
523 }
524
Jim Miller284b62e2010-06-08 14:27:42 -0700525 private void sendChangedNotification() {
526 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
527 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
528 mContext.sendBroadcast(intent);
529 }
530
Dianne Hackbornd6847842010-01-12 18:14:19 -0800531 private void loadSettingsLocked() {
532 JournaledFile journal = makeJournaledFile();
533 FileInputStream stream = null;
534 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800535 try {
536 stream = new FileInputStream(file);
537 XmlPullParser parser = Xml.newPullParser();
538 parser.setInput(stream, null);
539
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800540 int type;
541 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
542 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800543 }
544 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800545 if (!"policies".equals(tag)) {
546 throw new XmlPullParserException(
547 "Settings do not start with policies tag: found " + tag);
548 }
549 type = parser.next();
550 int outerDepth = parser.getDepth();
551 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
552 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
553 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
554 continue;
555 }
556 tag = parser.getName();
557 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800558 String name = parser.getAttributeValue(null, "name");
559 try {
560 DeviceAdminInfo dai = findAdmin(
561 ComponentName.unflattenFromString(name));
562 if (dai != null) {
563 ActiveAdmin ap = new ActiveAdmin(dai);
564 ap.readFromXml(parser);
565 mAdminMap.put(ap.info.getComponent(), ap);
566 mAdminList.add(ap);
567 }
568 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700569 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800570 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800571 } else if ("failed-password-attempts".equals(tag)) {
572 mFailedPasswordAttempts = Integer.parseInt(
573 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800574 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800575 } else if ("password-owner".equals(tag)) {
576 mPasswordOwner = Integer.parseInt(
577 parser.getAttributeValue(null, "value"));
578 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700579 } else if ("active-password".equals(tag)) {
580 mActivePasswordQuality = Integer.parseInt(
581 parser.getAttributeValue(null, "quality"));
582 mActivePasswordLength = Integer.parseInt(
583 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700584 mActivePasswordUpperCase = Integer.parseInt(
585 parser.getAttributeValue(null, "uppercase"));
586 mActivePasswordLowerCase = Integer.parseInt(
587 parser.getAttributeValue(null, "lowercase"));
588 mActivePasswordLetters = Integer.parseInt(
589 parser.getAttributeValue(null, "letters"));
590 mActivePasswordNumeric = Integer.parseInt(
591 parser.getAttributeValue(null, "numeric"));
592 mActivePasswordSymbols = Integer.parseInt(
593 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700594 mActivePasswordNonLetter = Integer.parseInt(
595 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700596 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800597 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700598 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800599 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800600 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800601 }
602 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700603 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800604 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700605 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800606 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700607 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800608 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700609 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800610 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700611 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800612 }
613 try {
614 if (stream != null) {
615 stream.close();
616 }
617 } catch (IOException e) {
618 // Ignore
619 }
620
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700621 // Validate that what we stored for the password quality matches
622 // sufficiently what is currently set. Note that this is only
623 // a sanity check in case the two get out of sync; this should
624 // never normally happen.
625 LockPatternUtils utils = new LockPatternUtils(mContext);
626 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
627 Slog.w(TAG, "Active password quality 0x"
628 + Integer.toHexString(mActivePasswordQuality)
629 + " does not match actual quality 0x"
630 + Integer.toHexString(utils.getActivePasswordQuality()));
631 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
632 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700633 mActivePasswordUpperCase = 0;
634 mActivePasswordLowerCase = 0;
635 mActivePasswordLetters = 0;
636 mActivePasswordNumeric = 0;
637 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700638 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700639 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700640
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800641 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700642
Dianne Hackborn254cb442010-01-27 19:23:59 -0800643 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800644 if (timeMs <= 0) {
645 timeMs = Integer.MAX_VALUE;
646 }
647 try {
648 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
649 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700650 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800651 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800652 }
653
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700654 static void validateQualityConstant(int quality) {
655 switch (quality) {
656 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
657 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
658 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
659 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
660 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700661 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700662 return;
663 }
664 throw new IllegalArgumentException("Invalid quality constant: 0x"
665 + Integer.toHexString(quality));
666 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700667
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800668 void validatePasswordOwnerLocked() {
669 if (mPasswordOwner >= 0) {
670 boolean haveOwner = false;
671 for (int i=mAdminList.size()-1; i>=0; i--) {
672 if (mAdminList.get(i).getUid() == mPasswordOwner) {
673 haveOwner = true;
674 break;
675 }
676 }
677 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700678 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800679 + " no longer active; disabling");
680 mPasswordOwner = -1;
681 }
682 }
683 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700684
Dianne Hackbornd6847842010-01-12 18:14:19 -0800685 public void systemReady() {
686 synchronized (this) {
687 loadSettingsLocked();
688 }
689 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700690
Dianne Hackbornd6847842010-01-12 18:14:19 -0800691 public void setActiveAdmin(ComponentName adminReceiver) {
692 mContext.enforceCallingOrSelfPermission(
693 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700694
Dianne Hackbornd6847842010-01-12 18:14:19 -0800695 DeviceAdminInfo info = findAdmin(adminReceiver);
696 if (info == null) {
697 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
698 }
699 synchronized (this) {
700 long ident = Binder.clearCallingIdentity();
701 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800702 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
703 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800704 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800705 ActiveAdmin admin = new ActiveAdmin(info);
706 mAdminMap.put(adminReceiver, admin);
707 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800708 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800709 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800710 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800711 } finally {
712 Binder.restoreCallingIdentity(ident);
713 }
714 }
715 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700716
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800717 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800718 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800719 return getActiveAdminUncheckedLocked(adminReceiver) != null;
720 }
721 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700722
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800723 public List<ComponentName> getActiveAdmins() {
724 synchronized (this) {
725 final int N = mAdminList.size();
726 if (N <= 0) {
727 return null;
728 }
729 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
730 for (int i=0; i<N; i++) {
731 res.add(mAdminList.get(i).info.getComponent());
732 }
733 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800734 }
735 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700736
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800737 public boolean packageHasActiveAdmins(String packageName) {
738 synchronized (this) {
739 final int N = mAdminList.size();
740 for (int i=0; i<N; i++) {
741 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
742 return true;
743 }
744 }
745 return false;
746 }
747 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700748
Dianne Hackbornd6847842010-01-12 18:14:19 -0800749 public void removeActiveAdmin(ComponentName adminReceiver) {
750 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800751 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
752 if (admin == null) {
753 return;
754 }
755 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800756 mContext.enforceCallingOrSelfPermission(
757 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
758 }
759 long ident = Binder.clearCallingIdentity();
760 try {
761 removeActiveAdminLocked(adminReceiver);
762 } finally {
763 Binder.restoreCallingIdentity(ident);
764 }
765 }
766 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700767
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700768 public void setPasswordQuality(ComponentName who, int quality) {
769 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700770
Dianne Hackbornd6847842010-01-12 18:14:19 -0800771 synchronized (this) {
772 if (who == null) {
773 throw new NullPointerException("ComponentName is null");
774 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800775 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
776 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700777 if (ap.passwordQuality != quality) {
778 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800779 saveSettingsLocked();
780 }
781 }
782 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700783
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800784 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800785 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800786 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700787
Dianne Hackborn254cb442010-01-27 19:23:59 -0800788 if (who != null) {
789 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800790 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800791 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700792
Dianne Hackborn254cb442010-01-27 19:23:59 -0800793 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800794 for (int i=0; i<N; i++) {
795 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800796 if (mode < admin.passwordQuality) {
797 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800798 }
799 }
800 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800801 }
802 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700803
Dianne Hackborn254cb442010-01-27 19:23:59 -0800804 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800805 synchronized (this) {
806 if (who == null) {
807 throw new NullPointerException("ComponentName is null");
808 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800809 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
810 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800811 if (ap.minimumPasswordLength != length) {
812 ap.minimumPasswordLength = length;
813 saveSettingsLocked();
814 }
815 }
816 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700817
Dianne Hackborn254cb442010-01-27 19:23:59 -0800818 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800819 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800820 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700821
Dianne Hackborn254cb442010-01-27 19:23:59 -0800822 if (who != null) {
823 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
824 return admin != null ? admin.minimumPasswordLength : length;
825 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700826
Dianne Hackborn254cb442010-01-27 19:23:59 -0800827 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800828 for (int i=0; i<N; i++) {
829 ActiveAdmin admin = mAdminList.get(i);
830 if (length < admin.minimumPasswordLength) {
831 length = admin.minimumPasswordLength;
832 }
833 }
834 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800835 }
836 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700837
838 public void setPasswordHistoryLength(ComponentName who, int length) {
839 synchronized (this) {
840 if (who == null) {
841 throw new NullPointerException("ComponentName is null");
842 }
843 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
844 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
845 if (ap.passwordHistoryLength != length) {
846 ap.passwordHistoryLength = length;
847 saveSettingsLocked();
848 }
849 }
850 }
851
852 public int getPasswordHistoryLength(ComponentName who) {
853 synchronized (this) {
854 int length = 0;
855
856 if (who != null) {
857 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
858 return admin != null ? admin.passwordHistoryLength : length;
859 }
860
861 final int N = mAdminList.size();
862 for (int i = 0; i < N; i++) {
863 ActiveAdmin admin = mAdminList.get(i);
864 if (length < admin.passwordHistoryLength) {
865 length = admin.passwordHistoryLength;
866 }
867 }
868 return length;
869 }
870 }
871
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700872 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
873 synchronized (this) {
874 if (who == null) {
875 throw new NullPointerException("ComponentName is null");
876 }
877 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
878 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
879 if (ap.minimumPasswordUpperCase != length) {
880 ap.minimumPasswordUpperCase = length;
881 saveSettingsLocked();
882 }
883 }
884 }
885
886 public int getPasswordMinimumUpperCase(ComponentName who) {
887 synchronized (this) {
888 int length = 0;
889
890 if (who != null) {
891 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
892 return admin != null ? admin.minimumPasswordUpperCase : length;
893 }
894
895 final int N = mAdminList.size();
896 for (int i=0; i<N; i++) {
897 ActiveAdmin admin = mAdminList.get(i);
898 if (length < admin.minimumPasswordUpperCase) {
899 length = admin.minimumPasswordUpperCase;
900 }
901 }
902 return length;
903 }
904 }
905
906 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
907 synchronized (this) {
908 if (who == null) {
909 throw new NullPointerException("ComponentName is null");
910 }
911 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
912 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
913 if (ap.minimumPasswordLowerCase != length) {
914 ap.minimumPasswordLowerCase = length;
915 saveSettingsLocked();
916 }
917 }
918 }
919
920 public int getPasswordMinimumLowerCase(ComponentName who) {
921 synchronized (this) {
922 int length = 0;
923
924 if (who != null) {
925 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
926 return admin != null ? admin.minimumPasswordLowerCase : length;
927 }
928
929 final int N = mAdminList.size();
930 for (int i=0; i<N; i++) {
931 ActiveAdmin admin = mAdminList.get(i);
932 if (length < admin.minimumPasswordLowerCase) {
933 length = admin.minimumPasswordLowerCase;
934 }
935 }
936 return length;
937 }
938 }
939
940 public void setPasswordMinimumLetters(ComponentName who, int length) {
941 synchronized (this) {
942 if (who == null) {
943 throw new NullPointerException("ComponentName is null");
944 }
945 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
946 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
947 if (ap.minimumPasswordLetters != length) {
948 ap.minimumPasswordLetters = length;
949 saveSettingsLocked();
950 }
951 }
952 }
953
954 public int getPasswordMinimumLetters(ComponentName who) {
955 synchronized (this) {
956 int length = 0;
957
958 if (who != null) {
959 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
960 return admin != null ? admin.minimumPasswordLetters : length;
961 }
962
963 final int N = mAdminList.size();
964 for (int i=0; i<N; i++) {
965 ActiveAdmin admin = mAdminList.get(i);
966 if (length < admin.minimumPasswordLetters) {
967 length = admin.minimumPasswordLetters;
968 }
969 }
970 return length;
971 }
972 }
973
974 public void setPasswordMinimumNumeric(ComponentName who, int length) {
975 synchronized (this) {
976 if (who == null) {
977 throw new NullPointerException("ComponentName is null");
978 }
979 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
980 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
981 if (ap.minimumPasswordNumeric != length) {
982 ap.minimumPasswordNumeric = length;
983 saveSettingsLocked();
984 }
985 }
986 }
987
988 public int getPasswordMinimumNumeric(ComponentName who) {
989 synchronized (this) {
990 int length = 0;
991
992 if (who != null) {
993 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
994 return admin != null ? admin.minimumPasswordNumeric : length;
995 }
996
997 final int N = mAdminList.size();
998 for (int i = 0; i < N; i++) {
999 ActiveAdmin admin = mAdminList.get(i);
1000 if (length < admin.minimumPasswordNumeric) {
1001 length = admin.minimumPasswordNumeric;
1002 }
1003 }
1004 return length;
1005 }
1006 }
1007
1008 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1009 synchronized (this) {
1010 if (who == null) {
1011 throw new NullPointerException("ComponentName is null");
1012 }
1013 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1014 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1015 if (ap.minimumPasswordSymbols != length) {
1016 ap.minimumPasswordSymbols = length;
1017 saveSettingsLocked();
1018 }
1019 }
1020 }
1021
1022 public int getPasswordMinimumSymbols(ComponentName who) {
1023 synchronized (this) {
1024 int length = 0;
1025
1026 if (who != null) {
1027 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1028 return admin != null ? admin.minimumPasswordSymbols : length;
1029 }
1030
1031 final int N = mAdminList.size();
1032 for (int i=0; i<N; i++) {
1033 ActiveAdmin admin = mAdminList.get(i);
1034 if (length < admin.minimumPasswordSymbols) {
1035 length = admin.minimumPasswordSymbols;
1036 }
1037 }
1038 return length;
1039 }
1040 }
1041
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001042 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1043 synchronized (this) {
1044 if (who == null) {
1045 throw new NullPointerException("ComponentName is null");
1046 }
1047 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1048 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1049 if (ap.minimumPasswordNonLetter != length) {
1050 ap.minimumPasswordNonLetter = length;
1051 saveSettingsLocked();
1052 }
1053 }
1054 }
1055
1056 public int getPasswordMinimumNonLetter(ComponentName who) {
1057 synchronized (this) {
1058 int length = 0;
1059
1060 if (who != null) {
1061 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1062 return admin != null ? admin.minimumPasswordNonLetter : length;
1063 }
1064
1065 final int N = mAdminList.size();
1066 for (int i=0; i<N; i++) {
1067 ActiveAdmin admin = mAdminList.get(i);
1068 if (length < admin.minimumPasswordNonLetter) {
1069 length = admin.minimumPasswordNonLetter;
1070 }
1071 }
1072 return length;
1073 }
1074 }
1075
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001076 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001077 synchronized (this) {
1078 // This API can only be called by an active device admin,
1079 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001080 getActiveAdminForCallerLocked(null,
1081 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001082 if (mActivePasswordQuality < getPasswordQuality(null)
1083 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1084 return false;
1085 }
1086 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1087 return true;
1088 }
1089 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1090 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1091 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1092 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001093 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1094 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001095 }
1096 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001097
Dianne Hackbornd6847842010-01-12 18:14:19 -08001098 public int getCurrentFailedPasswordAttempts() {
1099 synchronized (this) {
1100 // This API can only be called by an active device admin,
1101 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001102 getActiveAdminForCallerLocked(null,
1103 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001104 return mFailedPasswordAttempts;
1105 }
1106 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001107
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001108 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1109 synchronized (this) {
1110 // This API can only be called by an active device admin,
1111 // so try to retrieve it to check that the caller is one.
1112 getActiveAdminForCallerLocked(who,
1113 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1114 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1115 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1116 if (ap.maximumFailedPasswordsForWipe != num) {
1117 ap.maximumFailedPasswordsForWipe = num;
1118 saveSettingsLocked();
1119 }
1120 }
1121 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001122
Dianne Hackborn254cb442010-01-27 19:23:59 -08001123 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001124 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001125 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001126
Dianne Hackborn254cb442010-01-27 19:23:59 -08001127 if (who != null) {
1128 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1129 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1130 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001131
Dianne Hackborn254cb442010-01-27 19:23:59 -08001132 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001133 for (int i=0; i<N; i++) {
1134 ActiveAdmin admin = mAdminList.get(i);
1135 if (count == 0) {
1136 count = admin.maximumFailedPasswordsForWipe;
1137 } else if (admin.maximumFailedPasswordsForWipe != 0
1138 && count > admin.maximumFailedPasswordsForWipe) {
1139 count = admin.maximumFailedPasswordsForWipe;
1140 }
1141 }
1142 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001143 }
1144 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001145
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001146 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001147 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001148 synchronized (this) {
1149 // This API can only be called by an active device admin,
1150 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001151 getActiveAdminForCallerLocked(null,
1152 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001153 quality = getPasswordQuality(null);
1154 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001155 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001156 if (realQuality < quality
1157 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001158 Slog.w(TAG, "resetPassword: password quality 0x"
1159 + Integer.toHexString(quality)
1160 + " does not meet required quality 0x"
1161 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001162 return false;
1163 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001164 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001165 }
1166 int length = getPasswordMinimumLength(null);
1167 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001168 Slog.w(TAG, "resetPassword: password length " + password.length()
1169 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001170 return false;
1171 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001172 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1173 int letters = 0;
1174 int uppercase = 0;
1175 int lowercase = 0;
1176 int numbers = 0;
1177 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001178 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001179 for (int i = 0; i < password.length(); i++) {
1180 char c = password.charAt(i);
1181 if (c >= 'A' && c <= 'Z') {
1182 letters++;
1183 uppercase++;
1184 } else if (c >= 'a' && c <= 'z') {
1185 letters++;
1186 lowercase++;
1187 } else if (c >= '0' && c <= '9') {
1188 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001189 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001190 } else {
1191 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001192 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001193 }
1194 }
1195 int neededLetters = getPasswordMinimumLetters(null);
1196 if(letters < neededLetters) {
1197 Slog.w(TAG, "resetPassword: number of letters " + letters
1198 + " does not meet required number of letters " + neededLetters);
1199 return false;
1200 }
1201 int neededNumbers = getPasswordMinimumNumeric(null);
1202 if (numbers < neededNumbers) {
1203 Slog
1204 .w(TAG, "resetPassword: number of numerical digits " + numbers
1205 + " does not meet required number of numerical digits "
1206 + neededNumbers);
1207 return false;
1208 }
1209 int neededLowerCase = getPasswordMinimumLowerCase(null);
1210 if (lowercase < neededLowerCase) {
1211 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1212 + " does not meet required number of lowercase letters "
1213 + neededLowerCase);
1214 return false;
1215 }
1216 int neededUpperCase = getPasswordMinimumUpperCase(null);
1217 if (uppercase < neededUpperCase) {
1218 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1219 + " does not meet required number of uppercase letters "
1220 + neededUpperCase);
1221 return false;
1222 }
1223 int neededSymbols = getPasswordMinimumSymbols(null);
1224 if (symbols < neededSymbols) {
1225 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1226 + " does not meet required number of special symbols " + neededSymbols);
1227 return false;
1228 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001229 int neededNonLetter = getPasswordMinimumNonLetter(null);
1230 if (nonletter < neededNonLetter) {
1231 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1232 + " does not meet required number of non-letter characters "
1233 + neededNonLetter);
1234 return false;
1235 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001236 }
1237
1238 LockPatternUtils utils = new LockPatternUtils(mContext);
1239 if(utils.checkPasswordHistory(password)) {
1240 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1241 + getPasswordHistoryLength(null) + " passwords");
1242 return false;
1243 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001244 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001245
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001246 int callingUid = Binder.getCallingUid();
1247 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001248 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001249 return false;
1250 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001251
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001252 // Don't do this with the lock held, because it is going to call
1253 // back in to the service.
1254 long ident = Binder.clearCallingIdentity();
1255 try {
1256 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001257 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001258 synchronized (this) {
1259 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1260 != 0 ? callingUid : -1;
1261 if (mPasswordOwner != newOwner) {
1262 mPasswordOwner = newOwner;
1263 saveSettingsLocked();
1264 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001265 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001266 } finally {
1267 Binder.restoreCallingIdentity(ident);
1268 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001269
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001270 return true;
1271 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001272
Dianne Hackbornd6847842010-01-12 18:14:19 -08001273 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1274 synchronized (this) {
1275 if (who == null) {
1276 throw new NullPointerException("ComponentName is null");
1277 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001278 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001279 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001280 if (ap.maximumTimeToUnlock != timeMs) {
1281 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001282
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001283 long ident = Binder.clearCallingIdentity();
1284 try {
1285 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001286
Dianne Hackborn254cb442010-01-27 19:23:59 -08001287 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001288 if (timeMs <= 0) {
1289 timeMs = Integer.MAX_VALUE;
1290 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001291
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001292 try {
1293 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1294 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001295 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001296 }
1297 } finally {
1298 Binder.restoreCallingIdentity(ident);
1299 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001300 }
1301 }
1302 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001303
Dianne Hackborn254cb442010-01-27 19:23:59 -08001304 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001305 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001306 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001307
Dianne Hackborn254cb442010-01-27 19:23:59 -08001308 if (who != null) {
1309 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1310 return admin != null ? admin.maximumTimeToUnlock : time;
1311 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001312
Dianne Hackborn254cb442010-01-27 19:23:59 -08001313 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001314 for (int i=0; i<N; i++) {
1315 ActiveAdmin admin = mAdminList.get(i);
1316 if (time == 0) {
1317 time = admin.maximumTimeToUnlock;
1318 } else if (admin.maximumTimeToUnlock != 0
1319 && time > admin.maximumTimeToUnlock) {
1320 time = admin.maximumTimeToUnlock;
1321 }
1322 }
1323 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001324 }
1325 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001326
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001327 public void lockNow() {
1328 synchronized (this) {
1329 // This API can only be called by an active device admin,
1330 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001331 getActiveAdminForCallerLocked(null,
1332 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001333 long ident = Binder.clearCallingIdentity();
1334 try {
1335 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1336 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1337 } catch (RemoteException e) {
1338 } finally {
1339 Binder.restoreCallingIdentity(ident);
1340 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001341 }
1342 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001343
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001344 void wipeDataLocked(int flags) {
1345 try {
1346 RecoverySystem.rebootWipeUserData(mContext);
1347 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001348 Slog.w(TAG, "Failed requesting data wipe", e);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001349 }
1350 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001351
Dianne Hackbornd6847842010-01-12 18:14:19 -08001352 public void wipeData(int flags) {
1353 synchronized (this) {
1354 // This API can only be called by an active device admin,
1355 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001356 getActiveAdminForCallerLocked(null,
1357 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001358 long ident = Binder.clearCallingIdentity();
1359 try {
1360 wipeDataLocked(flags);
1361 } finally {
1362 Binder.restoreCallingIdentity(ident);
1363 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001364 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001365 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001366
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001367 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1368 mContext.enforceCallingOrSelfPermission(
1369 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001370
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001371 synchronized (this) {
1372 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1373 if (admin == null) {
1374 try {
1375 result.sendResult(null);
1376 } catch (RemoteException e) {
1377 }
1378 return;
1379 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001380 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001381 intent.setComponent(admin.info.getComponent());
1382 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1383 @Override
1384 public void onReceive(Context context, Intent intent) {
1385 try {
1386 result.sendResult(getResultExtras(false));
1387 } catch (RemoteException e) {
1388 }
1389 }
1390 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001391 }
1392 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001393
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001394 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001395 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001396 mContext.enforceCallingOrSelfPermission(
1397 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001398
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001399 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001400
Dianne Hackbornd6847842010-01-12 18:14:19 -08001401 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001402 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001403 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1404 || mActivePasswordUpperCase != uppercase
1405 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001406 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001407 long ident = Binder.clearCallingIdentity();
1408 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001409 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001410 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001411 mActivePasswordLetters = letters;
1412 mActivePasswordLowerCase = lowercase;
1413 mActivePasswordUpperCase = uppercase;
1414 mActivePasswordNumeric = numbers;
1415 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001416 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001417 mFailedPasswordAttempts = 0;
1418 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001419 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001420 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001421 } finally {
1422 Binder.restoreCallingIdentity(ident);
1423 }
1424 }
1425 }
1426 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001427
Dianne Hackbornd6847842010-01-12 18:14:19 -08001428 public void reportFailedPasswordAttempt() {
1429 mContext.enforceCallingOrSelfPermission(
1430 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001431
Dianne Hackbornd6847842010-01-12 18:14:19 -08001432 synchronized (this) {
1433 long ident = Binder.clearCallingIdentity();
1434 try {
1435 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001436 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001437 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001438 if (max > 0 && mFailedPasswordAttempts >= max) {
1439 wipeDataLocked(0);
1440 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001441 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001442 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001443 } finally {
1444 Binder.restoreCallingIdentity(ident);
1445 }
1446 }
1447 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001448
Dianne Hackbornd6847842010-01-12 18:14:19 -08001449 public void reportSuccessfulPasswordAttempt() {
1450 mContext.enforceCallingOrSelfPermission(
1451 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001452
Dianne Hackbornd6847842010-01-12 18:14:19 -08001453 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001454 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001455 long ident = Binder.clearCallingIdentity();
1456 try {
1457 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001458 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001459 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001460 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001461 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001462 } finally {
1463 Binder.restoreCallingIdentity(ident);
1464 }
1465 }
1466 }
1467 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001468
Oscar Montemayor69238c62010-08-03 10:51:06 -07001469 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1470 String exclusionList) {
1471 synchronized(this) {
1472 if (who == null) {
1473 throw new NullPointerException("ComponentName is null");
1474 }
1475
1476 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1477 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1478
1479 // Scan through active admins and find if anyone has already
1480 // set the global proxy.
1481 final int N = mAdminList.size();
1482 Set<ComponentName> compSet = mAdminMap.keySet();
1483 for (ComponentName component : compSet) {
1484 ActiveAdmin ap = mAdminMap.get(component);
1485 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1486 // Another admin already sets the global proxy
1487 // Return it to the caller.
1488 return component;
1489 }
1490 }
1491 if (proxySpec == null) {
1492 admin.specifiesGlobalProxy = false;
1493 admin.globalProxySpec = null;
1494 admin.globalProxyExclusionList = null;
1495 } else {
1496
1497 admin.specifiesGlobalProxy = true;
1498 admin.globalProxySpec = proxySpec;
1499 admin.globalProxyExclusionList = exclusionList;
1500 }
1501
1502 // Reset the global proxy accordingly
1503 // Do this using system permissions, as apps cannot write to secure settings
1504 long origId = Binder.clearCallingIdentity();
1505 resetGlobalProxy();
1506 Binder.restoreCallingIdentity(origId);
1507 return null;
1508 }
1509 }
1510
1511 public ComponentName getGlobalProxyAdmin() {
1512 synchronized(this) {
1513 // Scan through active admins and find if anyone has already
1514 // set the global proxy.
1515 final int N = mAdminList.size();
1516 for (int i = 0; i < N; i++) {
1517 ActiveAdmin ap = mAdminList.get(i);
1518 if (ap.specifiesGlobalProxy) {
1519 // Device admin sets the global proxy
1520 // Return it to the caller.
1521 return ap.info.getComponent();
1522 }
1523 }
1524 }
1525 // No device admin sets the global proxy.
1526 return null;
1527 }
1528
1529 private void resetGlobalProxy() {
1530 final int N = mAdminList.size();
1531 for (int i = 0; i < N; i++) {
1532 ActiveAdmin ap = mAdminList.get(i);
1533 if (ap.specifiesGlobalProxy) {
1534 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1535 return;
1536 }
1537 }
1538 // No device admins defining global proxies - reset global proxy settings to none
1539 saveGlobalProxy(null, null);
1540 }
1541
1542 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1543 if (exclusionList == null) {
1544 exclusionList = "";
1545 }
1546 if (proxySpec == null) {
1547 proxySpec = "";
1548 }
1549 // Remove white spaces
1550 proxySpec = proxySpec.trim();
1551 exclusionList = exclusionList.trim();
1552 ContentResolver res = mContext.getContentResolver();
1553 Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY, proxySpec);
1554 Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY_EXCLUSION_LIST, exclusionList);
1555 }
1556
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001557 @Override
1558 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1559 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1560 != PackageManager.PERMISSION_GRANTED) {
1561
1562 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1563 + Binder.getCallingPid()
1564 + ", uid=" + Binder.getCallingUid());
1565 return;
1566 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001567
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001568 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001569
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001570 synchronized (this) {
1571 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001572
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001573 p.println(" Enabled Device Admins:");
1574 final int N = mAdminList.size();
1575 for (int i=0; i<N; i++) {
1576 ActiveAdmin ap = mAdminList.get(i);
1577 if (ap != null) {
1578 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1579 pw.println(":");
1580 ap.dump(" ", pw);
1581 }
1582 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001583
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001584 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001585 pw.print(" mActivePasswordQuality=0x");
1586 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001587 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001588 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1589 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1590 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1591 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1592 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001593 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001594 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1595 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1596 }
1597 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001598}