blob: 28126b948942cc8772a07d500e7b5a232687423b [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;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070061import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080062import java.io.FileOutputStream;
63import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080064import java.io.PrintWriter;
Oscar Montemayor69238c62010-08-03 10:51:06 -070065import java.net.InetSocketAddress;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080066import java.util.ArrayList;
67import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080068import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070069import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080070
71/**
72 * Implementation of the device policy APIs.
73 */
74public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080075 static final String TAG = "DevicePolicyManagerService";
Konstantin Lopyrev32558232010-05-20 16:18:05 -070076
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080077 final Context mContext;
78 final MyPackageMonitor mMonitor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080079
Dianne Hackborndf83afa2010-01-20 13:37:26 -080080 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070081
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080082 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080083 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -070084 int mActivePasswordUpperCase = 0;
85 int mActivePasswordLowerCase = 0;
86 int mActivePasswordLetters = 0;
87 int mActivePasswordNumeric = 0;
88 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -070089 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -080090 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070091
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080092 int mPasswordOwner = -1;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070093
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080094 final HashMap<ComponentName, ActiveAdmin> mAdminMap
95 = new HashMap<ComponentName, ActiveAdmin>();
96 final ArrayList<ActiveAdmin> mAdminList
97 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -070098
Dianne Hackbornd6847842010-01-12 18:14:19 -080099 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800100 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700101
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800102 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800103 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700104 int passwordHistoryLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700105 int minimumPasswordUpperCase = 0;
106 int minimumPasswordLowerCase = 0;
107 int minimumPasswordLetters = 1;
108 int minimumPasswordNumeric = 1;
109 int minimumPasswordSymbols = 1;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700110 int minimumPasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800111 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800112 int maximumFailedPasswordsForWipe = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700113
Oscar Montemayor69238c62010-08-03 10:51:06 -0700114 // TODO: review implementation decisions with frameworks team
115 boolean specifiesGlobalProxy = false;
116 String globalProxySpec = null;
117 String globalProxyExclusionList = null;
118
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800119 ActiveAdmin(DeviceAdminInfo _info) {
120 info = _info;
121 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700122
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800123 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700124
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800125 void writeToXml(XmlSerializer out)
126 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800127 out.startTag(null, "policies");
128 info.writePoliciesToXml(out);
129 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800130 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
131 out.startTag(null, "password-quality");
132 out.attribute(null, "value", Integer.toString(passwordQuality));
133 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800134 if (minimumPasswordLength > 0) {
135 out.startTag(null, "min-password-length");
136 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700137 out.endTag(null, "min-password-length");
138 }
139 if(passwordHistoryLength > 0) {
140 out.startTag(null, "password-history-length");
141 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
142 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800143 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700144 if (minimumPasswordUpperCase > 0) {
145 out.startTag(null, "min-password-uppercase");
146 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
147 out.endTag(null, "min-password-uppercase");
148 }
149 if (minimumPasswordLowerCase > 0) {
150 out.startTag(null, "min-password-lowercase");
151 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
152 out.endTag(null, "min-password-lowercase");
153 }
154 if (minimumPasswordLetters > 0) {
155 out.startTag(null, "min-password-letters");
156 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
157 out.endTag(null, "min-password-letters");
158 }
159 if (minimumPasswordNumeric > 0) {
160 out.startTag(null, "min-password-numeric");
161 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
162 out.endTag(null, "min-password-numeric");
163 }
164 if (minimumPasswordSymbols > 0) {
165 out.startTag(null, "min-password-symbols");
166 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
167 out.endTag(null, "min-password-symbols");
168 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700169 if (minimumPasswordNonLetter > 0) {
170 out.startTag(null, "min-password-nonletter");
171 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
172 out.endTag(null, "min-password-nonletter");
173 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800174 }
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800175 if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800176 out.startTag(null, "max-time-to-unlock");
177 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
178 out.endTag(null, "max-time-to-unlock");
179 }
180 if (maximumFailedPasswordsForWipe != 0) {
181 out.startTag(null, "max-failed-password-wipe");
182 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
183 out.endTag(null, "max-failed-password-wipe");
184 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700185 if (specifiesGlobalProxy) {
186 out.startTag(null, "specifies-global-proxy");
187 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
188 out.endTag(null, "specifies_global_proxy");
189 if (globalProxySpec != null) {
190 out.startTag(null, "global-proxy-spec");
191 out.attribute(null, "value", globalProxySpec);
192 out.endTag(null, "global-proxy-spec");
193 }
194 if (globalProxyExclusionList != null) {
195 out.startTag(null, "global-proxy-exclusion-list");
196 out.attribute(null, "value", globalProxyExclusionList);
197 out.endTag(null, "global-proxy-exclusion-list");
198 }
199 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800200 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700201
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800202 void readFromXml(XmlPullParser parser)
203 throws XmlPullParserException, IOException {
204 int outerDepth = parser.getDepth();
205 int type;
206 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
207 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
208 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
209 continue;
210 }
211 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800212 if ("policies".equals(tag)) {
213 info.readPoliciesFromXml(parser);
214 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800215 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800216 parser.getAttributeValue(null, "value"));
217 } else if ("min-password-length".equals(tag)) {
218 minimumPasswordLength = Integer.parseInt(
219 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700220 } else if ("password-history-length".equals(tag)) {
221 passwordHistoryLength = Integer.parseInt(
222 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700223 } else if ("min-password-uppercase".equals(tag)) {
224 minimumPasswordUpperCase = Integer.parseInt(
225 parser.getAttributeValue(null, "value"));
226 } else if ("min-password-lowercase".equals(tag)) {
227 minimumPasswordLowerCase = Integer.parseInt(
228 parser.getAttributeValue(null, "value"));
229 } else if ("min-password-letters".equals(tag)) {
230 minimumPasswordLetters = Integer.parseInt(
231 parser.getAttributeValue(null, "value"));
232 } else if ("min-password-numeric".equals(tag)) {
233 minimumPasswordNumeric = Integer.parseInt(
234 parser.getAttributeValue(null, "value"));
235 } else if ("min-password-symbols".equals(tag)) {
236 minimumPasswordSymbols = Integer.parseInt(
237 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700238 } else if ("min-password-nonletter".equals(tag)) {
239 minimumPasswordNonLetter = Integer.parseInt(
240 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800241 } else if ("max-time-to-unlock".equals(tag)) {
242 maximumTimeToUnlock = Long.parseLong(
243 parser.getAttributeValue(null, "value"));
244 } else if ("max-failed-password-wipe".equals(tag)) {
245 maximumFailedPasswordsForWipe = Integer.parseInt(
246 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700247 } else if ("specifies-global-proxy".equals(tag)) {
248 specifiesGlobalProxy = Boolean.getBoolean(
249 parser.getAttributeValue(null, "value"));
250 } else if ("global-proxy-spec".equals(tag)) {
251 globalProxySpec =
252 parser.getAttributeValue(null, "value");
253 } else if ("global-proxy-exclusion-list".equals(tag)) {
254 globalProxyExclusionList =
255 parser.getAttributeValue(null, "value");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800256 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700257 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800258 }
259 XmlUtils.skipCurrentTag(parser);
260 }
261 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700262
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800263 void dump(String prefix, PrintWriter pw) {
264 pw.print(prefix); pw.print("uid="); pw.println(getUid());
265 pw.print(prefix); pw.println("policies:");
266 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
267 if (pols != null) {
268 for (int i=0; i<pols.size(); i++) {
269 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
270 }
271 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700272 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700273 pw.println(Integer.toHexString(passwordQuality));
274 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800275 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700276 pw.print(prefix); pw.print("passwordHistoryLength=");
277 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700278 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
279 pw.println(minimumPasswordUpperCase);
280 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
281 pw.println(minimumPasswordLowerCase);
282 pw.print(prefix); pw.print("minimumPasswordLetters=");
283 pw.println(minimumPasswordLetters);
284 pw.print(prefix); pw.print("minimumPasswordNumeric=");
285 pw.println(minimumPasswordNumeric);
286 pw.print(prefix); pw.print("minimumPasswordSymbols=");
287 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700288 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
289 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800290 pw.print(prefix); pw.print("maximumTimeToUnlock=");
291 pw.println(maximumTimeToUnlock);
292 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
293 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700294 pw.print(prefix); pw.print("specifiesGlobalProxy=");
295 pw.println(specifiesGlobalProxy);
296 if (globalProxySpec != null) {
297 pw.print(prefix); pw.print("globalProxySpec=");
298 pw.println(globalProxySpec);
299 }
300 if (globalProxyExclusionList != null) {
301 pw.print(prefix); pw.print("globalProxyEclusionList=");
302 pw.println(globalProxyExclusionList);
303 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800304 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800305 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700306
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800307 class MyPackageMonitor extends PackageMonitor {
308 public void onSomePackagesChanged() {
309 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800310 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800311 for (int i=mAdminList.size()-1; i>=0; i--) {
312 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700313 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800314 if (change == PACKAGE_PERMANENT_CHANGE
315 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700316 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800317 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800318 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800319 mAdminList.remove(i);
320 } else if (isPackageModified(aa.info.getPackageName())) {
321 try {
322 mContext.getPackageManager().getReceiverInfo(
323 aa.info.getComponent(), 0);
324 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700325 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800326 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800327 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800328 mAdminList.remove(i);
329 }
330 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800331 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800332 if (removed) {
333 validatePasswordOwnerLocked();
334 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800335 }
336 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800337 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700338
Dianne Hackbornd6847842010-01-12 18:14:19 -0800339 /**
340 * Instantiates the service.
341 */
342 public DevicePolicyManagerService(Context context) {
343 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800344 mMonitor = new MyPackageMonitor();
345 mMonitor.register(context, true);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800346 }
347
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800348 private IPowerManager getIPowerManager() {
349 if (mIPowerManager == null) {
350 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
351 mIPowerManager = IPowerManager.Stub.asInterface(b);
352 }
353 return mIPowerManager;
354 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700355
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800356 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800357 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800358 if (admin != null
359 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
360 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
361 return admin;
362 }
363 return null;
364 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700365
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800366 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
367 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800368 final int callingUid = Binder.getCallingUid();
369 if (who != null) {
370 ActiveAdmin admin = mAdminMap.get(who);
371 if (admin == null) {
372 throw new SecurityException("No active admin " + who);
373 }
374 if (admin.getUid() != callingUid) {
375 throw new SecurityException("Admin " + who + " is not owned by uid "
376 + Binder.getCallingUid());
377 }
378 if (!admin.info.usesPolicy(reqPolicy)) {
379 throw new SecurityException("Admin " + admin.info.getComponent()
380 + " did not specify uses-policy for: "
381 + admin.info.getTagForPolicy(reqPolicy));
382 }
383 return admin;
384 } else {
385 final int N = mAdminList.size();
386 for (int i=0; i<N; i++) {
387 ActiveAdmin admin = mAdminList.get(i);
388 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
389 return admin;
390 }
391 }
392 throw new SecurityException("No active admin owned by uid "
393 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800394 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800395 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700396
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800397 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800398 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800399 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800400 mContext.sendBroadcast(intent);
401 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700402
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800403 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800404 final int N = mAdminList.size();
405 if (N > 0) {
406 for (int i=0; i<N; i++) {
407 ActiveAdmin admin = mAdminList.get(i);
408 if (admin.info.usesPolicy(reqPolicy)) {
409 sendAdminCommandLocked(admin, action);
410 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800411 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800412 }
413 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700414
Dianne Hackbornd6847842010-01-12 18:14:19 -0800415 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800416 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
417 if (admin != null) {
Oscar Montemayor69238c62010-08-03 10:51:06 -0700418 boolean doProxyCleanup =
419 admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800420 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800421 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800422 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800423 mAdminList.remove(admin);
424 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800425 validatePasswordOwnerLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -0700426 if (doProxyCleanup) {
427 resetGlobalProxy();
428 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800429 }
430 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700431
Dianne Hackbornd6847842010-01-12 18:14:19 -0800432 public DeviceAdminInfo findAdmin(ComponentName adminName) {
433 Intent resolveIntent = new Intent();
434 resolveIntent.setComponent(adminName);
435 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
436 resolveIntent, PackageManager.GET_META_DATA);
437 if (infos == null || infos.size() <= 0) {
438 throw new IllegalArgumentException("Unknown admin: " + adminName);
439 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700440
Dianne Hackbornd6847842010-01-12 18:14:19 -0800441 try {
442 return new DeviceAdminInfo(mContext, infos.get(0));
443 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700444 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800445 return null;
446 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700447 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800448 return null;
449 }
450 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700451
Dianne Hackbornd6847842010-01-12 18:14:19 -0800452 private static JournaledFile makeJournaledFile() {
453 final String base = "/data/system/device_policies.xml";
454 return new JournaledFile(new File(base), new File(base + ".tmp"));
455 }
456
457 private void saveSettingsLocked() {
458 JournaledFile journal = makeJournaledFile();
459 FileOutputStream stream = null;
460 try {
461 stream = new FileOutputStream(journal.chooseForWrite(), false);
462 XmlSerializer out = new FastXmlSerializer();
463 out.setOutput(stream, "utf-8");
464 out.startDocument(null, true);
465
466 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700467
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800468 final int N = mAdminList.size();
469 for (int i=0; i<N; i++) {
470 ActiveAdmin ap = mAdminList.get(i);
471 if (ap != null) {
472 out.startTag(null, "admin");
473 out.attribute(null, "name", ap.info.getComponent().flattenToString());
474 ap.writeToXml(out);
475 out.endTag(null, "admin");
476 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800477 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700478
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800479 if (mPasswordOwner >= 0) {
480 out.startTag(null, "password-owner");
481 out.attribute(null, "value", Integer.toString(mPasswordOwner));
482 out.endTag(null, "password-owner");
483 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700484
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800485 if (mFailedPasswordAttempts != 0) {
486 out.startTag(null, "failed-password-attempts");
487 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
488 out.endTag(null, "failed-password-attempts");
489 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700490
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700491 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
492 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
493 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700494 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700495 out.startTag(null, "active-password");
496 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
497 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700498 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
499 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
500 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
501 out.attribute(null, "numeric", Integer
502 .toString(mActivePasswordNumeric));
503 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700504 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700505 out.endTag(null, "active-password");
506 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700507
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700508 out.endTag(null, "policies");
509
Dianne Hackbornd6847842010-01-12 18:14:19 -0800510 out.endDocument();
511 stream.close();
512 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700513 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800514 } catch (IOException e) {
515 try {
516 if (stream != null) {
517 stream.close();
518 }
519 } catch (IOException ex) {
520 // Ignore
521 }
522 journal.rollback();
523 }
524 }
525
Jim Miller284b62e2010-06-08 14:27:42 -0700526 private void sendChangedNotification() {
527 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
528 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
529 mContext.sendBroadcast(intent);
530 }
531
Dianne Hackbornd6847842010-01-12 18:14:19 -0800532 private void loadSettingsLocked() {
533 JournaledFile journal = makeJournaledFile();
534 FileInputStream stream = null;
535 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800536 try {
537 stream = new FileInputStream(file);
538 XmlPullParser parser = Xml.newPullParser();
539 parser.setInput(stream, null);
540
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800541 int type;
542 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
543 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800544 }
545 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800546 if (!"policies".equals(tag)) {
547 throw new XmlPullParserException(
548 "Settings do not start with policies tag: found " + tag);
549 }
550 type = parser.next();
551 int outerDepth = parser.getDepth();
552 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
553 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
554 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
555 continue;
556 }
557 tag = parser.getName();
558 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800559 String name = parser.getAttributeValue(null, "name");
560 try {
561 DeviceAdminInfo dai = findAdmin(
562 ComponentName.unflattenFromString(name));
563 if (dai != null) {
564 ActiveAdmin ap = new ActiveAdmin(dai);
565 ap.readFromXml(parser);
566 mAdminMap.put(ap.info.getComponent(), ap);
567 mAdminList.add(ap);
568 }
569 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700570 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800571 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800572 } else if ("failed-password-attempts".equals(tag)) {
573 mFailedPasswordAttempts = Integer.parseInt(
574 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800575 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800576 } else if ("password-owner".equals(tag)) {
577 mPasswordOwner = Integer.parseInt(
578 parser.getAttributeValue(null, "value"));
579 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700580 } else if ("active-password".equals(tag)) {
581 mActivePasswordQuality = Integer.parseInt(
582 parser.getAttributeValue(null, "quality"));
583 mActivePasswordLength = Integer.parseInt(
584 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700585 mActivePasswordUpperCase = Integer.parseInt(
586 parser.getAttributeValue(null, "uppercase"));
587 mActivePasswordLowerCase = Integer.parseInt(
588 parser.getAttributeValue(null, "lowercase"));
589 mActivePasswordLetters = Integer.parseInt(
590 parser.getAttributeValue(null, "letters"));
591 mActivePasswordNumeric = Integer.parseInt(
592 parser.getAttributeValue(null, "numeric"));
593 mActivePasswordSymbols = Integer.parseInt(
594 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700595 mActivePasswordNonLetter = Integer.parseInt(
596 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700597 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800598 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700599 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800600 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800601 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800602 }
603 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700604 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800605 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700606 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800607 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700608 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700609 } catch (FileNotFoundException e) {
610 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800611 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700612 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800613 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700614 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800615 }
616 try {
617 if (stream != null) {
618 stream.close();
619 }
620 } catch (IOException e) {
621 // Ignore
622 }
623
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700624 // Validate that what we stored for the password quality matches
625 // sufficiently what is currently set. Note that this is only
626 // a sanity check in case the two get out of sync; this should
627 // never normally happen.
628 LockPatternUtils utils = new LockPatternUtils(mContext);
629 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
630 Slog.w(TAG, "Active password quality 0x"
631 + Integer.toHexString(mActivePasswordQuality)
632 + " does not match actual quality 0x"
633 + Integer.toHexString(utils.getActivePasswordQuality()));
634 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
635 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700636 mActivePasswordUpperCase = 0;
637 mActivePasswordLowerCase = 0;
638 mActivePasswordLetters = 0;
639 mActivePasswordNumeric = 0;
640 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700641 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700642 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700643
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800644 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700645
Dianne Hackborn254cb442010-01-27 19:23:59 -0800646 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800647 if (timeMs <= 0) {
648 timeMs = Integer.MAX_VALUE;
649 }
650 try {
651 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
652 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700653 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800654 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800655 }
656
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700657 static void validateQualityConstant(int quality) {
658 switch (quality) {
659 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
660 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
661 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
662 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
663 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700664 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700665 return;
666 }
667 throw new IllegalArgumentException("Invalid quality constant: 0x"
668 + Integer.toHexString(quality));
669 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700670
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800671 void validatePasswordOwnerLocked() {
672 if (mPasswordOwner >= 0) {
673 boolean haveOwner = false;
674 for (int i=mAdminList.size()-1; i>=0; i--) {
675 if (mAdminList.get(i).getUid() == mPasswordOwner) {
676 haveOwner = true;
677 break;
678 }
679 }
680 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700681 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800682 + " no longer active; disabling");
683 mPasswordOwner = -1;
684 }
685 }
686 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700687
Dianne Hackbornd6847842010-01-12 18:14:19 -0800688 public void systemReady() {
689 synchronized (this) {
690 loadSettingsLocked();
691 }
692 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700693
Dianne Hackbornd6847842010-01-12 18:14:19 -0800694 public void setActiveAdmin(ComponentName adminReceiver) {
695 mContext.enforceCallingOrSelfPermission(
696 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700697
Dianne Hackbornd6847842010-01-12 18:14:19 -0800698 DeviceAdminInfo info = findAdmin(adminReceiver);
699 if (info == null) {
700 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
701 }
702 synchronized (this) {
703 long ident = Binder.clearCallingIdentity();
704 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800705 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
706 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800707 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800708 ActiveAdmin admin = new ActiveAdmin(info);
709 mAdminMap.put(adminReceiver, admin);
710 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800711 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800712 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800713 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800714 } finally {
715 Binder.restoreCallingIdentity(ident);
716 }
717 }
718 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700719
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800720 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800721 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800722 return getActiveAdminUncheckedLocked(adminReceiver) != null;
723 }
724 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700725
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800726 public List<ComponentName> getActiveAdmins() {
727 synchronized (this) {
728 final int N = mAdminList.size();
729 if (N <= 0) {
730 return null;
731 }
732 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
733 for (int i=0; i<N; i++) {
734 res.add(mAdminList.get(i).info.getComponent());
735 }
736 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800737 }
738 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700739
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800740 public boolean packageHasActiveAdmins(String packageName) {
741 synchronized (this) {
742 final int N = mAdminList.size();
743 for (int i=0; i<N; i++) {
744 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
745 return true;
746 }
747 }
748 return false;
749 }
750 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700751
Dianne Hackbornd6847842010-01-12 18:14:19 -0800752 public void removeActiveAdmin(ComponentName adminReceiver) {
753 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800754 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
755 if (admin == null) {
756 return;
757 }
758 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800759 mContext.enforceCallingOrSelfPermission(
760 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
761 }
762 long ident = Binder.clearCallingIdentity();
763 try {
764 removeActiveAdminLocked(adminReceiver);
765 } finally {
766 Binder.restoreCallingIdentity(ident);
767 }
768 }
769 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700770
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700771 public void setPasswordQuality(ComponentName who, int quality) {
772 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700773
Dianne Hackbornd6847842010-01-12 18:14:19 -0800774 synchronized (this) {
775 if (who == null) {
776 throw new NullPointerException("ComponentName is null");
777 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800778 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
779 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700780 if (ap.passwordQuality != quality) {
781 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800782 saveSettingsLocked();
783 }
784 }
785 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700786
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800787 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800788 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800789 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700790
Dianne Hackborn254cb442010-01-27 19:23:59 -0800791 if (who != null) {
792 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800793 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800794 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700795
Dianne Hackborn254cb442010-01-27 19:23:59 -0800796 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800797 for (int i=0; i<N; i++) {
798 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800799 if (mode < admin.passwordQuality) {
800 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800801 }
802 }
803 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800804 }
805 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700806
Dianne Hackborn254cb442010-01-27 19:23:59 -0800807 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800808 synchronized (this) {
809 if (who == null) {
810 throw new NullPointerException("ComponentName is null");
811 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800812 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
813 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800814 if (ap.minimumPasswordLength != length) {
815 ap.minimumPasswordLength = length;
816 saveSettingsLocked();
817 }
818 }
819 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700820
Dianne Hackborn254cb442010-01-27 19:23:59 -0800821 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800822 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800823 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700824
Dianne Hackborn254cb442010-01-27 19:23:59 -0800825 if (who != null) {
826 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
827 return admin != null ? admin.minimumPasswordLength : length;
828 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700829
Dianne Hackborn254cb442010-01-27 19:23:59 -0800830 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800831 for (int i=0; i<N; i++) {
832 ActiveAdmin admin = mAdminList.get(i);
833 if (length < admin.minimumPasswordLength) {
834 length = admin.minimumPasswordLength;
835 }
836 }
837 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800838 }
839 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700840
841 public void setPasswordHistoryLength(ComponentName who, int length) {
842 synchronized (this) {
843 if (who == null) {
844 throw new NullPointerException("ComponentName is null");
845 }
846 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
847 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
848 if (ap.passwordHistoryLength != length) {
849 ap.passwordHistoryLength = length;
850 saveSettingsLocked();
851 }
852 }
853 }
854
855 public int getPasswordHistoryLength(ComponentName who) {
856 synchronized (this) {
857 int length = 0;
858
859 if (who != null) {
860 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
861 return admin != null ? admin.passwordHistoryLength : length;
862 }
863
864 final int N = mAdminList.size();
865 for (int i = 0; i < N; i++) {
866 ActiveAdmin admin = mAdminList.get(i);
867 if (length < admin.passwordHistoryLength) {
868 length = admin.passwordHistoryLength;
869 }
870 }
871 return length;
872 }
873 }
874
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700875 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
876 synchronized (this) {
877 if (who == null) {
878 throw new NullPointerException("ComponentName is null");
879 }
880 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
881 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
882 if (ap.minimumPasswordUpperCase != length) {
883 ap.minimumPasswordUpperCase = length;
884 saveSettingsLocked();
885 }
886 }
887 }
888
889 public int getPasswordMinimumUpperCase(ComponentName who) {
890 synchronized (this) {
891 int length = 0;
892
893 if (who != null) {
894 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
895 return admin != null ? admin.minimumPasswordUpperCase : length;
896 }
897
898 final int N = mAdminList.size();
899 for (int i=0; i<N; i++) {
900 ActiveAdmin admin = mAdminList.get(i);
901 if (length < admin.minimumPasswordUpperCase) {
902 length = admin.minimumPasswordUpperCase;
903 }
904 }
905 return length;
906 }
907 }
908
909 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
910 synchronized (this) {
911 if (who == null) {
912 throw new NullPointerException("ComponentName is null");
913 }
914 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
915 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
916 if (ap.minimumPasswordLowerCase != length) {
917 ap.minimumPasswordLowerCase = length;
918 saveSettingsLocked();
919 }
920 }
921 }
922
923 public int getPasswordMinimumLowerCase(ComponentName who) {
924 synchronized (this) {
925 int length = 0;
926
927 if (who != null) {
928 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
929 return admin != null ? admin.minimumPasswordLowerCase : length;
930 }
931
932 final int N = mAdminList.size();
933 for (int i=0; i<N; i++) {
934 ActiveAdmin admin = mAdminList.get(i);
935 if (length < admin.minimumPasswordLowerCase) {
936 length = admin.minimumPasswordLowerCase;
937 }
938 }
939 return length;
940 }
941 }
942
943 public void setPasswordMinimumLetters(ComponentName who, int length) {
944 synchronized (this) {
945 if (who == null) {
946 throw new NullPointerException("ComponentName is null");
947 }
948 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
949 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
950 if (ap.minimumPasswordLetters != length) {
951 ap.minimumPasswordLetters = length;
952 saveSettingsLocked();
953 }
954 }
955 }
956
957 public int getPasswordMinimumLetters(ComponentName who) {
958 synchronized (this) {
959 int length = 0;
960
961 if (who != null) {
962 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
963 return admin != null ? admin.minimumPasswordLetters : length;
964 }
965
966 final int N = mAdminList.size();
967 for (int i=0; i<N; i++) {
968 ActiveAdmin admin = mAdminList.get(i);
969 if (length < admin.minimumPasswordLetters) {
970 length = admin.minimumPasswordLetters;
971 }
972 }
973 return length;
974 }
975 }
976
977 public void setPasswordMinimumNumeric(ComponentName who, int length) {
978 synchronized (this) {
979 if (who == null) {
980 throw new NullPointerException("ComponentName is null");
981 }
982 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
983 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
984 if (ap.minimumPasswordNumeric != length) {
985 ap.minimumPasswordNumeric = length;
986 saveSettingsLocked();
987 }
988 }
989 }
990
991 public int getPasswordMinimumNumeric(ComponentName who) {
992 synchronized (this) {
993 int length = 0;
994
995 if (who != null) {
996 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
997 return admin != null ? admin.minimumPasswordNumeric : length;
998 }
999
1000 final int N = mAdminList.size();
1001 for (int i = 0; i < N; i++) {
1002 ActiveAdmin admin = mAdminList.get(i);
1003 if (length < admin.minimumPasswordNumeric) {
1004 length = admin.minimumPasswordNumeric;
1005 }
1006 }
1007 return length;
1008 }
1009 }
1010
1011 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1012 synchronized (this) {
1013 if (who == null) {
1014 throw new NullPointerException("ComponentName is null");
1015 }
1016 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1017 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1018 if (ap.minimumPasswordSymbols != length) {
1019 ap.minimumPasswordSymbols = length;
1020 saveSettingsLocked();
1021 }
1022 }
1023 }
1024
1025 public int getPasswordMinimumSymbols(ComponentName who) {
1026 synchronized (this) {
1027 int length = 0;
1028
1029 if (who != null) {
1030 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1031 return admin != null ? admin.minimumPasswordSymbols : length;
1032 }
1033
1034 final int N = mAdminList.size();
1035 for (int i=0; i<N; i++) {
1036 ActiveAdmin admin = mAdminList.get(i);
1037 if (length < admin.minimumPasswordSymbols) {
1038 length = admin.minimumPasswordSymbols;
1039 }
1040 }
1041 return length;
1042 }
1043 }
1044
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001045 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1046 synchronized (this) {
1047 if (who == null) {
1048 throw new NullPointerException("ComponentName is null");
1049 }
1050 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1051 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1052 if (ap.minimumPasswordNonLetter != length) {
1053 ap.minimumPasswordNonLetter = length;
1054 saveSettingsLocked();
1055 }
1056 }
1057 }
1058
1059 public int getPasswordMinimumNonLetter(ComponentName who) {
1060 synchronized (this) {
1061 int length = 0;
1062
1063 if (who != null) {
1064 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1065 return admin != null ? admin.minimumPasswordNonLetter : length;
1066 }
1067
1068 final int N = mAdminList.size();
1069 for (int i=0; i<N; i++) {
1070 ActiveAdmin admin = mAdminList.get(i);
1071 if (length < admin.minimumPasswordNonLetter) {
1072 length = admin.minimumPasswordNonLetter;
1073 }
1074 }
1075 return length;
1076 }
1077 }
1078
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001079 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001080 synchronized (this) {
1081 // This API can only be called by an active device admin,
1082 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001083 getActiveAdminForCallerLocked(null,
1084 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001085 if (mActivePasswordQuality < getPasswordQuality(null)
1086 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1087 return false;
1088 }
1089 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1090 return true;
1091 }
1092 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1093 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1094 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1095 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001096 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1097 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001098 }
1099 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001100
Dianne Hackbornd6847842010-01-12 18:14:19 -08001101 public int getCurrentFailedPasswordAttempts() {
1102 synchronized (this) {
1103 // This API can only be called by an active device admin,
1104 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001105 getActiveAdminForCallerLocked(null,
1106 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001107 return mFailedPasswordAttempts;
1108 }
1109 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001110
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001111 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1112 synchronized (this) {
1113 // This API can only be called by an active device admin,
1114 // so try to retrieve it to check that the caller is one.
1115 getActiveAdminForCallerLocked(who,
1116 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1117 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1118 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1119 if (ap.maximumFailedPasswordsForWipe != num) {
1120 ap.maximumFailedPasswordsForWipe = num;
1121 saveSettingsLocked();
1122 }
1123 }
1124 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001125
Dianne Hackborn254cb442010-01-27 19:23:59 -08001126 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001127 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001128 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001129
Dianne Hackborn254cb442010-01-27 19:23:59 -08001130 if (who != null) {
1131 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1132 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1133 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001134
Dianne Hackborn254cb442010-01-27 19:23:59 -08001135 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001136 for (int i=0; i<N; i++) {
1137 ActiveAdmin admin = mAdminList.get(i);
1138 if (count == 0) {
1139 count = admin.maximumFailedPasswordsForWipe;
1140 } else if (admin.maximumFailedPasswordsForWipe != 0
1141 && count > admin.maximumFailedPasswordsForWipe) {
1142 count = admin.maximumFailedPasswordsForWipe;
1143 }
1144 }
1145 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001146 }
1147 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001148
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001149 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001150 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001151 synchronized (this) {
1152 // This API can only be called by an active device admin,
1153 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001154 getActiveAdminForCallerLocked(null,
1155 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001156 quality = getPasswordQuality(null);
1157 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001158 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001159 if (realQuality < quality
1160 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001161 Slog.w(TAG, "resetPassword: password quality 0x"
1162 + Integer.toHexString(quality)
1163 + " does not meet required quality 0x"
1164 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001165 return false;
1166 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001167 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001168 }
1169 int length = getPasswordMinimumLength(null);
1170 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001171 Slog.w(TAG, "resetPassword: password length " + password.length()
1172 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001173 return false;
1174 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001175 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1176 int letters = 0;
1177 int uppercase = 0;
1178 int lowercase = 0;
1179 int numbers = 0;
1180 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001181 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001182 for (int i = 0; i < password.length(); i++) {
1183 char c = password.charAt(i);
1184 if (c >= 'A' && c <= 'Z') {
1185 letters++;
1186 uppercase++;
1187 } else if (c >= 'a' && c <= 'z') {
1188 letters++;
1189 lowercase++;
1190 } else if (c >= '0' && c <= '9') {
1191 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001192 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001193 } else {
1194 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001195 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001196 }
1197 }
1198 int neededLetters = getPasswordMinimumLetters(null);
1199 if(letters < neededLetters) {
1200 Slog.w(TAG, "resetPassword: number of letters " + letters
1201 + " does not meet required number of letters " + neededLetters);
1202 return false;
1203 }
1204 int neededNumbers = getPasswordMinimumNumeric(null);
1205 if (numbers < neededNumbers) {
1206 Slog
1207 .w(TAG, "resetPassword: number of numerical digits " + numbers
1208 + " does not meet required number of numerical digits "
1209 + neededNumbers);
1210 return false;
1211 }
1212 int neededLowerCase = getPasswordMinimumLowerCase(null);
1213 if (lowercase < neededLowerCase) {
1214 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1215 + " does not meet required number of lowercase letters "
1216 + neededLowerCase);
1217 return false;
1218 }
1219 int neededUpperCase = getPasswordMinimumUpperCase(null);
1220 if (uppercase < neededUpperCase) {
1221 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1222 + " does not meet required number of uppercase letters "
1223 + neededUpperCase);
1224 return false;
1225 }
1226 int neededSymbols = getPasswordMinimumSymbols(null);
1227 if (symbols < neededSymbols) {
1228 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1229 + " does not meet required number of special symbols " + neededSymbols);
1230 return false;
1231 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001232 int neededNonLetter = getPasswordMinimumNonLetter(null);
1233 if (nonletter < neededNonLetter) {
1234 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1235 + " does not meet required number of non-letter characters "
1236 + neededNonLetter);
1237 return false;
1238 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001239 }
1240
1241 LockPatternUtils utils = new LockPatternUtils(mContext);
1242 if(utils.checkPasswordHistory(password)) {
1243 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1244 + getPasswordHistoryLength(null) + " passwords");
1245 return false;
1246 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001247 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001248
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001249 int callingUid = Binder.getCallingUid();
1250 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001251 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001252 return false;
1253 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001254
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001255 // Don't do this with the lock held, because it is going to call
1256 // back in to the service.
1257 long ident = Binder.clearCallingIdentity();
1258 try {
1259 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001260 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001261 synchronized (this) {
1262 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1263 != 0 ? callingUid : -1;
1264 if (mPasswordOwner != newOwner) {
1265 mPasswordOwner = newOwner;
1266 saveSettingsLocked();
1267 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001268 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001269 } finally {
1270 Binder.restoreCallingIdentity(ident);
1271 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001272
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001273 return true;
1274 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001275
Dianne Hackbornd6847842010-01-12 18:14:19 -08001276 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1277 synchronized (this) {
1278 if (who == null) {
1279 throw new NullPointerException("ComponentName is null");
1280 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001281 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001282 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001283 if (ap.maximumTimeToUnlock != timeMs) {
1284 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001285
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001286 long ident = Binder.clearCallingIdentity();
1287 try {
1288 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001289
Dianne Hackborn254cb442010-01-27 19:23:59 -08001290 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001291 if (timeMs <= 0) {
1292 timeMs = Integer.MAX_VALUE;
1293 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001294
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001295 try {
1296 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1297 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001298 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001299 }
1300 } finally {
1301 Binder.restoreCallingIdentity(ident);
1302 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001303 }
1304 }
1305 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001306
Dianne Hackborn254cb442010-01-27 19:23:59 -08001307 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001308 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001309 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001310
Dianne Hackborn254cb442010-01-27 19:23:59 -08001311 if (who != null) {
1312 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1313 return admin != null ? admin.maximumTimeToUnlock : time;
1314 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001315
Dianne Hackborn254cb442010-01-27 19:23:59 -08001316 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001317 for (int i=0; i<N; i++) {
1318 ActiveAdmin admin = mAdminList.get(i);
1319 if (time == 0) {
1320 time = admin.maximumTimeToUnlock;
1321 } else if (admin.maximumTimeToUnlock != 0
1322 && time > admin.maximumTimeToUnlock) {
1323 time = admin.maximumTimeToUnlock;
1324 }
1325 }
1326 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001327 }
1328 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001329
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001330 public void lockNow() {
1331 synchronized (this) {
1332 // This API can only be called by an active device admin,
1333 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001334 getActiveAdminForCallerLocked(null,
1335 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001336 long ident = Binder.clearCallingIdentity();
1337 try {
1338 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1339 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1340 } catch (RemoteException e) {
1341 } finally {
1342 Binder.restoreCallingIdentity(ident);
1343 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001344 }
1345 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001346
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001347 void wipeDataLocked(int flags) {
1348 try {
1349 RecoverySystem.rebootWipeUserData(mContext);
1350 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001351 Slog.w(TAG, "Failed requesting data wipe", e);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001352 }
1353 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001354
Dianne Hackbornd6847842010-01-12 18:14:19 -08001355 public void wipeData(int flags) {
1356 synchronized (this) {
1357 // This API can only be called by an active device admin,
1358 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001359 getActiveAdminForCallerLocked(null,
1360 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001361 long ident = Binder.clearCallingIdentity();
1362 try {
1363 wipeDataLocked(flags);
1364 } finally {
1365 Binder.restoreCallingIdentity(ident);
1366 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001367 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001368 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001369
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001370 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1371 mContext.enforceCallingOrSelfPermission(
1372 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001373
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001374 synchronized (this) {
1375 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1376 if (admin == null) {
1377 try {
1378 result.sendResult(null);
1379 } catch (RemoteException e) {
1380 }
1381 return;
1382 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001383 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001384 intent.setComponent(admin.info.getComponent());
1385 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1386 @Override
1387 public void onReceive(Context context, Intent intent) {
1388 try {
1389 result.sendResult(getResultExtras(false));
1390 } catch (RemoteException e) {
1391 }
1392 }
1393 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001394 }
1395 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001396
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001397 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001398 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001399 mContext.enforceCallingOrSelfPermission(
1400 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001401
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001402 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001403
Dianne Hackbornd6847842010-01-12 18:14:19 -08001404 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001405 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001406 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1407 || mActivePasswordUpperCase != uppercase
1408 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001409 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001410 long ident = Binder.clearCallingIdentity();
1411 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001412 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001413 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001414 mActivePasswordLetters = letters;
1415 mActivePasswordLowerCase = lowercase;
1416 mActivePasswordUpperCase = uppercase;
1417 mActivePasswordNumeric = numbers;
1418 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001419 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001420 mFailedPasswordAttempts = 0;
1421 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001422 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001423 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001424 } finally {
1425 Binder.restoreCallingIdentity(ident);
1426 }
1427 }
1428 }
1429 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001430
Dianne Hackbornd6847842010-01-12 18:14:19 -08001431 public void reportFailedPasswordAttempt() {
1432 mContext.enforceCallingOrSelfPermission(
1433 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001434
Dianne Hackbornd6847842010-01-12 18:14:19 -08001435 synchronized (this) {
1436 long ident = Binder.clearCallingIdentity();
1437 try {
1438 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001439 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001440 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001441 if (max > 0 && mFailedPasswordAttempts >= max) {
1442 wipeDataLocked(0);
1443 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001444 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001445 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001446 } finally {
1447 Binder.restoreCallingIdentity(ident);
1448 }
1449 }
1450 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001451
Dianne Hackbornd6847842010-01-12 18:14:19 -08001452 public void reportSuccessfulPasswordAttempt() {
1453 mContext.enforceCallingOrSelfPermission(
1454 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001455
Dianne Hackbornd6847842010-01-12 18:14:19 -08001456 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001457 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001458 long ident = Binder.clearCallingIdentity();
1459 try {
1460 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001461 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001462 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001463 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001464 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001465 } finally {
1466 Binder.restoreCallingIdentity(ident);
1467 }
1468 }
1469 }
1470 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001471
Oscar Montemayor69238c62010-08-03 10:51:06 -07001472 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1473 String exclusionList) {
1474 synchronized(this) {
1475 if (who == null) {
1476 throw new NullPointerException("ComponentName is null");
1477 }
1478
1479 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1480 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1481
1482 // Scan through active admins and find if anyone has already
1483 // set the global proxy.
1484 final int N = mAdminList.size();
1485 Set<ComponentName> compSet = mAdminMap.keySet();
1486 for (ComponentName component : compSet) {
1487 ActiveAdmin ap = mAdminMap.get(component);
1488 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1489 // Another admin already sets the global proxy
1490 // Return it to the caller.
1491 return component;
1492 }
1493 }
1494 if (proxySpec == null) {
1495 admin.specifiesGlobalProxy = false;
1496 admin.globalProxySpec = null;
1497 admin.globalProxyExclusionList = null;
1498 } else {
1499
1500 admin.specifiesGlobalProxy = true;
1501 admin.globalProxySpec = proxySpec;
1502 admin.globalProxyExclusionList = exclusionList;
1503 }
1504
1505 // Reset the global proxy accordingly
1506 // Do this using system permissions, as apps cannot write to secure settings
1507 long origId = Binder.clearCallingIdentity();
1508 resetGlobalProxy();
1509 Binder.restoreCallingIdentity(origId);
1510 return null;
1511 }
1512 }
1513
1514 public ComponentName getGlobalProxyAdmin() {
1515 synchronized(this) {
1516 // Scan through active admins and find if anyone has already
1517 // set the global proxy.
1518 final int N = mAdminList.size();
1519 for (int i = 0; i < N; i++) {
1520 ActiveAdmin ap = mAdminList.get(i);
1521 if (ap.specifiesGlobalProxy) {
1522 // Device admin sets the global proxy
1523 // Return it to the caller.
1524 return ap.info.getComponent();
1525 }
1526 }
1527 }
1528 // No device admin sets the global proxy.
1529 return null;
1530 }
1531
1532 private void resetGlobalProxy() {
1533 final int N = mAdminList.size();
1534 for (int i = 0; i < N; i++) {
1535 ActiveAdmin ap = mAdminList.get(i);
1536 if (ap.specifiesGlobalProxy) {
1537 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1538 return;
1539 }
1540 }
1541 // No device admins defining global proxies - reset global proxy settings to none
1542 saveGlobalProxy(null, null);
1543 }
1544
1545 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1546 if (exclusionList == null) {
1547 exclusionList = "";
1548 }
1549 if (proxySpec == null) {
1550 proxySpec = "";
1551 }
1552 // Remove white spaces
1553 proxySpec = proxySpec.trim();
1554 exclusionList = exclusionList.trim();
1555 ContentResolver res = mContext.getContentResolver();
1556 Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY, proxySpec);
1557 Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY_EXCLUSION_LIST, exclusionList);
1558 }
1559
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001560 @Override
1561 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1562 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1563 != PackageManager.PERMISSION_GRANTED) {
1564
1565 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1566 + Binder.getCallingPid()
1567 + ", uid=" + Binder.getCallingUid());
1568 return;
1569 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001570
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001571 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001572
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001573 synchronized (this) {
1574 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001575
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001576 p.println(" Enabled Device Admins:");
1577 final int N = mAdminList.size();
1578 for (int i=0; i<N; i++) {
1579 ActiveAdmin ap = mAdminList.get(i);
1580 if (ap != null) {
1581 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1582 pw.println(":");
1583 ap.dump(" ", pw);
1584 }
1585 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001586
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001587 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001588 pw.print(" mActivePasswordQuality=0x");
1589 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001590 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001591 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1592 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1593 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1594 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1595 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001596 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001597 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1598 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1599 }
1600 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001601}