blob: 68aa8e37ba7c7a3a7319cab890de4bfaf6585bf0 [file] [log] [blame]
Dianne Hackbornd6847842010-01-12 18:14:19 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080019import com.android.internal.content.PackageMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070020import com.android.internal.os.storage.ExternalStorageFormatter;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080021import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070022import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080023import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080024import com.android.internal.widget.LockPatternUtils;
Dianne Hackbornd6847842010-01-12 18:14:19 -080025
26import org.xmlpull.v1.XmlPullParser;
27import org.xmlpull.v1.XmlPullParserException;
28import org.xmlpull.v1.XmlSerializer;
29
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080030import android.app.Activity;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080031import android.app.admin.DeviceAdminInfo;
32import android.app.admin.DeviceAdminReceiver;
33import android.app.admin.DevicePolicyManager;
34import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080035import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080036import android.content.ComponentName;
Oscar Montemayor69238c62010-08-03 10:51:06 -070037import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080038import android.content.Context;
39import android.content.Intent;
40import android.content.pm.PackageManager;
41import android.content.pm.ResolveInfo;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080042import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080043import android.os.Binder;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080044import android.os.IBinder;
45import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070046import android.os.PowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080047import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080048import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080049import android.os.RemoteException;
50import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080051import android.os.SystemClock;
Oscar Montemayor69238c62010-08-03 10:51:06 -070052import android.net.Proxy;
53import android.provider.Settings;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -070054import android.util.Slog;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080055import android.util.PrintWriterPrinter;
56import android.util.Printer;
Dianne Hackbornd6847842010-01-12 18:14:19 -080057import android.util.Xml;
Dianne Hackborn254cb442010-01-27 19:23:59 -080058import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080059
60import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080061import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080062import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070063import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080064import java.io.FileOutputStream;
65import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080066import java.io.PrintWriter;
Oscar Montemayor69238c62010-08-03 10:51:06 -070067import java.net.InetSocketAddress;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080068import java.util.ArrayList;
69import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080070import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070071import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080072
73/**
74 * Implementation of the device policy APIs.
75 */
76public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080077 static final String TAG = "DevicePolicyManagerService";
Konstantin Lopyrev32558232010-05-20 16:18:05 -070078
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080079 final Context mContext;
80 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070081 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080082
Dianne Hackborndf83afa2010-01-20 13:37:26 -080083 IPowerManager mIPowerManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070084
Dianne Hackborn9327f4f2010-01-29 10:38:29 -080085 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -080086 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -070087 int mActivePasswordUpperCase = 0;
88 int mActivePasswordLowerCase = 0;
89 int mActivePasswordLetters = 0;
90 int mActivePasswordNumeric = 0;
91 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -070092 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -080093 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070094
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080095 int mPasswordOwner = -1;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070096
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080097 final HashMap<ComponentName, ActiveAdmin> mAdminMap
98 = new HashMap<ComponentName, ActiveAdmin>();
99 final ArrayList<ActiveAdmin> mAdminList
100 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700101
Dianne Hackbornd6847842010-01-12 18:14:19 -0800102 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800103 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700104
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800105 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800106 int minimumPasswordLength = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700107 int passwordHistoryLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700108 int minimumPasswordUpperCase = 0;
109 int minimumPasswordLowerCase = 0;
110 int minimumPasswordLetters = 1;
111 int minimumPasswordNumeric = 1;
112 int minimumPasswordSymbols = 1;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700113 int minimumPasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800114 long maximumTimeToUnlock = 0;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800115 int maximumFailedPasswordsForWipe = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700116
Oscar Montemayor69238c62010-08-03 10:51:06 -0700117 // TODO: review implementation decisions with frameworks team
118 boolean specifiesGlobalProxy = false;
119 String globalProxySpec = null;
120 String globalProxyExclusionList = null;
121
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800122 ActiveAdmin(DeviceAdminInfo _info) {
123 info = _info;
124 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700125
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800126 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700127
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800128 void writeToXml(XmlSerializer out)
129 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800130 out.startTag(null, "policies");
131 info.writePoliciesToXml(out);
132 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800133 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
134 out.startTag(null, "password-quality");
135 out.attribute(null, "value", Integer.toString(passwordQuality));
136 out.endTag(null, "password-quality");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800137 if (minimumPasswordLength > 0) {
138 out.startTag(null, "min-password-length");
139 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700140 out.endTag(null, "min-password-length");
141 }
142 if(passwordHistoryLength > 0) {
143 out.startTag(null, "password-history-length");
144 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
145 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800146 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700147 if (minimumPasswordUpperCase > 0) {
148 out.startTag(null, "min-password-uppercase");
149 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
150 out.endTag(null, "min-password-uppercase");
151 }
152 if (minimumPasswordLowerCase > 0) {
153 out.startTag(null, "min-password-lowercase");
154 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
155 out.endTag(null, "min-password-lowercase");
156 }
157 if (minimumPasswordLetters > 0) {
158 out.startTag(null, "min-password-letters");
159 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
160 out.endTag(null, "min-password-letters");
161 }
162 if (minimumPasswordNumeric > 0) {
163 out.startTag(null, "min-password-numeric");
164 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
165 out.endTag(null, "min-password-numeric");
166 }
167 if (minimumPasswordSymbols > 0) {
168 out.startTag(null, "min-password-symbols");
169 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
170 out.endTag(null, "min-password-symbols");
171 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700172 if (minimumPasswordNonLetter > 0) {
173 out.startTag(null, "min-password-nonletter");
174 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
175 out.endTag(null, "min-password-nonletter");
176 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800177 }
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700178 if (maximumTimeToUnlock != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800179 out.startTag(null, "max-time-to-unlock");
180 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
181 out.endTag(null, "max-time-to-unlock");
182 }
183 if (maximumFailedPasswordsForWipe != 0) {
184 out.startTag(null, "max-failed-password-wipe");
185 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
186 out.endTag(null, "max-failed-password-wipe");
187 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700188 if (specifiesGlobalProxy) {
189 out.startTag(null, "specifies-global-proxy");
190 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
191 out.endTag(null, "specifies_global_proxy");
192 if (globalProxySpec != null) {
193 out.startTag(null, "global-proxy-spec");
194 out.attribute(null, "value", globalProxySpec);
195 out.endTag(null, "global-proxy-spec");
196 }
197 if (globalProxyExclusionList != null) {
198 out.startTag(null, "global-proxy-exclusion-list");
199 out.attribute(null, "value", globalProxyExclusionList);
200 out.endTag(null, "global-proxy-exclusion-list");
201 }
202 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800203 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700204
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800205 void readFromXml(XmlPullParser parser)
206 throws XmlPullParserException, IOException {
207 int outerDepth = parser.getDepth();
208 int type;
209 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
210 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
211 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
212 continue;
213 }
214 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800215 if ("policies".equals(tag)) {
216 info.readPoliciesFromXml(parser);
217 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800218 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800219 parser.getAttributeValue(null, "value"));
220 } else if ("min-password-length".equals(tag)) {
221 minimumPasswordLength = Integer.parseInt(
222 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700223 } else if ("password-history-length".equals(tag)) {
224 passwordHistoryLength = Integer.parseInt(
225 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700226 } else if ("min-password-uppercase".equals(tag)) {
227 minimumPasswordUpperCase = Integer.parseInt(
228 parser.getAttributeValue(null, "value"));
229 } else if ("min-password-lowercase".equals(tag)) {
230 minimumPasswordLowerCase = Integer.parseInt(
231 parser.getAttributeValue(null, "value"));
232 } else if ("min-password-letters".equals(tag)) {
233 minimumPasswordLetters = Integer.parseInt(
234 parser.getAttributeValue(null, "value"));
235 } else if ("min-password-numeric".equals(tag)) {
236 minimumPasswordNumeric = Integer.parseInt(
237 parser.getAttributeValue(null, "value"));
238 } else if ("min-password-symbols".equals(tag)) {
239 minimumPasswordSymbols = Integer.parseInt(
240 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700241 } else if ("min-password-nonletter".equals(tag)) {
242 minimumPasswordNonLetter = Integer.parseInt(
243 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800244 } else if ("max-time-to-unlock".equals(tag)) {
245 maximumTimeToUnlock = Long.parseLong(
246 parser.getAttributeValue(null, "value"));
247 } else if ("max-failed-password-wipe".equals(tag)) {
248 maximumFailedPasswordsForWipe = Integer.parseInt(
249 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700250 } else if ("specifies-global-proxy".equals(tag)) {
251 specifiesGlobalProxy = Boolean.getBoolean(
252 parser.getAttributeValue(null, "value"));
253 } else if ("global-proxy-spec".equals(tag)) {
254 globalProxySpec =
255 parser.getAttributeValue(null, "value");
256 } else if ("global-proxy-exclusion-list".equals(tag)) {
257 globalProxyExclusionList =
258 parser.getAttributeValue(null, "value");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800259 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700260 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800261 }
262 XmlUtils.skipCurrentTag(parser);
263 }
264 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700265
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800266 void dump(String prefix, PrintWriter pw) {
267 pw.print(prefix); pw.print("uid="); pw.println(getUid());
268 pw.print(prefix); pw.println("policies:");
269 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
270 if (pols != null) {
271 for (int i=0; i<pols.size(); i++) {
272 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
273 }
274 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700275 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700276 pw.println(Integer.toHexString(passwordQuality));
277 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800278 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700279 pw.print(prefix); pw.print("passwordHistoryLength=");
280 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700281 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
282 pw.println(minimumPasswordUpperCase);
283 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
284 pw.println(minimumPasswordLowerCase);
285 pw.print(prefix); pw.print("minimumPasswordLetters=");
286 pw.println(minimumPasswordLetters);
287 pw.print(prefix); pw.print("minimumPasswordNumeric=");
288 pw.println(minimumPasswordNumeric);
289 pw.print(prefix); pw.print("minimumPasswordSymbols=");
290 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700291 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
292 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800293 pw.print(prefix); pw.print("maximumTimeToUnlock=");
294 pw.println(maximumTimeToUnlock);
295 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
296 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700297 pw.print(prefix); pw.print("specifiesGlobalProxy=");
298 pw.println(specifiesGlobalProxy);
299 if (globalProxySpec != null) {
300 pw.print(prefix); pw.print("globalProxySpec=");
301 pw.println(globalProxySpec);
302 }
303 if (globalProxyExclusionList != null) {
304 pw.print(prefix); pw.print("globalProxyEclusionList=");
305 pw.println(globalProxyExclusionList);
306 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800307 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800308 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700309
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800310 class MyPackageMonitor extends PackageMonitor {
311 public void onSomePackagesChanged() {
312 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800313 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800314 for (int i=mAdminList.size()-1; i>=0; i--) {
315 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700316 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800317 if (change == PACKAGE_PERMANENT_CHANGE
318 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700319 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800320 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800321 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800322 mAdminList.remove(i);
323 } else if (isPackageModified(aa.info.getPackageName())) {
324 try {
325 mContext.getPackageManager().getReceiverInfo(
326 aa.info.getComponent(), 0);
327 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700328 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800329 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800330 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800331 mAdminList.remove(i);
332 }
333 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800334 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800335 if (removed) {
336 validatePasswordOwnerLocked();
337 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800338 }
339 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800340 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700341
Dianne Hackbornd6847842010-01-12 18:14:19 -0800342 /**
343 * Instantiates the service.
344 */
345 public DevicePolicyManagerService(Context context) {
346 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800347 mMonitor = new MyPackageMonitor();
348 mMonitor.register(context, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700349 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
350 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800351 }
352
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800353 private IPowerManager getIPowerManager() {
354 if (mIPowerManager == null) {
355 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
356 mIPowerManager = IPowerManager.Stub.asInterface(b);
357 }
358 return mIPowerManager;
359 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700360
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800361 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800362 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800363 if (admin != null
364 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
365 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
366 return admin;
367 }
368 return null;
369 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700370
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800371 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
372 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800373 final int callingUid = Binder.getCallingUid();
374 if (who != null) {
375 ActiveAdmin admin = mAdminMap.get(who);
376 if (admin == null) {
377 throw new SecurityException("No active admin " + who);
378 }
379 if (admin.getUid() != callingUid) {
380 throw new SecurityException("Admin " + who + " is not owned by uid "
381 + Binder.getCallingUid());
382 }
383 if (!admin.info.usesPolicy(reqPolicy)) {
384 throw new SecurityException("Admin " + admin.info.getComponent()
385 + " did not specify uses-policy for: "
386 + admin.info.getTagForPolicy(reqPolicy));
387 }
388 return admin;
389 } else {
390 final int N = mAdminList.size();
391 for (int i=0; i<N; i++) {
392 ActiveAdmin admin = mAdminList.get(i);
393 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
394 return admin;
395 }
396 }
397 throw new SecurityException("No active admin owned by uid "
398 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800399 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800400 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700401
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800402 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800403 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800404 intent.setComponent(admin.info.getComponent());
Dianne Hackbornd6847842010-01-12 18:14:19 -0800405 mContext.sendBroadcast(intent);
406 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700407
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800408 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800409 final int N = mAdminList.size();
410 if (N > 0) {
411 for (int i=0; i<N; i++) {
412 ActiveAdmin admin = mAdminList.get(i);
413 if (admin.info.usesPolicy(reqPolicy)) {
414 sendAdminCommandLocked(admin, action);
415 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800416 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800417 }
418 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700419
Dianne Hackbornd6847842010-01-12 18:14:19 -0800420 void removeActiveAdminLocked(ComponentName adminReceiver) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800421 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
422 if (admin != null) {
Oscar Montemayor69238c62010-08-03 10:51:06 -0700423 boolean doProxyCleanup =
424 admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800425 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800426 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800427 // XXX need to wait for it to complete.
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800428 mAdminList.remove(admin);
429 mAdminMap.remove(adminReceiver);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800430 validatePasswordOwnerLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -0700431 if (doProxyCleanup) {
432 resetGlobalProxy();
433 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800434 }
435 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700436
Dianne Hackbornd6847842010-01-12 18:14:19 -0800437 public DeviceAdminInfo findAdmin(ComponentName adminName) {
438 Intent resolveIntent = new Intent();
439 resolveIntent.setComponent(adminName);
440 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
441 resolveIntent, PackageManager.GET_META_DATA);
442 if (infos == null || infos.size() <= 0) {
443 throw new IllegalArgumentException("Unknown admin: " + adminName);
444 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700445
Dianne Hackbornd6847842010-01-12 18:14:19 -0800446 try {
447 return new DeviceAdminInfo(mContext, infos.get(0));
448 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700449 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800450 return null;
451 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700452 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800453 return null;
454 }
455 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700456
Dianne Hackbornd6847842010-01-12 18:14:19 -0800457 private static JournaledFile makeJournaledFile() {
458 final String base = "/data/system/device_policies.xml";
459 return new JournaledFile(new File(base), new File(base + ".tmp"));
460 }
461
462 private void saveSettingsLocked() {
463 JournaledFile journal = makeJournaledFile();
464 FileOutputStream stream = null;
465 try {
466 stream = new FileOutputStream(journal.chooseForWrite(), false);
467 XmlSerializer out = new FastXmlSerializer();
468 out.setOutput(stream, "utf-8");
469 out.startDocument(null, true);
470
471 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700472
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800473 final int N = mAdminList.size();
474 for (int i=0; i<N; i++) {
475 ActiveAdmin ap = mAdminList.get(i);
476 if (ap != null) {
477 out.startTag(null, "admin");
478 out.attribute(null, "name", ap.info.getComponent().flattenToString());
479 ap.writeToXml(out);
480 out.endTag(null, "admin");
481 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800482 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700483
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800484 if (mPasswordOwner >= 0) {
485 out.startTag(null, "password-owner");
486 out.attribute(null, "value", Integer.toString(mPasswordOwner));
487 out.endTag(null, "password-owner");
488 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700489
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800490 if (mFailedPasswordAttempts != 0) {
491 out.startTag(null, "failed-password-attempts");
492 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
493 out.endTag(null, "failed-password-attempts");
494 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700495
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700496 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
497 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
498 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700499 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700500 out.startTag(null, "active-password");
501 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
502 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700503 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
504 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
505 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
506 out.attribute(null, "numeric", Integer
507 .toString(mActivePasswordNumeric));
508 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700509 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700510 out.endTag(null, "active-password");
511 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700512
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700513 out.endTag(null, "policies");
514
Dianne Hackbornd6847842010-01-12 18:14:19 -0800515 out.endDocument();
516 stream.close();
517 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700518 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800519 } catch (IOException e) {
520 try {
521 if (stream != null) {
522 stream.close();
523 }
524 } catch (IOException ex) {
525 // Ignore
526 }
527 journal.rollback();
528 }
529 }
530
Jim Miller284b62e2010-06-08 14:27:42 -0700531 private void sendChangedNotification() {
532 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
533 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
534 mContext.sendBroadcast(intent);
535 }
536
Dianne Hackbornd6847842010-01-12 18:14:19 -0800537 private void loadSettingsLocked() {
538 JournaledFile journal = makeJournaledFile();
539 FileInputStream stream = null;
540 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800541 try {
542 stream = new FileInputStream(file);
543 XmlPullParser parser = Xml.newPullParser();
544 parser.setInput(stream, null);
545
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800546 int type;
547 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
548 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800549 }
550 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800551 if (!"policies".equals(tag)) {
552 throw new XmlPullParserException(
553 "Settings do not start with policies tag: found " + tag);
554 }
555 type = parser.next();
556 int outerDepth = parser.getDepth();
557 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
558 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
559 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
560 continue;
561 }
562 tag = parser.getName();
563 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800564 String name = parser.getAttributeValue(null, "name");
565 try {
566 DeviceAdminInfo dai = findAdmin(
567 ComponentName.unflattenFromString(name));
568 if (dai != null) {
569 ActiveAdmin ap = new ActiveAdmin(dai);
570 ap.readFromXml(parser);
571 mAdminMap.put(ap.info.getComponent(), ap);
572 mAdminList.add(ap);
573 }
574 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700575 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800576 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800577 } else if ("failed-password-attempts".equals(tag)) {
578 mFailedPasswordAttempts = Integer.parseInt(
579 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800580 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800581 } else if ("password-owner".equals(tag)) {
582 mPasswordOwner = Integer.parseInt(
583 parser.getAttributeValue(null, "value"));
584 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700585 } else if ("active-password".equals(tag)) {
586 mActivePasswordQuality = Integer.parseInt(
587 parser.getAttributeValue(null, "quality"));
588 mActivePasswordLength = Integer.parseInt(
589 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700590 mActivePasswordUpperCase = Integer.parseInt(
591 parser.getAttributeValue(null, "uppercase"));
592 mActivePasswordLowerCase = Integer.parseInt(
593 parser.getAttributeValue(null, "lowercase"));
594 mActivePasswordLetters = Integer.parseInt(
595 parser.getAttributeValue(null, "letters"));
596 mActivePasswordNumeric = Integer.parseInt(
597 parser.getAttributeValue(null, "numeric"));
598 mActivePasswordSymbols = Integer.parseInt(
599 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700600 mActivePasswordNonLetter = Integer.parseInt(
601 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700602 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800603 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700604 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800605 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800606 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800607 }
608 } catch (NullPointerException 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 (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700611 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800612 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700613 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700614 } catch (FileNotFoundException e) {
615 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800616 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700617 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800618 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700619 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800620 }
621 try {
622 if (stream != null) {
623 stream.close();
624 }
625 } catch (IOException e) {
626 // Ignore
627 }
628
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700629 // Validate that what we stored for the password quality matches
630 // sufficiently what is currently set. Note that this is only
631 // a sanity check in case the two get out of sync; this should
632 // never normally happen.
633 LockPatternUtils utils = new LockPatternUtils(mContext);
634 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
635 Slog.w(TAG, "Active password quality 0x"
636 + Integer.toHexString(mActivePasswordQuality)
637 + " does not match actual quality 0x"
638 + Integer.toHexString(utils.getActivePasswordQuality()));
639 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
640 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700641 mActivePasswordUpperCase = 0;
642 mActivePasswordLowerCase = 0;
643 mActivePasswordLetters = 0;
644 mActivePasswordNumeric = 0;
645 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700646 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700647 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700648
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800649 validatePasswordOwnerLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700650
Dianne Hackborn254cb442010-01-27 19:23:59 -0800651 long timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800652 if (timeMs <= 0) {
653 timeMs = Integer.MAX_VALUE;
654 }
655 try {
656 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
657 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700658 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800659 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800660 }
661
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700662 static void validateQualityConstant(int quality) {
663 switch (quality) {
664 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
665 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
666 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
667 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
668 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700669 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700670 return;
671 }
672 throw new IllegalArgumentException("Invalid quality constant: 0x"
673 + Integer.toHexString(quality));
674 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700675
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800676 void validatePasswordOwnerLocked() {
677 if (mPasswordOwner >= 0) {
678 boolean haveOwner = false;
679 for (int i=mAdminList.size()-1; i>=0; i--) {
680 if (mAdminList.get(i).getUid() == mPasswordOwner) {
681 haveOwner = true;
682 break;
683 }
684 }
685 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700686 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800687 + " no longer active; disabling");
688 mPasswordOwner = -1;
689 }
690 }
691 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700692
Dianne Hackbornd6847842010-01-12 18:14:19 -0800693 public void systemReady() {
694 synchronized (this) {
695 loadSettingsLocked();
696 }
697 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700698
Dianne Hackbornd6847842010-01-12 18:14:19 -0800699 public void setActiveAdmin(ComponentName adminReceiver) {
700 mContext.enforceCallingOrSelfPermission(
701 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700702
Dianne Hackbornd6847842010-01-12 18:14:19 -0800703 DeviceAdminInfo info = findAdmin(adminReceiver);
704 if (info == null) {
705 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
706 }
707 synchronized (this) {
708 long ident = Binder.clearCallingIdentity();
709 try {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800710 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
711 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800712 }
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800713 ActiveAdmin admin = new ActiveAdmin(info);
714 mAdminMap.put(adminReceiver, admin);
715 mAdminList.add(admin);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800716 saveSettingsLocked();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800717 sendAdminCommandLocked(admin,
Dianne Hackbornef6b22f2010-02-16 20:38:49 -0800718 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800719 } finally {
720 Binder.restoreCallingIdentity(ident);
721 }
722 }
723 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700724
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800725 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800726 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800727 return getActiveAdminUncheckedLocked(adminReceiver) != null;
728 }
729 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700730
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800731 public List<ComponentName> getActiveAdmins() {
732 synchronized (this) {
733 final int N = mAdminList.size();
734 if (N <= 0) {
735 return null;
736 }
737 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
738 for (int i=0; i<N; i++) {
739 res.add(mAdminList.get(i).info.getComponent());
740 }
741 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800742 }
743 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700744
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800745 public boolean packageHasActiveAdmins(String packageName) {
746 synchronized (this) {
747 final int N = mAdminList.size();
748 for (int i=0; i<N; i++) {
749 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
750 return true;
751 }
752 }
753 return false;
754 }
755 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700756
Dianne Hackbornd6847842010-01-12 18:14:19 -0800757 public void removeActiveAdmin(ComponentName adminReceiver) {
758 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800759 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
760 if (admin == null) {
761 return;
762 }
763 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800764 mContext.enforceCallingOrSelfPermission(
765 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
766 }
767 long ident = Binder.clearCallingIdentity();
768 try {
769 removeActiveAdminLocked(adminReceiver);
770 } finally {
771 Binder.restoreCallingIdentity(ident);
772 }
773 }
774 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700775
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700776 public void setPasswordQuality(ComponentName who, int quality) {
777 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700778
Dianne Hackbornd6847842010-01-12 18:14:19 -0800779 synchronized (this) {
780 if (who == null) {
781 throw new NullPointerException("ComponentName is null");
782 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800783 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
784 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700785 if (ap.passwordQuality != quality) {
786 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800787 saveSettingsLocked();
788 }
789 }
790 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700791
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800792 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800793 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800794 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700795
Dianne Hackborn254cb442010-01-27 19:23:59 -0800796 if (who != null) {
797 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800798 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -0800799 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700800
Dianne Hackborn254cb442010-01-27 19:23:59 -0800801 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800802 for (int i=0; i<N; i++) {
803 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800804 if (mode < admin.passwordQuality) {
805 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800806 }
807 }
808 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800809 }
810 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700811
Dianne Hackborn254cb442010-01-27 19:23:59 -0800812 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800813 synchronized (this) {
814 if (who == null) {
815 throw new NullPointerException("ComponentName is null");
816 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800817 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
818 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800819 if (ap.minimumPasswordLength != length) {
820 ap.minimumPasswordLength = length;
821 saveSettingsLocked();
822 }
823 }
824 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700825
Dianne Hackborn254cb442010-01-27 19:23:59 -0800826 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800827 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800828 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700829
Dianne Hackborn254cb442010-01-27 19:23:59 -0800830 if (who != null) {
831 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
832 return admin != null ? admin.minimumPasswordLength : length;
833 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700834
Dianne Hackborn254cb442010-01-27 19:23:59 -0800835 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800836 for (int i=0; i<N; i++) {
837 ActiveAdmin admin = mAdminList.get(i);
838 if (length < admin.minimumPasswordLength) {
839 length = admin.minimumPasswordLength;
840 }
841 }
842 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800843 }
844 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700845
846 public void setPasswordHistoryLength(ComponentName who, int length) {
847 synchronized (this) {
848 if (who == null) {
849 throw new NullPointerException("ComponentName is null");
850 }
851 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
852 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
853 if (ap.passwordHistoryLength != length) {
854 ap.passwordHistoryLength = length;
855 saveSettingsLocked();
856 }
857 }
858 }
859
860 public int getPasswordHistoryLength(ComponentName who) {
861 synchronized (this) {
862 int length = 0;
863
864 if (who != null) {
865 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
866 return admin != null ? admin.passwordHistoryLength : length;
867 }
868
869 final int N = mAdminList.size();
870 for (int i = 0; i < N; i++) {
871 ActiveAdmin admin = mAdminList.get(i);
872 if (length < admin.passwordHistoryLength) {
873 length = admin.passwordHistoryLength;
874 }
875 }
876 return length;
877 }
878 }
879
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700880 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
881 synchronized (this) {
882 if (who == null) {
883 throw new NullPointerException("ComponentName is null");
884 }
885 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
886 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
887 if (ap.minimumPasswordUpperCase != length) {
888 ap.minimumPasswordUpperCase = length;
889 saveSettingsLocked();
890 }
891 }
892 }
893
894 public int getPasswordMinimumUpperCase(ComponentName who) {
895 synchronized (this) {
896 int length = 0;
897
898 if (who != null) {
899 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
900 return admin != null ? admin.minimumPasswordUpperCase : length;
901 }
902
903 final int N = mAdminList.size();
904 for (int i=0; i<N; i++) {
905 ActiveAdmin admin = mAdminList.get(i);
906 if (length < admin.minimumPasswordUpperCase) {
907 length = admin.minimumPasswordUpperCase;
908 }
909 }
910 return length;
911 }
912 }
913
914 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
915 synchronized (this) {
916 if (who == null) {
917 throw new NullPointerException("ComponentName is null");
918 }
919 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
920 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
921 if (ap.minimumPasswordLowerCase != length) {
922 ap.minimumPasswordLowerCase = length;
923 saveSettingsLocked();
924 }
925 }
926 }
927
928 public int getPasswordMinimumLowerCase(ComponentName who) {
929 synchronized (this) {
930 int length = 0;
931
932 if (who != null) {
933 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
934 return admin != null ? admin.minimumPasswordLowerCase : length;
935 }
936
937 final int N = mAdminList.size();
938 for (int i=0; i<N; i++) {
939 ActiveAdmin admin = mAdminList.get(i);
940 if (length < admin.minimumPasswordLowerCase) {
941 length = admin.minimumPasswordLowerCase;
942 }
943 }
944 return length;
945 }
946 }
947
948 public void setPasswordMinimumLetters(ComponentName who, int length) {
949 synchronized (this) {
950 if (who == null) {
951 throw new NullPointerException("ComponentName is null");
952 }
953 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
954 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
955 if (ap.minimumPasswordLetters != length) {
956 ap.minimumPasswordLetters = length;
957 saveSettingsLocked();
958 }
959 }
960 }
961
962 public int getPasswordMinimumLetters(ComponentName who) {
963 synchronized (this) {
964 int length = 0;
965
966 if (who != null) {
967 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
968 return admin != null ? admin.minimumPasswordLetters : length;
969 }
970
971 final int N = mAdminList.size();
972 for (int i=0; i<N; i++) {
973 ActiveAdmin admin = mAdminList.get(i);
974 if (length < admin.minimumPasswordLetters) {
975 length = admin.minimumPasswordLetters;
976 }
977 }
978 return length;
979 }
980 }
981
982 public void setPasswordMinimumNumeric(ComponentName who, int length) {
983 synchronized (this) {
984 if (who == null) {
985 throw new NullPointerException("ComponentName is null");
986 }
987 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
988 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
989 if (ap.minimumPasswordNumeric != length) {
990 ap.minimumPasswordNumeric = length;
991 saveSettingsLocked();
992 }
993 }
994 }
995
996 public int getPasswordMinimumNumeric(ComponentName who) {
997 synchronized (this) {
998 int length = 0;
999
1000 if (who != null) {
1001 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1002 return admin != null ? admin.minimumPasswordNumeric : length;
1003 }
1004
1005 final int N = mAdminList.size();
1006 for (int i = 0; i < N; i++) {
1007 ActiveAdmin admin = mAdminList.get(i);
1008 if (length < admin.minimumPasswordNumeric) {
1009 length = admin.minimumPasswordNumeric;
1010 }
1011 }
1012 return length;
1013 }
1014 }
1015
1016 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1017 synchronized (this) {
1018 if (who == null) {
1019 throw new NullPointerException("ComponentName is null");
1020 }
1021 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1022 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1023 if (ap.minimumPasswordSymbols != length) {
1024 ap.minimumPasswordSymbols = length;
1025 saveSettingsLocked();
1026 }
1027 }
1028 }
1029
1030 public int getPasswordMinimumSymbols(ComponentName who) {
1031 synchronized (this) {
1032 int length = 0;
1033
1034 if (who != null) {
1035 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1036 return admin != null ? admin.minimumPasswordSymbols : length;
1037 }
1038
1039 final int N = mAdminList.size();
1040 for (int i=0; i<N; i++) {
1041 ActiveAdmin admin = mAdminList.get(i);
1042 if (length < admin.minimumPasswordSymbols) {
1043 length = admin.minimumPasswordSymbols;
1044 }
1045 }
1046 return length;
1047 }
1048 }
1049
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001050 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1051 synchronized (this) {
1052 if (who == null) {
1053 throw new NullPointerException("ComponentName is null");
1054 }
1055 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1056 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1057 if (ap.minimumPasswordNonLetter != length) {
1058 ap.minimumPasswordNonLetter = length;
1059 saveSettingsLocked();
1060 }
1061 }
1062 }
1063
1064 public int getPasswordMinimumNonLetter(ComponentName who) {
1065 synchronized (this) {
1066 int length = 0;
1067
1068 if (who != null) {
1069 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1070 return admin != null ? admin.minimumPasswordNonLetter : length;
1071 }
1072
1073 final int N = mAdminList.size();
1074 for (int i=0; i<N; i++) {
1075 ActiveAdmin admin = mAdminList.get(i);
1076 if (length < admin.minimumPasswordNonLetter) {
1077 length = admin.minimumPasswordNonLetter;
1078 }
1079 }
1080 return length;
1081 }
1082 }
1083
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001084 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001085 synchronized (this) {
1086 // This API can only be called by an active device admin,
1087 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001088 getActiveAdminForCallerLocked(null,
1089 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001090 if (mActivePasswordQuality < getPasswordQuality(null)
1091 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1092 return false;
1093 }
1094 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1095 return true;
1096 }
1097 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1098 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1099 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1100 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001101 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1102 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001103 }
1104 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001105
Dianne Hackbornd6847842010-01-12 18:14:19 -08001106 public int getCurrentFailedPasswordAttempts() {
1107 synchronized (this) {
1108 // This API can only be called by an active device admin,
1109 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001110 getActiveAdminForCallerLocked(null,
1111 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001112 return mFailedPasswordAttempts;
1113 }
1114 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001115
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001116 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1117 synchronized (this) {
1118 // This API can only be called by an active device admin,
1119 // so try to retrieve it to check that the caller is one.
1120 getActiveAdminForCallerLocked(who,
1121 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1122 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1123 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1124 if (ap.maximumFailedPasswordsForWipe != num) {
1125 ap.maximumFailedPasswordsForWipe = num;
1126 saveSettingsLocked();
1127 }
1128 }
1129 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001130
Dianne Hackborn254cb442010-01-27 19:23:59 -08001131 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001132 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001133 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001134
Dianne Hackborn254cb442010-01-27 19:23:59 -08001135 if (who != null) {
1136 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1137 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1138 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001139
Dianne Hackborn254cb442010-01-27 19:23:59 -08001140 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001141 for (int i=0; i<N; i++) {
1142 ActiveAdmin admin = mAdminList.get(i);
1143 if (count == 0) {
1144 count = admin.maximumFailedPasswordsForWipe;
1145 } else if (admin.maximumFailedPasswordsForWipe != 0
1146 && count > admin.maximumFailedPasswordsForWipe) {
1147 count = admin.maximumFailedPasswordsForWipe;
1148 }
1149 }
1150 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001151 }
1152 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001153
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001154 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001155 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001156 synchronized (this) {
1157 // This API can only be called by an active device admin,
1158 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001159 getActiveAdminForCallerLocked(null,
1160 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001161 quality = getPasswordQuality(null);
1162 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001163 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001164 if (realQuality < quality
1165 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001166 Slog.w(TAG, "resetPassword: password quality 0x"
1167 + Integer.toHexString(quality)
1168 + " does not meet required quality 0x"
1169 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001170 return false;
1171 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001172 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001173 }
1174 int length = getPasswordMinimumLength(null);
1175 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001176 Slog.w(TAG, "resetPassword: password length " + password.length()
1177 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001178 return false;
1179 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001180 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1181 int letters = 0;
1182 int uppercase = 0;
1183 int lowercase = 0;
1184 int numbers = 0;
1185 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001186 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001187 for (int i = 0; i < password.length(); i++) {
1188 char c = password.charAt(i);
1189 if (c >= 'A' && c <= 'Z') {
1190 letters++;
1191 uppercase++;
1192 } else if (c >= 'a' && c <= 'z') {
1193 letters++;
1194 lowercase++;
1195 } else if (c >= '0' && c <= '9') {
1196 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001197 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001198 } else {
1199 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001200 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001201 }
1202 }
1203 int neededLetters = getPasswordMinimumLetters(null);
1204 if(letters < neededLetters) {
1205 Slog.w(TAG, "resetPassword: number of letters " + letters
1206 + " does not meet required number of letters " + neededLetters);
1207 return false;
1208 }
1209 int neededNumbers = getPasswordMinimumNumeric(null);
1210 if (numbers < neededNumbers) {
1211 Slog
1212 .w(TAG, "resetPassword: number of numerical digits " + numbers
1213 + " does not meet required number of numerical digits "
1214 + neededNumbers);
1215 return false;
1216 }
1217 int neededLowerCase = getPasswordMinimumLowerCase(null);
1218 if (lowercase < neededLowerCase) {
1219 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1220 + " does not meet required number of lowercase letters "
1221 + neededLowerCase);
1222 return false;
1223 }
1224 int neededUpperCase = getPasswordMinimumUpperCase(null);
1225 if (uppercase < neededUpperCase) {
1226 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1227 + " does not meet required number of uppercase letters "
1228 + neededUpperCase);
1229 return false;
1230 }
1231 int neededSymbols = getPasswordMinimumSymbols(null);
1232 if (symbols < neededSymbols) {
1233 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1234 + " does not meet required number of special symbols " + neededSymbols);
1235 return false;
1236 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001237 int neededNonLetter = getPasswordMinimumNonLetter(null);
1238 if (nonletter < neededNonLetter) {
1239 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1240 + " does not meet required number of non-letter characters "
1241 + neededNonLetter);
1242 return false;
1243 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001244 }
1245
1246 LockPatternUtils utils = new LockPatternUtils(mContext);
1247 if(utils.checkPasswordHistory(password)) {
1248 Slog.w(TAG, "resetPassword: password is the same as one of the last "
1249 + getPasswordHistoryLength(null) + " passwords");
1250 return false;
1251 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001252 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001253
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001254 int callingUid = Binder.getCallingUid();
1255 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001256 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001257 return false;
1258 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001259
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001260 // Don't do this with the lock held, because it is going to call
1261 // back in to the service.
1262 long ident = Binder.clearCallingIdentity();
1263 try {
1264 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001265 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001266 synchronized (this) {
1267 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1268 != 0 ? callingUid : -1;
1269 if (mPasswordOwner != newOwner) {
1270 mPasswordOwner = newOwner;
1271 saveSettingsLocked();
1272 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001273 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001274 } finally {
1275 Binder.restoreCallingIdentity(ident);
1276 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001277
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001278 return true;
1279 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001280
Dianne Hackbornd6847842010-01-12 18:14:19 -08001281 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1282 synchronized (this) {
1283 if (who == null) {
1284 throw new NullPointerException("ComponentName is null");
1285 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001286 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001287 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001288 if (ap.maximumTimeToUnlock != timeMs) {
1289 ap.maximumTimeToUnlock = timeMs;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001290
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001291 long ident = Binder.clearCallingIdentity();
1292 try {
1293 saveSettingsLocked();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001294
Dianne Hackborn254cb442010-01-27 19:23:59 -08001295 timeMs = getMaximumTimeToLock(null);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001296 if (timeMs <= 0) {
1297 timeMs = Integer.MAX_VALUE;
1298 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001299
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001300 try {
1301 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1302 } catch (RemoteException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001303 Slog.w(TAG, "Failure talking with power manager", e);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001304 }
1305 } finally {
1306 Binder.restoreCallingIdentity(ident);
1307 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001308 }
1309 }
1310 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001311
Dianne Hackborn254cb442010-01-27 19:23:59 -08001312 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001313 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001314 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001315
Dianne Hackborn254cb442010-01-27 19:23:59 -08001316 if (who != null) {
1317 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1318 return admin != null ? admin.maximumTimeToUnlock : time;
1319 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001320
Dianne Hackborn254cb442010-01-27 19:23:59 -08001321 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001322 for (int i=0; i<N; i++) {
1323 ActiveAdmin admin = mAdminList.get(i);
1324 if (time == 0) {
1325 time = admin.maximumTimeToUnlock;
1326 } else if (admin.maximumTimeToUnlock != 0
1327 && time > admin.maximumTimeToUnlock) {
1328 time = admin.maximumTimeToUnlock;
1329 }
1330 }
1331 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001332 }
1333 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001334
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001335 public void lockNow() {
1336 synchronized (this) {
1337 // This API can only be called by an active device admin,
1338 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001339 getActiveAdminForCallerLocked(null,
1340 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001341 long ident = Binder.clearCallingIdentity();
1342 try {
1343 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1344 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1345 } catch (RemoteException e) {
1346 } finally {
1347 Binder.restoreCallingIdentity(ident);
1348 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001349 }
1350 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001351
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001352 void wipeDataLocked(int flags) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001353 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
1354 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1355 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1356 mWakeLock.acquire(10000);
1357 mContext.startService(intent);
1358 } else {
1359 try {
1360 RecoverySystem.rebootWipeUserData(mContext);
1361 } catch (IOException e) {
1362 Slog.w(TAG, "Failed requesting data wipe", e);
1363 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001364 }
1365 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001366
Dianne Hackbornd6847842010-01-12 18:14:19 -08001367 public void wipeData(int flags) {
1368 synchronized (this) {
1369 // This API can only be called by an active device admin,
1370 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001371 getActiveAdminForCallerLocked(null,
1372 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001373 long ident = Binder.clearCallingIdentity();
1374 try {
1375 wipeDataLocked(flags);
1376 } finally {
1377 Binder.restoreCallingIdentity(ident);
1378 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001379 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001380 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001381
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001382 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1383 mContext.enforceCallingOrSelfPermission(
1384 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001385
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001386 synchronized (this) {
1387 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1388 if (admin == null) {
1389 try {
1390 result.sendResult(null);
1391 } catch (RemoteException e) {
1392 }
1393 return;
1394 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001395 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001396 intent.setComponent(admin.info.getComponent());
1397 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1398 @Override
1399 public void onReceive(Context context, Intent intent) {
1400 try {
1401 result.sendResult(getResultExtras(false));
1402 } catch (RemoteException e) {
1403 }
1404 }
1405 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001406 }
1407 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001408
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001409 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001410 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001411 mContext.enforceCallingOrSelfPermission(
1412 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001413
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001414 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001415
Dianne Hackbornd6847842010-01-12 18:14:19 -08001416 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001417 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001418 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1419 || mActivePasswordUpperCase != uppercase
1420 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001421 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001422 long ident = Binder.clearCallingIdentity();
1423 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001424 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001425 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001426 mActivePasswordLetters = letters;
1427 mActivePasswordLowerCase = lowercase;
1428 mActivePasswordUpperCase = uppercase;
1429 mActivePasswordNumeric = numbers;
1430 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001431 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001432 mFailedPasswordAttempts = 0;
1433 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001434 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001435 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001436 } finally {
1437 Binder.restoreCallingIdentity(ident);
1438 }
1439 }
1440 }
1441 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001442
Dianne Hackbornd6847842010-01-12 18:14:19 -08001443 public void reportFailedPasswordAttempt() {
1444 mContext.enforceCallingOrSelfPermission(
1445 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001446
Dianne Hackbornd6847842010-01-12 18:14:19 -08001447 synchronized (this) {
1448 long ident = Binder.clearCallingIdentity();
1449 try {
1450 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001451 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001452 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001453 if (max > 0 && mFailedPasswordAttempts >= max) {
1454 wipeDataLocked(0);
1455 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001456 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001457 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001458 } finally {
1459 Binder.restoreCallingIdentity(ident);
1460 }
1461 }
1462 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001463
Dianne Hackbornd6847842010-01-12 18:14:19 -08001464 public void reportSuccessfulPasswordAttempt() {
1465 mContext.enforceCallingOrSelfPermission(
1466 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001467
Dianne Hackbornd6847842010-01-12 18:14:19 -08001468 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001469 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001470 long ident = Binder.clearCallingIdentity();
1471 try {
1472 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001473 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001474 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001475 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001476 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001477 } finally {
1478 Binder.restoreCallingIdentity(ident);
1479 }
1480 }
1481 }
1482 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001483
Oscar Montemayor69238c62010-08-03 10:51:06 -07001484 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1485 String exclusionList) {
1486 synchronized(this) {
1487 if (who == null) {
1488 throw new NullPointerException("ComponentName is null");
1489 }
1490
1491 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1492 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1493
1494 // Scan through active admins and find if anyone has already
1495 // set the global proxy.
1496 final int N = mAdminList.size();
1497 Set<ComponentName> compSet = mAdminMap.keySet();
1498 for (ComponentName component : compSet) {
1499 ActiveAdmin ap = mAdminMap.get(component);
1500 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1501 // Another admin already sets the global proxy
1502 // Return it to the caller.
1503 return component;
1504 }
1505 }
1506 if (proxySpec == null) {
1507 admin.specifiesGlobalProxy = false;
1508 admin.globalProxySpec = null;
1509 admin.globalProxyExclusionList = null;
1510 } else {
1511
1512 admin.specifiesGlobalProxy = true;
1513 admin.globalProxySpec = proxySpec;
1514 admin.globalProxyExclusionList = exclusionList;
1515 }
1516
1517 // Reset the global proxy accordingly
1518 // Do this using system permissions, as apps cannot write to secure settings
1519 long origId = Binder.clearCallingIdentity();
1520 resetGlobalProxy();
1521 Binder.restoreCallingIdentity(origId);
1522 return null;
1523 }
1524 }
1525
1526 public ComponentName getGlobalProxyAdmin() {
1527 synchronized(this) {
1528 // Scan through active admins and find if anyone has already
1529 // set the global proxy.
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 // Device admin sets the global proxy
1535 // Return it to the caller.
1536 return ap.info.getComponent();
1537 }
1538 }
1539 }
1540 // No device admin sets the global proxy.
1541 return null;
1542 }
1543
1544 private void resetGlobalProxy() {
1545 final int N = mAdminList.size();
1546 for (int i = 0; i < N; i++) {
1547 ActiveAdmin ap = mAdminList.get(i);
1548 if (ap.specifiesGlobalProxy) {
1549 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1550 return;
1551 }
1552 }
1553 // No device admins defining global proxies - reset global proxy settings to none
1554 saveGlobalProxy(null, null);
1555 }
1556
1557 private void saveGlobalProxy(String proxySpec, String exclusionList) {
1558 if (exclusionList == null) {
1559 exclusionList = "";
1560 }
1561 if (proxySpec == null) {
1562 proxySpec = "";
1563 }
1564 // Remove white spaces
1565 proxySpec = proxySpec.trim();
1566 exclusionList = exclusionList.trim();
1567 ContentResolver res = mContext.getContentResolver();
1568 Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY, proxySpec);
1569 Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY_EXCLUSION_LIST, exclusionList);
1570 }
1571
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001572 @Override
1573 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1574 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1575 != PackageManager.PERMISSION_GRANTED) {
1576
1577 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1578 + Binder.getCallingPid()
1579 + ", uid=" + Binder.getCallingUid());
1580 return;
1581 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001582
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001583 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001584
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001585 synchronized (this) {
1586 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001587
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001588 p.println(" Enabled Device Admins:");
1589 final int N = mAdminList.size();
1590 for (int i=0; i<N; i++) {
1591 ActiveAdmin ap = mAdminList.get(i);
1592 if (ap != null) {
1593 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
1594 pw.println(":");
1595 ap.dump(" ", pw);
1596 }
1597 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001598
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001599 pw.println(" ");
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001600 pw.print(" mActivePasswordQuality=0x");
1601 pw.println(Integer.toHexString(mActivePasswordQuality));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001602 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001603 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1604 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1605 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1606 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1607 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001608 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001609 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1610 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
1611 }
1612 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001613}