blob: 77b062c2d389c64874c5997960b427b7de14ae4e [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;
Jim Millera4e28d12010-11-08 16:15:47 -080031import android.app.AlarmManager;
32import android.app.PendingIntent;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080033import android.app.admin.DeviceAdminInfo;
34import android.app.admin.DeviceAdminReceiver;
35import android.app.admin.DevicePolicyManager;
36import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080037import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080038import android.content.ComponentName;
Oscar Montemayor69238c62010-08-03 10:51:06 -070039import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080040import android.content.Context;
41import android.content.Intent;
Jim Millera4e28d12010-11-08 16:15:47 -080042import android.content.IntentFilter;
Dianne Hackbornd6847842010-01-12 18:14:19 -080043import android.content.pm.PackageManager;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080044import android.content.pm.PackageManager.NameNotFoundException;
Andy Stadler1f35d482010-11-19 15:39:41 -080045import android.content.pm.ResolveInfo;
Dianne Hackbornd6847842010-01-12 18:14:19 -080046import android.os.Binder;
Ben Komaloed48c8b2011-10-17 17:30:21 -070047import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080048import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080049import android.os.IBinder;
50import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070051import android.os.PowerManager;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080052import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080053import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080054import android.os.RemoteException;
55import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080056import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080057import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070058import android.os.UserHandle;
Oscar Montemayor69238c62010-08-03 10:51:06 -070059import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080060import android.util.PrintWriterPrinter;
61import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080062import android.util.Slog;
Dianne Hackbornd6847842010-01-12 18:14:19 -080063import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080064import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080065import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080066
67import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080068import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080069import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070070import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080071import java.io.FileOutputStream;
72import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080073import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080074import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080075import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080076import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080077import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080078import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070079import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080080
81/**
82 * Implementation of the device policy APIs.
83 */
84public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Jim Miller6b857682011-02-16 16:27:41 -080085 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080086
Jim Miller6b857682011-02-16 16:27:41 -080087 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070088
Jim Millera4e28d12010-11-08 16:15:47 -080089 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
90
91 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
92 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
93
94 private static final long MS_PER_DAY = 86400 * 1000;
Jim Millera4e28d12010-11-08 16:15:47 -080095
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080096 final Context mContext;
97 final MyPackageMonitor mMonitor;
Dianne Hackborn42499172010-10-15 18:45:07 -070098 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -080099
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800100 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800101 IWindowManager mIWindowManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700102
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800103 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800104 int mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700105 int mActivePasswordUpperCase = 0;
106 int mActivePasswordLowerCase = 0;
107 int mActivePasswordLetters = 0;
108 int mActivePasswordNumeric = 0;
109 int mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700110 int mActivePasswordNonLetter = 0;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800111 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700112
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800113 int mPasswordOwner = -1;
Jim Millera4e28d12010-11-08 16:15:47 -0800114 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700115
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700116 long mLastMaximumTimeToLock = -1;
117
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800118 final HashMap<ComponentName, ActiveAdmin> mAdminMap
119 = new HashMap<ComponentName, ActiveAdmin>();
120 final ArrayList<ActiveAdmin> mAdminList
121 = new ArrayList<ActiveAdmin>();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700122
Jim Millera4e28d12010-11-08 16:15:47 -0800123 BroadcastReceiver mReceiver = new BroadcastReceiver() {
124 @Override
125 public void onReceive(Context context, Intent intent) {
126 String action = intent.getAction();
127 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
128 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
129 Slog.v(TAG, "Sending password expiration notifications for action " + action);
130 mHandler.post(new Runnable() {
131 public void run() {
132 handlePasswordExpirationNotification();
133 }
134 });
135 }
136 }
137 };
138
Dianne Hackbornd6847842010-01-12 18:14:19 -0800139 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800140 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700141
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800142 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700143
144 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
145 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
146
147 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
148 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
149
150 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
151 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
152
153 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
154 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
155
156 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700157 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700158
159 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
160 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
161
162 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
163 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
164
165 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
166 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
167
168 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
169 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
170
171 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
172 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
173
174 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
175 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
176
177 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
178 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
179
Andy Stadler22dbfda2011-01-17 12:47:31 -0800180 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700181 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700182
Oscar Montemayor69238c62010-08-03 10:51:06 -0700183 // TODO: review implementation decisions with frameworks team
184 boolean specifiesGlobalProxy = false;
185 String globalProxySpec = null;
186 String globalProxyExclusionList = null;
187
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800188 ActiveAdmin(DeviceAdminInfo _info) {
189 info = _info;
190 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700191
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800192 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700193
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800194 void writeToXml(XmlSerializer out)
195 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800196 out.startTag(null, "policies");
197 info.writePoliciesToXml(out);
198 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800199 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
200 out.startTag(null, "password-quality");
201 out.attribute(null, "value", Integer.toString(passwordQuality));
202 out.endTag(null, "password-quality");
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700203 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800204 out.startTag(null, "min-password-length");
205 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700206 out.endTag(null, "min-password-length");
207 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700208 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700209 out.startTag(null, "password-history-length");
210 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
211 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800212 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700213 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700214 out.startTag(null, "min-password-uppercase");
215 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
216 out.endTag(null, "min-password-uppercase");
217 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700218 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700219 out.startTag(null, "min-password-lowercase");
220 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
221 out.endTag(null, "min-password-lowercase");
222 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700223 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700224 out.startTag(null, "min-password-letters");
225 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
226 out.endTag(null, "min-password-letters");
227 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700228 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700229 out.startTag(null, "min-password-numeric");
230 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
231 out.endTag(null, "min-password-numeric");
232 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700233 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700234 out.startTag(null, "min-password-symbols");
235 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
236 out.endTag(null, "min-password-symbols");
237 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700238 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700239 out.startTag(null, "min-password-nonletter");
240 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
241 out.endTag(null, "min-password-nonletter");
242 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800243 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700244 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800245 out.startTag(null, "max-time-to-unlock");
246 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
247 out.endTag(null, "max-time-to-unlock");
248 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700249 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800250 out.startTag(null, "max-failed-password-wipe");
251 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
252 out.endTag(null, "max-failed-password-wipe");
253 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700254 if (specifiesGlobalProxy) {
255 out.startTag(null, "specifies-global-proxy");
256 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
257 out.endTag(null, "specifies_global_proxy");
258 if (globalProxySpec != null) {
259 out.startTag(null, "global-proxy-spec");
260 out.attribute(null, "value", globalProxySpec);
261 out.endTag(null, "global-proxy-spec");
262 }
263 if (globalProxyExclusionList != null) {
264 out.startTag(null, "global-proxy-exclusion-list");
265 out.attribute(null, "value", globalProxyExclusionList);
266 out.endTag(null, "global-proxy-exclusion-list");
267 }
268 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700269 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800270 out.startTag(null, "password-expiration-timeout");
271 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
272 out.endTag(null, "password-expiration-timeout");
273 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700274 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800275 out.startTag(null, "password-expiration-date");
276 out.attribute(null, "value", Long.toString(passwordExpirationDate));
277 out.endTag(null, "password-expiration-date");
278 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800279 if (encryptionRequested) {
280 out.startTag(null, "encryption-requested");
281 out.attribute(null, "value", Boolean.toString(encryptionRequested));
282 out.endTag(null, "encryption-requested");
283 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700284 if (disableCamera) {
285 out.startTag(null, "disable-camera");
286 out.attribute(null, "value", Boolean.toString(disableCamera));
287 out.endTag(null, "disable-camera");
288 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800289 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700290
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800291 void readFromXml(XmlPullParser parser)
292 throws XmlPullParserException, IOException {
293 int outerDepth = parser.getDepth();
294 int type;
295 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
296 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
297 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
298 continue;
299 }
300 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800301 if ("policies".equals(tag)) {
302 info.readPoliciesFromXml(parser);
303 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800304 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800305 parser.getAttributeValue(null, "value"));
306 } else if ("min-password-length".equals(tag)) {
307 minimumPasswordLength = Integer.parseInt(
308 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700309 } else if ("password-history-length".equals(tag)) {
310 passwordHistoryLength = Integer.parseInt(
311 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700312 } else if ("min-password-uppercase".equals(tag)) {
313 minimumPasswordUpperCase = Integer.parseInt(
314 parser.getAttributeValue(null, "value"));
315 } else if ("min-password-lowercase".equals(tag)) {
316 minimumPasswordLowerCase = Integer.parseInt(
317 parser.getAttributeValue(null, "value"));
318 } else if ("min-password-letters".equals(tag)) {
319 minimumPasswordLetters = Integer.parseInt(
320 parser.getAttributeValue(null, "value"));
321 } else if ("min-password-numeric".equals(tag)) {
322 minimumPasswordNumeric = Integer.parseInt(
323 parser.getAttributeValue(null, "value"));
324 } else if ("min-password-symbols".equals(tag)) {
325 minimumPasswordSymbols = Integer.parseInt(
326 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700327 } else if ("min-password-nonletter".equals(tag)) {
328 minimumPasswordNonLetter = Integer.parseInt(
329 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800330 } else if ("max-time-to-unlock".equals(tag)) {
331 maximumTimeToUnlock = Long.parseLong(
332 parser.getAttributeValue(null, "value"));
333 } else if ("max-failed-password-wipe".equals(tag)) {
334 maximumFailedPasswordsForWipe = Integer.parseInt(
335 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700336 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800337 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700338 parser.getAttributeValue(null, "value"));
339 } else if ("global-proxy-spec".equals(tag)) {
340 globalProxySpec =
341 parser.getAttributeValue(null, "value");
342 } else if ("global-proxy-exclusion-list".equals(tag)) {
343 globalProxyExclusionList =
344 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800345 } else if ("password-expiration-timeout".equals(tag)) {
346 passwordExpirationTimeout = Long.parseLong(
347 parser.getAttributeValue(null, "value"));
348 } else if ("password-expiration-date".equals(tag)) {
349 passwordExpirationDate = Long.parseLong(
350 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800351 } else if ("encryption-requested".equals(tag)) {
352 encryptionRequested = Boolean.parseBoolean(
353 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700354 } else if ("disable-camera".equals(tag)) {
355 disableCamera = Boolean.parseBoolean(
356 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800357 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700358 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800359 }
360 XmlUtils.skipCurrentTag(parser);
361 }
362 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700363
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800364 void dump(String prefix, PrintWriter pw) {
365 pw.print(prefix); pw.print("uid="); pw.println(getUid());
366 pw.print(prefix); pw.println("policies:");
367 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
368 if (pols != null) {
369 for (int i=0; i<pols.size(); i++) {
370 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
371 }
372 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700373 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700374 pw.println(Integer.toHexString(passwordQuality));
375 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800376 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700377 pw.print(prefix); pw.print("passwordHistoryLength=");
378 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700379 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
380 pw.println(minimumPasswordUpperCase);
381 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
382 pw.println(minimumPasswordLowerCase);
383 pw.print(prefix); pw.print("minimumPasswordLetters=");
384 pw.println(minimumPasswordLetters);
385 pw.print(prefix); pw.print("minimumPasswordNumeric=");
386 pw.println(minimumPasswordNumeric);
387 pw.print(prefix); pw.print("minimumPasswordSymbols=");
388 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700389 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
390 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800391 pw.print(prefix); pw.print("maximumTimeToUnlock=");
392 pw.println(maximumTimeToUnlock);
393 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
394 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700395 pw.print(prefix); pw.print("specifiesGlobalProxy=");
396 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800397 pw.print(prefix); pw.print("passwordExpirationTimeout=");
398 pw.println(passwordExpirationTimeout);
399 pw.print(prefix); pw.print("passwordExpirationDate=");
400 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700401 if (globalProxySpec != null) {
402 pw.print(prefix); pw.print("globalProxySpec=");
403 pw.println(globalProxySpec);
404 }
405 if (globalProxyExclusionList != null) {
406 pw.print(prefix); pw.print("globalProxyEclusionList=");
407 pw.println(globalProxyExclusionList);
408 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800409 pw.print(prefix); pw.print("encryptionRequested=");
410 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700411 pw.print(prefix); pw.print("disableCamera=");
412 pw.println(disableCamera);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800413 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800414 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700415
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800416 class MyPackageMonitor extends PackageMonitor {
Andy Stadler1f35d482010-11-19 15:39:41 -0800417 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800418 public void onSomePackagesChanged() {
419 synchronized (DevicePolicyManagerService.this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800420 boolean removed = false;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800421 for (int i=mAdminList.size()-1; i>=0; i--) {
422 ActiveAdmin aa = mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700423 int change = isPackageDisappearing(aa.info.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800424 if (change == PACKAGE_PERMANENT_CHANGE
425 || change == PACKAGE_TEMPORARY_CHANGE) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700426 Slog.w(TAG, "Admin unexpectedly uninstalled: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800427 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800428 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800429 mAdminList.remove(i);
430 } else if (isPackageModified(aa.info.getPackageName())) {
431 try {
432 mContext.getPackageManager().getReceiverInfo(
433 aa.info.getComponent(), 0);
434 } catch (NameNotFoundException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700435 Slog.w(TAG, "Admin package change removed component: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800436 + aa.info.getComponent());
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800437 removed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800438 mAdminList.remove(i);
439 }
440 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800441 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800442 if (removed) {
443 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700444 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700445 saveSettingsLocked();
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800446 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800447 }
448 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800449 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700450
Dianne Hackbornd6847842010-01-12 18:14:19 -0800451 /**
452 * Instantiates the service.
453 */
454 public DevicePolicyManagerService(Context context) {
455 mContext = context;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800456 mMonitor = new MyPackageMonitor();
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700457 mMonitor.register(context, null, true);
Dianne Hackborn42499172010-10-15 18:45:07 -0700458 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
459 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800460 IntentFilter filter = new IntentFilter();
461 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
462 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
463 context.registerReceiver(mReceiver, filter);
464 }
465
Andy Stadler043116a2010-11-29 17:43:32 -0800466 /**
467 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
468 * reminders. Clears alarm if no expirations are configured.
469 */
Jim Millera4e28d12010-11-08 16:15:47 -0800470 protected void setExpirationAlarmCheckLocked(Context context) {
471 final long expiration = getPasswordExpirationLocked(null);
472 final long now = System.currentTimeMillis();
473 final long timeToExpire = expiration - now;
474 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800475 if (expiration == 0) {
476 // No expirations are currently configured: Cancel alarm.
477 alarmTime = 0;
478 } else if (timeToExpire <= 0) {
479 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800480 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800481 } else {
482 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
483 // the expiration time.
484 long alarmInterval = timeToExpire % MS_PER_DAY;
485 if (alarmInterval == 0) {
486 alarmInterval = MS_PER_DAY;
487 }
488 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800489 }
490
Andy Stadler1f35d482010-11-19 15:39:41 -0800491 long token = Binder.clearCallingIdentity();
492 try {
493 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
494 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
495 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
496 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
497 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800498 if (alarmTime != 0) {
499 am.set(AlarmManager.RTC, alarmTime, pi);
500 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800501 } finally {
502 Binder.restoreCallingIdentity(token);
503 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800504 }
505
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800506 private IPowerManager getIPowerManager() {
507 if (mIPowerManager == null) {
508 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
509 mIPowerManager = IPowerManager.Stub.asInterface(b);
510 }
511 return mIPowerManager;
512 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700513
Jim Miller93c518e2012-01-17 15:55:31 -0800514 private IWindowManager getWindowManager() {
515 if (mIWindowManager == null) {
516 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
517 mIWindowManager = IWindowManager.Stub.asInterface(b);
518 }
519 return mIWindowManager;
520 }
521
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800522 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800523 ActiveAdmin admin = mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800524 if (admin != null
525 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
526 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
527 return admin;
528 }
529 return null;
530 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700531
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800532 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
533 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800534 final int callingUid = Binder.getCallingUid();
535 if (who != null) {
536 ActiveAdmin admin = mAdminMap.get(who);
537 if (admin == null) {
538 throw new SecurityException("No active admin " + who);
539 }
540 if (admin.getUid() != callingUid) {
541 throw new SecurityException("Admin " + who + " is not owned by uid "
542 + Binder.getCallingUid());
543 }
544 if (!admin.info.usesPolicy(reqPolicy)) {
545 throw new SecurityException("Admin " + admin.info.getComponent()
546 + " did not specify uses-policy for: "
547 + admin.info.getTagForPolicy(reqPolicy));
548 }
549 return admin;
550 } else {
551 final int N = mAdminList.size();
552 for (int i=0; i<N; i++) {
553 ActiveAdmin admin = mAdminList.get(i);
554 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
555 return admin;
556 }
557 }
558 throw new SecurityException("No active admin owned by uid "
559 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800560 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800561 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700562
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800563 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700564 sendAdminCommandLocked(admin, action, null);
565 }
566
567 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800568 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800569 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800570 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
571 intent.putExtra("expiration", admin.passwordExpirationDate);
572 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700573 if (result != null) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700574 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
575 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700576 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700577 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700578 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800579 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700580
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800581 void sendAdminCommandLocked(String action, int reqPolicy) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800582 final int N = mAdminList.size();
583 if (N > 0) {
584 for (int i=0; i<N; i++) {
585 ActiveAdmin admin = mAdminList.get(i);
586 if (admin.info.usesPolicy(reqPolicy)) {
587 sendAdminCommandLocked(admin, action);
588 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800589 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800590 }
591 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700592
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700593 void removeActiveAdminLocked(final ComponentName adminReceiver) {
594 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800595 if (admin != null) {
596 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700597 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
598 new BroadcastReceiver() {
599 @Override
600 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700601 synchronized (DevicePolicyManagerService.this) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700602 boolean doProxyCleanup = admin.info.usesPolicy(
603 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
604 mAdminList.remove(admin);
605 mAdminMap.remove(adminReceiver);
606 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700607 syncDeviceCapabilitiesLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700608 if (doProxyCleanup) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700609 resetGlobalProxyLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700610 }
611 saveSettingsLocked();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700612 updateMaximumTimeToLockLocked();
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700613 }
614 }
615 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800616 }
617 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700618
Dianne Hackbornd6847842010-01-12 18:14:19 -0800619 public DeviceAdminInfo findAdmin(ComponentName adminName) {
620 Intent resolveIntent = new Intent();
621 resolveIntent.setComponent(adminName);
622 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
623 resolveIntent, PackageManager.GET_META_DATA);
624 if (infos == null || infos.size() <= 0) {
625 throw new IllegalArgumentException("Unknown admin: " + adminName);
626 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700627
Dianne Hackbornd6847842010-01-12 18:14:19 -0800628 try {
629 return new DeviceAdminInfo(mContext, infos.get(0));
630 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700631 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800632 return null;
633 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700634 Slog.w(TAG, "Bad device admin requested: " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800635 return null;
636 }
637 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700638
Dianne Hackbornd6847842010-01-12 18:14:19 -0800639 private static JournaledFile makeJournaledFile() {
640 final String base = "/data/system/device_policies.xml";
641 return new JournaledFile(new File(base), new File(base + ".tmp"));
642 }
643
644 private void saveSettingsLocked() {
645 JournaledFile journal = makeJournaledFile();
646 FileOutputStream stream = null;
647 try {
648 stream = new FileOutputStream(journal.chooseForWrite(), false);
649 XmlSerializer out = new FastXmlSerializer();
650 out.setOutput(stream, "utf-8");
651 out.startDocument(null, true);
652
653 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700654
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800655 final int N = mAdminList.size();
656 for (int i=0; i<N; i++) {
657 ActiveAdmin ap = mAdminList.get(i);
658 if (ap != null) {
659 out.startTag(null, "admin");
660 out.attribute(null, "name", ap.info.getComponent().flattenToString());
661 ap.writeToXml(out);
662 out.endTag(null, "admin");
663 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800664 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700665
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800666 if (mPasswordOwner >= 0) {
667 out.startTag(null, "password-owner");
668 out.attribute(null, "value", Integer.toString(mPasswordOwner));
669 out.endTag(null, "password-owner");
670 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700671
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800672 if (mFailedPasswordAttempts != 0) {
673 out.startTag(null, "failed-password-attempts");
674 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
675 out.endTag(null, "failed-password-attempts");
676 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700677
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700678 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
679 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
680 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700681 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700682 out.startTag(null, "active-password");
683 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
684 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700685 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
686 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
687 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
688 out.attribute(null, "numeric", Integer
689 .toString(mActivePasswordNumeric));
690 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700691 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700692 out.endTag(null, "active-password");
693 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700694
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700695 out.endTag(null, "policies");
696
Dianne Hackbornd6847842010-01-12 18:14:19 -0800697 out.endDocument();
698 stream.close();
699 journal.commit();
Jim Miller284b62e2010-06-08 14:27:42 -0700700 sendChangedNotification();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800701 } catch (IOException e) {
702 try {
703 if (stream != null) {
704 stream.close();
705 }
706 } catch (IOException ex) {
707 // Ignore
708 }
709 journal.rollback();
710 }
711 }
712
Jim Miller284b62e2010-06-08 14:27:42 -0700713 private void sendChangedNotification() {
714 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
715 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700716 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Jim Miller284b62e2010-06-08 14:27:42 -0700717 }
718
Dianne Hackbornd6847842010-01-12 18:14:19 -0800719 private void loadSettingsLocked() {
720 JournaledFile journal = makeJournaledFile();
721 FileInputStream stream = null;
722 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800723 try {
724 stream = new FileInputStream(file);
725 XmlPullParser parser = Xml.newPullParser();
726 parser.setInput(stream, null);
727
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800728 int type;
729 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
730 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800731 }
732 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800733 if (!"policies".equals(tag)) {
734 throw new XmlPullParserException(
735 "Settings do not start with policies tag: found " + tag);
736 }
737 type = parser.next();
738 int outerDepth = parser.getDepth();
739 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
740 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
741 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
742 continue;
743 }
744 tag = parser.getName();
745 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800746 String name = parser.getAttributeValue(null, "name");
747 try {
748 DeviceAdminInfo dai = findAdmin(
749 ComponentName.unflattenFromString(name));
750 if (dai != null) {
751 ActiveAdmin ap = new ActiveAdmin(dai);
752 ap.readFromXml(parser);
753 mAdminMap.put(ap.info.getComponent(), ap);
754 mAdminList.add(ap);
755 }
756 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700757 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800758 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800759 } else if ("failed-password-attempts".equals(tag)) {
760 mFailedPasswordAttempts = Integer.parseInt(
761 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800762 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800763 } else if ("password-owner".equals(tag)) {
764 mPasswordOwner = Integer.parseInt(
765 parser.getAttributeValue(null, "value"));
766 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700767 } else if ("active-password".equals(tag)) {
768 mActivePasswordQuality = Integer.parseInt(
769 parser.getAttributeValue(null, "quality"));
770 mActivePasswordLength = Integer.parseInt(
771 parser.getAttributeValue(null, "length"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700772 mActivePasswordUpperCase = Integer.parseInt(
773 parser.getAttributeValue(null, "uppercase"));
774 mActivePasswordLowerCase = Integer.parseInt(
775 parser.getAttributeValue(null, "lowercase"));
776 mActivePasswordLetters = Integer.parseInt(
777 parser.getAttributeValue(null, "letters"));
778 mActivePasswordNumeric = Integer.parseInt(
779 parser.getAttributeValue(null, "numeric"));
780 mActivePasswordSymbols = Integer.parseInt(
781 parser.getAttributeValue(null, "symbols"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700782 mActivePasswordNonLetter = Integer.parseInt(
783 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700784 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800785 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700786 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800787 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800788 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800789 }
790 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700791 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800792 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700793 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800794 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700795 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700796 } catch (FileNotFoundException e) {
797 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800798 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700799 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800800 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700801 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800802 }
803 try {
804 if (stream != null) {
805 stream.close();
806 }
807 } catch (IOException e) {
808 // Ignore
809 }
810
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700811 // Validate that what we stored for the password quality matches
812 // sufficiently what is currently set. Note that this is only
813 // a sanity check in case the two get out of sync; this should
814 // never normally happen.
815 LockPatternUtils utils = new LockPatternUtils(mContext);
816 if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
817 Slog.w(TAG, "Active password quality 0x"
818 + Integer.toHexString(mActivePasswordQuality)
819 + " does not match actual quality 0x"
820 + Integer.toHexString(utils.getActivePasswordQuality()));
821 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
822 mActivePasswordLength = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700823 mActivePasswordUpperCase = 0;
824 mActivePasswordLowerCase = 0;
825 mActivePasswordLetters = 0;
826 mActivePasswordNumeric = 0;
827 mActivePasswordSymbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700828 mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700829 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700830
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800831 validatePasswordOwnerLocked();
Ben Komalo2447edd2011-05-09 16:05:33 -0700832 syncDeviceCapabilitiesLocked();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700833 updateMaximumTimeToLockLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800834 }
835
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700836 static void validateQualityConstant(int quality) {
837 switch (quality) {
838 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500839 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700840 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
841 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
842 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
843 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700844 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700845 return;
846 }
847 throw new IllegalArgumentException("Invalid quality constant: 0x"
848 + Integer.toHexString(quality));
849 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700850
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800851 void validatePasswordOwnerLocked() {
852 if (mPasswordOwner >= 0) {
853 boolean haveOwner = false;
854 for (int i=mAdminList.size()-1; i>=0; i--) {
855 if (mAdminList.get(i).getUid() == mPasswordOwner) {
856 haveOwner = true;
857 break;
858 }
859 }
860 if (!haveOwner) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700861 Slog.w(TAG, "Previous password owner " + mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800862 + " no longer active; disabling");
863 mPasswordOwner = -1;
864 }
865 }
866 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700867
Ben Komalo2447edd2011-05-09 16:05:33 -0700868 /**
869 * Pushes down policy information to the system for any policies related to general device
870 * capabilities that need to be enforced by lower level services (e.g. Camera services).
871 */
872 void syncDeviceCapabilitiesLocked() {
873 // Ensure the status of the camera is synced down to the system. Interested native services
874 // should monitor this value and act accordingly.
875 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
876 boolean cameraDisabled = getCameraDisabled(null);
877 if (cameraDisabled != systemState) {
878 long token = Binder.clearCallingIdentity();
879 try {
880 String value = cameraDisabled ? "1" : "0";
881 Slog.v(TAG, "Change in camera state ["
882 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
883 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
884 } finally {
885 Binder.restoreCallingIdentity(token);
886 }
887 }
888 }
889
Dianne Hackbornd6847842010-01-12 18:14:19 -0800890 public void systemReady() {
891 synchronized (this) {
892 loadSettingsLocked();
893 }
894 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700895
Jim Millera4e28d12010-11-08 16:15:47 -0800896 private void handlePasswordExpirationNotification() {
897 synchronized (this) {
898 final long now = System.currentTimeMillis();
899 final int N = mAdminList.size();
900 if (N <= 0) {
901 return;
902 }
903 for (int i=0; i < N; i++) {
904 ActiveAdmin admin = mAdminList.get(i);
905 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
906 && admin.passwordExpirationTimeout > 0L
907 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -0800908 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -0800909 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
910 }
911 }
912 setExpirationAlarmCheckLocked(mContext);
913 }
914 }
915
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800916 /**
917 * @param adminReceiver The admin to add
918 * @param refreshing true = update an active admin, no error
919 */
920 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800921 mContext.enforceCallingOrSelfPermission(
922 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700923
Dianne Hackbornd6847842010-01-12 18:14:19 -0800924 DeviceAdminInfo info = findAdmin(adminReceiver);
925 if (info == null) {
926 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
927 }
928 synchronized (this) {
929 long ident = Binder.clearCallingIdentity();
930 try {
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800931 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800932 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -0800933 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800934 ActiveAdmin newAdmin = new ActiveAdmin(info);
935 mAdminMap.put(adminReceiver, newAdmin);
936 int replaceIndex = -1;
937 if (refreshing) {
938 final int N = mAdminList.size();
939 for (int i=0; i < N; i++) {
940 ActiveAdmin oldAdmin = mAdminList.get(i);
941 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
942 replaceIndex = i;
943 break;
944 }
945 }
946 }
947 if (replaceIndex == -1) {
948 mAdminList.add(newAdmin);
949 } else {
950 mAdminList.set(replaceIndex, newAdmin);
951 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800952 saveSettingsLocked();
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800953 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800954 } finally {
955 Binder.restoreCallingIdentity(ident);
956 }
957 }
958 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700959
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800960 public boolean isAdminActive(ComponentName adminReceiver) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800961 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800962 return getActiveAdminUncheckedLocked(adminReceiver) != null;
963 }
964 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700965
Andy Stadlerc25f70a2010-12-08 15:56:45 -0800966 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) {
967 synchronized (this) {
968 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver);
969 if (administrator == null) {
970 throw new SecurityException("No active admin " + adminReceiver);
971 }
972 return administrator.info.usesPolicy(policyId);
973 }
974 }
975
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800976 public List<ComponentName> getActiveAdmins() {
977 synchronized (this) {
978 final int N = mAdminList.size();
979 if (N <= 0) {
980 return null;
981 }
982 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
983 for (int i=0; i<N; i++) {
984 res.add(mAdminList.get(i).info.getComponent());
985 }
986 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800987 }
988 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700989
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800990 public boolean packageHasActiveAdmins(String packageName) {
991 synchronized (this) {
992 final int N = mAdminList.size();
993 for (int i=0; i<N; i++) {
994 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
995 return true;
996 }
997 }
998 return false;
999 }
1000 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001001
Dianne Hackbornd6847842010-01-12 18:14:19 -08001002 public void removeActiveAdmin(ComponentName adminReceiver) {
1003 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001004 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
1005 if (admin == null) {
1006 return;
1007 }
1008 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001009 mContext.enforceCallingOrSelfPermission(
1010 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1011 }
1012 long ident = Binder.clearCallingIdentity();
1013 try {
1014 removeActiveAdminLocked(adminReceiver);
1015 } finally {
1016 Binder.restoreCallingIdentity(ident);
1017 }
1018 }
1019 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001020
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001021 public void setPasswordQuality(ComponentName who, int quality) {
1022 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001023
Dianne Hackbornd6847842010-01-12 18:14:19 -08001024 synchronized (this) {
1025 if (who == null) {
1026 throw new NullPointerException("ComponentName is null");
1027 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001028 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1029 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001030 if (ap.passwordQuality != quality) {
1031 ap.passwordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001032 saveSettingsLocked();
1033 }
1034 }
1035 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001036
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001037 public int getPasswordQuality(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001038 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001039 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001040
Dianne Hackborn254cb442010-01-27 19:23:59 -08001041 if (who != null) {
1042 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001043 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001044 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001045
Dianne Hackborn254cb442010-01-27 19:23:59 -08001046 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001047 for (int i=0; i<N; i++) {
1048 ActiveAdmin admin = mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001049 if (mode < admin.passwordQuality) {
1050 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001051 }
1052 }
1053 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001054 }
1055 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001056
Dianne Hackborn254cb442010-01-27 19:23:59 -08001057 public void setPasswordMinimumLength(ComponentName who, int length) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001058 synchronized (this) {
1059 if (who == null) {
1060 throw new NullPointerException("ComponentName is null");
1061 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001062 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1063 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001064 if (ap.minimumPasswordLength != length) {
1065 ap.minimumPasswordLength = length;
1066 saveSettingsLocked();
1067 }
1068 }
1069 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001070
Dianne Hackborn254cb442010-01-27 19:23:59 -08001071 public int getPasswordMinimumLength(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001072 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001073 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001074
Dianne Hackborn254cb442010-01-27 19:23:59 -08001075 if (who != null) {
1076 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1077 return admin != null ? admin.minimumPasswordLength : length;
1078 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001079
Dianne Hackborn254cb442010-01-27 19:23:59 -08001080 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001081 for (int i=0; i<N; i++) {
1082 ActiveAdmin admin = mAdminList.get(i);
1083 if (length < admin.minimumPasswordLength) {
1084 length = admin.minimumPasswordLength;
1085 }
1086 }
1087 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001088 }
1089 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001090
1091 public void setPasswordHistoryLength(ComponentName who, int length) {
1092 synchronized (this) {
1093 if (who == null) {
1094 throw new NullPointerException("ComponentName is null");
1095 }
1096 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1097 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1098 if (ap.passwordHistoryLength != length) {
1099 ap.passwordHistoryLength = length;
1100 saveSettingsLocked();
1101 }
1102 }
1103 }
1104
1105 public int getPasswordHistoryLength(ComponentName who) {
1106 synchronized (this) {
1107 int length = 0;
1108
1109 if (who != null) {
1110 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1111 return admin != null ? admin.passwordHistoryLength : length;
1112 }
1113
1114 final int N = mAdminList.size();
1115 for (int i = 0; i < N; i++) {
1116 ActiveAdmin admin = mAdminList.get(i);
1117 if (length < admin.passwordHistoryLength) {
1118 length = admin.passwordHistoryLength;
1119 }
1120 }
1121 return length;
1122 }
1123 }
1124
Jim Millera4e28d12010-11-08 16:15:47 -08001125 public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
1126 synchronized (this) {
1127 if (who == null) {
1128 throw new NullPointerException("ComponentName is null");
1129 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001130 if (timeout < 0) {
1131 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001132 }
1133 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1134 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1135 // Calling this API automatically bumps the expiration date
1136 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1137 ap.passwordExpirationDate = expiration;
1138 ap.passwordExpirationTimeout = timeout;
1139 if (timeout > 0L) {
1140 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1141 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1142 .format(new Date(expiration)));
1143 }
1144 saveSettingsLocked();
1145 setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1146 }
1147 }
1148
Andy Stadler043116a2010-11-29 17:43:32 -08001149 /**
1150 * Return a single admin's expiration cycle time, or the min of all cycle times.
1151 * Returns 0 if not configured.
1152 */
Jim Millera4e28d12010-11-08 16:15:47 -08001153 public long getPasswordExpirationTimeout(ComponentName who) {
1154 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001155 if (who != null) {
1156 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001157 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001158 }
1159
Andy Stadler043116a2010-11-29 17:43:32 -08001160 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001161 final int N = mAdminList.size();
1162 for (int i = 0; i < N; i++) {
1163 ActiveAdmin admin = mAdminList.get(i);
1164 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1165 && timeout > admin.passwordExpirationTimeout)) {
1166 timeout = admin.passwordExpirationTimeout;
1167 }
1168 }
1169 return timeout;
1170 }
1171 }
1172
Andy Stadler043116a2010-11-29 17:43:32 -08001173 /**
1174 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1175 * Returns 0 if not configured.
1176 */
Jim Millera4e28d12010-11-08 16:15:47 -08001177 private long getPasswordExpirationLocked(ComponentName who) {
Jim Millera4e28d12010-11-08 16:15:47 -08001178 if (who != null) {
1179 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
Andy Stadler043116a2010-11-29 17:43:32 -08001180 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001181 }
1182
Andy Stadler043116a2010-11-29 17:43:32 -08001183 long timeout = 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001184 final int N = mAdminList.size();
1185 for (int i = 0; i < N; i++) {
1186 ActiveAdmin admin = mAdminList.get(i);
1187 if (timeout == 0L || (admin.passwordExpirationDate != 0
1188 && timeout > admin.passwordExpirationDate)) {
1189 timeout = admin.passwordExpirationDate;
1190 }
1191 }
1192 return timeout;
1193 }
1194
1195 public long getPasswordExpiration(ComponentName who) {
1196 synchronized (this) {
1197 return getPasswordExpirationLocked(who);
1198 }
1199 }
1200
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001201 public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1202 synchronized (this) {
1203 if (who == null) {
1204 throw new NullPointerException("ComponentName is null");
1205 }
1206 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1207 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1208 if (ap.minimumPasswordUpperCase != length) {
1209 ap.minimumPasswordUpperCase = length;
1210 saveSettingsLocked();
1211 }
1212 }
1213 }
1214
1215 public int getPasswordMinimumUpperCase(ComponentName who) {
1216 synchronized (this) {
1217 int length = 0;
1218
1219 if (who != null) {
1220 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1221 return admin != null ? admin.minimumPasswordUpperCase : length;
1222 }
1223
1224 final int N = mAdminList.size();
1225 for (int i=0; i<N; i++) {
1226 ActiveAdmin admin = mAdminList.get(i);
1227 if (length < admin.minimumPasswordUpperCase) {
1228 length = admin.minimumPasswordUpperCase;
1229 }
1230 }
1231 return length;
1232 }
1233 }
1234
1235 public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1236 synchronized (this) {
1237 if (who == null) {
1238 throw new NullPointerException("ComponentName is null");
1239 }
1240 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1241 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1242 if (ap.minimumPasswordLowerCase != length) {
1243 ap.minimumPasswordLowerCase = length;
1244 saveSettingsLocked();
1245 }
1246 }
1247 }
1248
1249 public int getPasswordMinimumLowerCase(ComponentName who) {
1250 synchronized (this) {
1251 int length = 0;
1252
1253 if (who != null) {
1254 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1255 return admin != null ? admin.minimumPasswordLowerCase : length;
1256 }
1257
1258 final int N = mAdminList.size();
1259 for (int i=0; i<N; i++) {
1260 ActiveAdmin admin = mAdminList.get(i);
1261 if (length < admin.minimumPasswordLowerCase) {
1262 length = admin.minimumPasswordLowerCase;
1263 }
1264 }
1265 return length;
1266 }
1267 }
1268
1269 public void setPasswordMinimumLetters(ComponentName who, int length) {
1270 synchronized (this) {
1271 if (who == null) {
1272 throw new NullPointerException("ComponentName is null");
1273 }
1274 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1275 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1276 if (ap.minimumPasswordLetters != length) {
1277 ap.minimumPasswordLetters = length;
1278 saveSettingsLocked();
1279 }
1280 }
1281 }
1282
1283 public int getPasswordMinimumLetters(ComponentName who) {
1284 synchronized (this) {
1285 int length = 0;
1286
1287 if (who != null) {
1288 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1289 return admin != null ? admin.minimumPasswordLetters : length;
1290 }
1291
1292 final int N = mAdminList.size();
1293 for (int i=0; i<N; i++) {
1294 ActiveAdmin admin = mAdminList.get(i);
1295 if (length < admin.minimumPasswordLetters) {
1296 length = admin.minimumPasswordLetters;
1297 }
1298 }
1299 return length;
1300 }
1301 }
1302
1303 public void setPasswordMinimumNumeric(ComponentName who, int length) {
1304 synchronized (this) {
1305 if (who == null) {
1306 throw new NullPointerException("ComponentName is null");
1307 }
1308 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1309 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1310 if (ap.minimumPasswordNumeric != length) {
1311 ap.minimumPasswordNumeric = length;
1312 saveSettingsLocked();
1313 }
1314 }
1315 }
1316
1317 public int getPasswordMinimumNumeric(ComponentName who) {
1318 synchronized (this) {
1319 int length = 0;
1320
1321 if (who != null) {
1322 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1323 return admin != null ? admin.minimumPasswordNumeric : length;
1324 }
1325
1326 final int N = mAdminList.size();
1327 for (int i = 0; i < N; i++) {
1328 ActiveAdmin admin = mAdminList.get(i);
1329 if (length < admin.minimumPasswordNumeric) {
1330 length = admin.minimumPasswordNumeric;
1331 }
1332 }
1333 return length;
1334 }
1335 }
1336
1337 public void setPasswordMinimumSymbols(ComponentName who, int length) {
1338 synchronized (this) {
1339 if (who == null) {
1340 throw new NullPointerException("ComponentName is null");
1341 }
1342 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1343 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1344 if (ap.minimumPasswordSymbols != length) {
1345 ap.minimumPasswordSymbols = length;
1346 saveSettingsLocked();
1347 }
1348 }
1349 }
1350
1351 public int getPasswordMinimumSymbols(ComponentName who) {
1352 synchronized (this) {
1353 int length = 0;
1354
1355 if (who != null) {
1356 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1357 return admin != null ? admin.minimumPasswordSymbols : length;
1358 }
1359
1360 final int N = mAdminList.size();
1361 for (int i=0; i<N; i++) {
1362 ActiveAdmin admin = mAdminList.get(i);
1363 if (length < admin.minimumPasswordSymbols) {
1364 length = admin.minimumPasswordSymbols;
1365 }
1366 }
1367 return length;
1368 }
1369 }
1370
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001371 public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1372 synchronized (this) {
1373 if (who == null) {
1374 throw new NullPointerException("ComponentName is null");
1375 }
1376 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1377 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1378 if (ap.minimumPasswordNonLetter != length) {
1379 ap.minimumPasswordNonLetter = length;
1380 saveSettingsLocked();
1381 }
1382 }
1383 }
1384
1385 public int getPasswordMinimumNonLetter(ComponentName who) {
1386 synchronized (this) {
1387 int length = 0;
1388
1389 if (who != null) {
1390 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1391 return admin != null ? admin.minimumPasswordNonLetter : length;
1392 }
1393
1394 final int N = mAdminList.size();
1395 for (int i=0; i<N; i++) {
1396 ActiveAdmin admin = mAdminList.get(i);
1397 if (length < admin.minimumPasswordNonLetter) {
1398 length = admin.minimumPasswordNonLetter;
1399 }
1400 }
1401 return length;
1402 }
1403 }
1404
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001405 public boolean isActivePasswordSufficient() {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001406 synchronized (this) {
1407 // This API can only be called by an active device admin,
1408 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001409 getActiveAdminForCallerLocked(null,
1410 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001411 if (mActivePasswordQuality < getPasswordQuality(null)
1412 || mActivePasswordLength < getPasswordMinimumLength(null)) {
1413 return false;
1414 }
1415 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1416 return true;
1417 }
1418 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1419 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1420 && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1421 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001422 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1423 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001424 }
1425 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001426
Dianne Hackbornd6847842010-01-12 18:14:19 -08001427 public int getCurrentFailedPasswordAttempts() {
1428 synchronized (this) {
1429 // This API can only be called by an active device admin,
1430 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001431 getActiveAdminForCallerLocked(null,
1432 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001433 return mFailedPasswordAttempts;
1434 }
1435 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001436
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001437 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1438 synchronized (this) {
1439 // This API can only be called by an active device admin,
1440 // so try to retrieve it to check that the caller is one.
1441 getActiveAdminForCallerLocked(who,
1442 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1443 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1444 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1445 if (ap.maximumFailedPasswordsForWipe != num) {
1446 ap.maximumFailedPasswordsForWipe = num;
1447 saveSettingsLocked();
1448 }
1449 }
1450 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001451
Dianne Hackborn254cb442010-01-27 19:23:59 -08001452 public int getMaximumFailedPasswordsForWipe(ComponentName who) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001453 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001454 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001455
Dianne Hackborn254cb442010-01-27 19:23:59 -08001456 if (who != null) {
1457 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1458 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1459 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001460
Dianne Hackborn254cb442010-01-27 19:23:59 -08001461 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001462 for (int i=0; i<N; i++) {
1463 ActiveAdmin admin = mAdminList.get(i);
1464 if (count == 0) {
1465 count = admin.maximumFailedPasswordsForWipe;
1466 } else if (admin.maximumFailedPasswordsForWipe != 0
1467 && count > admin.maximumFailedPasswordsForWipe) {
1468 count = admin.maximumFailedPasswordsForWipe;
1469 }
1470 }
1471 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001472 }
1473 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001474
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001475 public boolean resetPassword(String password, int flags) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001476 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001477 synchronized (this) {
1478 // This API can only be called by an active device admin,
1479 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001480 getActiveAdminForCallerLocked(null,
1481 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001482 quality = getPasswordQuality(null);
1483 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001484 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001485 if (realQuality < quality
1486 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001487 Slog.w(TAG, "resetPassword: password quality 0x"
1488 + Integer.toHexString(quality)
1489 + " does not meet required quality 0x"
1490 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001491 return false;
1492 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001493 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001494 }
1495 int length = getPasswordMinimumLength(null);
1496 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001497 Slog.w(TAG, "resetPassword: password length " + password.length()
1498 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001499 return false;
1500 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001501 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1502 int letters = 0;
1503 int uppercase = 0;
1504 int lowercase = 0;
1505 int numbers = 0;
1506 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001507 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001508 for (int i = 0; i < password.length(); i++) {
1509 char c = password.charAt(i);
1510 if (c >= 'A' && c <= 'Z') {
1511 letters++;
1512 uppercase++;
1513 } else if (c >= 'a' && c <= 'z') {
1514 letters++;
1515 lowercase++;
1516 } else if (c >= '0' && c <= '9') {
1517 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001518 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001519 } else {
1520 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001521 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001522 }
1523 }
1524 int neededLetters = getPasswordMinimumLetters(null);
1525 if(letters < neededLetters) {
1526 Slog.w(TAG, "resetPassword: number of letters " + letters
1527 + " does not meet required number of letters " + neededLetters);
1528 return false;
1529 }
1530 int neededNumbers = getPasswordMinimumNumeric(null);
1531 if (numbers < neededNumbers) {
1532 Slog
1533 .w(TAG, "resetPassword: number of numerical digits " + numbers
1534 + " does not meet required number of numerical digits "
1535 + neededNumbers);
1536 return false;
1537 }
1538 int neededLowerCase = getPasswordMinimumLowerCase(null);
1539 if (lowercase < neededLowerCase) {
1540 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1541 + " does not meet required number of lowercase letters "
1542 + neededLowerCase);
1543 return false;
1544 }
1545 int neededUpperCase = getPasswordMinimumUpperCase(null);
1546 if (uppercase < neededUpperCase) {
1547 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1548 + " does not meet required number of uppercase letters "
1549 + neededUpperCase);
1550 return false;
1551 }
1552 int neededSymbols = getPasswordMinimumSymbols(null);
1553 if (symbols < neededSymbols) {
1554 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1555 + " does not meet required number of special symbols " + neededSymbols);
1556 return false;
1557 }
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001558 int neededNonLetter = getPasswordMinimumNonLetter(null);
1559 if (nonletter < neededNonLetter) {
1560 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1561 + " does not meet required number of non-letter characters "
1562 + neededNonLetter);
1563 return false;
1564 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001565 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001566 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001567
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001568 int callingUid = Binder.getCallingUid();
1569 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001570 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001571 return false;
1572 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001573
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001574 // Don't do this with the lock held, because it is going to call
1575 // back in to the service.
1576 long ident = Binder.clearCallingIdentity();
1577 try {
1578 LockPatternUtils utils = new LockPatternUtils(mContext);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001579 utils.saveLockPassword(password, quality);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001580 synchronized (this) {
1581 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1582 != 0 ? callingUid : -1;
1583 if (mPasswordOwner != newOwner) {
1584 mPasswordOwner = newOwner;
1585 saveSettingsLocked();
1586 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001587 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001588 } finally {
1589 Binder.restoreCallingIdentity(ident);
1590 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001591
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001592 return true;
1593 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001594
Dianne Hackbornd6847842010-01-12 18:14:19 -08001595 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1596 synchronized (this) {
1597 if (who == null) {
1598 throw new NullPointerException("ComponentName is null");
1599 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001600 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001601 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001602 if (ap.maximumTimeToUnlock != timeMs) {
1603 ap.maximumTimeToUnlock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001604 saveSettingsLocked();
1605 updateMaximumTimeToLockLocked();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001606 }
1607 }
1608 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001609
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001610 void updateMaximumTimeToLockLocked() {
1611 long timeMs = getMaximumTimeToLock(null);
1612 if (mLastMaximumTimeToLock == timeMs) {
1613 return;
1614 }
1615
1616 long ident = Binder.clearCallingIdentity();
1617 try {
1618 if (timeMs <= 0) {
1619 timeMs = Integer.MAX_VALUE;
1620 } else {
1621 // Make sure KEEP_SCREEN_ON is disabled, since that
1622 // would allow bypassing of the maximum time to lock.
1623 Settings.System.putInt(mContext.getContentResolver(),
1624 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
1625 }
1626
1627 mLastMaximumTimeToLock = timeMs;
1628
1629 try {
Jeff Brown96307042012-07-27 15:51:34 -07001630 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001631 } catch (RemoteException e) {
1632 Slog.w(TAG, "Failure talking with power manager", e);
1633 }
1634 } finally {
1635 Binder.restoreCallingIdentity(ident);
1636 }
1637 }
1638
Dianne Hackborn254cb442010-01-27 19:23:59 -08001639 public long getMaximumTimeToLock(ComponentName who) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001640 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001641 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001642
Dianne Hackborn254cb442010-01-27 19:23:59 -08001643 if (who != null) {
1644 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1645 return admin != null ? admin.maximumTimeToUnlock : time;
1646 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001647
Dianne Hackborn254cb442010-01-27 19:23:59 -08001648 final int N = mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001649 for (int i=0; i<N; i++) {
1650 ActiveAdmin admin = mAdminList.get(i);
1651 if (time == 0) {
1652 time = admin.maximumTimeToUnlock;
1653 } else if (admin.maximumTimeToUnlock != 0
1654 && time > admin.maximumTimeToUnlock) {
1655 time = admin.maximumTimeToUnlock;
1656 }
1657 }
1658 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001659 }
1660 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001661
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001662 public void lockNow() {
1663 synchronized (this) {
1664 // This API can only be called by an active device admin,
1665 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001666 getActiveAdminForCallerLocked(null,
1667 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001668 long ident = Binder.clearCallingIdentity();
1669 try {
Jim Miller93c518e2012-01-17 15:55:31 -08001670 // Power off the display
Jeff Brown96307042012-07-27 15:51:34 -07001671 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1672 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
Jim Miller93c518e2012-01-17 15:55:31 -08001673 // Ensure the device is locked
1674 getWindowManager().lockNow();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001675 } catch (RemoteException e) {
1676 } finally {
1677 Binder.restoreCallingIdentity(ident);
1678 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001679 }
1680 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001681
Ben Komaloed48c8b2011-10-17 17:30:21 -07001682 private boolean isExtStorageEncrypted() {
1683 String state = SystemProperties.get("vold.decrypt");
1684 return !"".equals(state);
1685 }
1686
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001687 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001688 // If the SD card is encrypted and non-removable, we have to force a wipe.
1689 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1690 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1691
1692 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1693 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001694 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001695 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001696 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1697 mWakeLock.acquire(10000);
1698 mContext.startService(intent);
1699 } else {
1700 try {
1701 RecoverySystem.rebootWipeUserData(mContext);
1702 } catch (IOException e) {
1703 Slog.w(TAG, "Failed requesting data wipe", e);
1704 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001705 }
1706 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001707
Dianne Hackbornd6847842010-01-12 18:14:19 -08001708 public void wipeData(int flags) {
1709 synchronized (this) {
1710 // This API can only be called by an active device admin,
1711 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001712 getActiveAdminForCallerLocked(null,
1713 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001714 long ident = Binder.clearCallingIdentity();
1715 try {
1716 wipeDataLocked(flags);
1717 } finally {
1718 Binder.restoreCallingIdentity(ident);
1719 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001720 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001721 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001722
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001723 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1724 mContext.enforceCallingOrSelfPermission(
1725 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001726
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001727 synchronized (this) {
1728 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1729 if (admin == null) {
1730 try {
1731 result.sendResult(null);
1732 } catch (RemoteException e) {
1733 }
1734 return;
1735 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001736 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001737 intent.setComponent(admin.info.getComponent());
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001738 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
1739 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001740 @Override
1741 public void onReceive(Context context, Intent intent) {
1742 try {
1743 result.sendResult(getResultExtras(false));
1744 } catch (RemoteException e) {
1745 }
1746 }
1747 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001748 }
1749 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001750
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001751 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001752 int lowercase, int numbers, int symbols, int nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001753 mContext.enforceCallingOrSelfPermission(
1754 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001755
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001756 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001757
Dianne Hackbornd6847842010-01-12 18:14:19 -08001758 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001759 if (mActivePasswordQuality != quality || mActivePasswordLength != length
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001760 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1761 || mActivePasswordUpperCase != uppercase
1762 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001763 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001764 long ident = Binder.clearCallingIdentity();
1765 try {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001766 mActivePasswordQuality = quality;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001767 mActivePasswordLength = length;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001768 mActivePasswordLetters = letters;
1769 mActivePasswordLowerCase = lowercase;
1770 mActivePasswordUpperCase = uppercase;
1771 mActivePasswordNumeric = numbers;
1772 mActivePasswordSymbols = symbols;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001773 mActivePasswordNonLetter = nonletter;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001774 mFailedPasswordAttempts = 0;
1775 saveSettingsLocked();
Jim Millera4e28d12010-11-08 16:15:47 -08001776 updatePasswordExpirationsLocked();
Andy Stadler043116a2010-11-29 17:43:32 -08001777 setExpirationAlarmCheckLocked(mContext);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001778 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001779 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001780 } finally {
1781 Binder.restoreCallingIdentity(ident);
1782 }
1783 }
1784 }
1785 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001786
Andy Stadler043116a2010-11-29 17:43:32 -08001787 /**
1788 * Called any time the device password is updated. Resets all password expiration clocks.
1789 */
Jim Millera4e28d12010-11-08 16:15:47 -08001790 private void updatePasswordExpirationsLocked() {
1791 final int N = mAdminList.size();
1792 if (N > 0) {
1793 for (int i=0; i<N; i++) {
1794 ActiveAdmin admin = mAdminList.get(i);
1795 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001796 long timeout = admin.passwordExpirationTimeout;
1797 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1798 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001799 }
1800 }
1801 saveSettingsLocked();
1802 }
1803 }
1804
Dianne Hackbornd6847842010-01-12 18:14:19 -08001805 public void reportFailedPasswordAttempt() {
1806 mContext.enforceCallingOrSelfPermission(
1807 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001808
Dianne Hackbornd6847842010-01-12 18:14:19 -08001809 synchronized (this) {
1810 long ident = Binder.clearCallingIdentity();
1811 try {
1812 mFailedPasswordAttempts++;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001813 saveSettingsLocked();
Dianne Hackborn254cb442010-01-27 19:23:59 -08001814 int max = getMaximumFailedPasswordsForWipe(null);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001815 if (max > 0 && mFailedPasswordAttempts >= max) {
1816 wipeDataLocked(0);
1817 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001818 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001819 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001820 } finally {
1821 Binder.restoreCallingIdentity(ident);
1822 }
1823 }
1824 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001825
Dianne Hackbornd6847842010-01-12 18:14:19 -08001826 public void reportSuccessfulPasswordAttempt() {
1827 mContext.enforceCallingOrSelfPermission(
1828 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001829
Dianne Hackbornd6847842010-01-12 18:14:19 -08001830 synchronized (this) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001831 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001832 long ident = Binder.clearCallingIdentity();
1833 try {
1834 mFailedPasswordAttempts = 0;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001835 mPasswordOwner = -1;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001836 saveSettingsLocked();
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001837 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001838 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001839 } finally {
1840 Binder.restoreCallingIdentity(ident);
1841 }
1842 }
1843 }
1844 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001845
Oscar Montemayor69238c62010-08-03 10:51:06 -07001846 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1847 String exclusionList) {
1848 synchronized(this) {
1849 if (who == null) {
1850 throw new NullPointerException("ComponentName is null");
1851 }
1852
1853 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1854 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1855
1856 // Scan through active admins and find if anyone has already
1857 // set the global proxy.
Oscar Montemayor69238c62010-08-03 10:51:06 -07001858 Set<ComponentName> compSet = mAdminMap.keySet();
1859 for (ComponentName component : compSet) {
1860 ActiveAdmin ap = mAdminMap.get(component);
1861 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1862 // Another admin already sets the global proxy
1863 // Return it to the caller.
1864 return component;
1865 }
1866 }
1867 if (proxySpec == null) {
1868 admin.specifiesGlobalProxy = false;
1869 admin.globalProxySpec = null;
1870 admin.globalProxyExclusionList = null;
1871 } else {
1872
1873 admin.specifiesGlobalProxy = true;
1874 admin.globalProxySpec = proxySpec;
1875 admin.globalProxyExclusionList = exclusionList;
1876 }
1877
1878 // Reset the global proxy accordingly
1879 // Do this using system permissions, as apps cannot write to secure settings
1880 long origId = Binder.clearCallingIdentity();
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001881 resetGlobalProxyLocked();
Oscar Montemayor69238c62010-08-03 10:51:06 -07001882 Binder.restoreCallingIdentity(origId);
1883 return null;
1884 }
1885 }
1886
1887 public ComponentName getGlobalProxyAdmin() {
1888 synchronized(this) {
1889 // Scan through active admins and find if anyone has already
1890 // set the global proxy.
1891 final int N = mAdminList.size();
1892 for (int i = 0; i < N; i++) {
1893 ActiveAdmin ap = mAdminList.get(i);
1894 if (ap.specifiesGlobalProxy) {
1895 // Device admin sets the global proxy
1896 // Return it to the caller.
1897 return ap.info.getComponent();
1898 }
1899 }
1900 }
1901 // No device admin sets the global proxy.
1902 return null;
1903 }
1904
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001905 private void resetGlobalProxyLocked() {
Oscar Montemayor69238c62010-08-03 10:51:06 -07001906 final int N = mAdminList.size();
1907 for (int i = 0; i < N; i++) {
1908 ActiveAdmin ap = mAdminList.get(i);
1909 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001910 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001911 return;
1912 }
1913 }
1914 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001915 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001916 }
1917
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001918 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07001919 if (exclusionList == null) {
1920 exclusionList = "";
1921 }
1922 if (proxySpec == null) {
1923 proxySpec = "";
1924 }
1925 // Remove white spaces
1926 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001927 String data[] = proxySpec.split(":");
1928 int proxyPort = 8080;
1929 if (data.length > 1) {
1930 try {
1931 proxyPort = Integer.parseInt(data[1]);
1932 } catch (NumberFormatException e) {}
1933 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07001934 exclusionList = exclusionList.trim();
1935 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07001936 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1937 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1938 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1939 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07001940 }
1941
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001942 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001943 * Set the storage encryption request for a single admin. Returns the new total request
1944 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001945 */
1946 public int setStorageEncryption(ComponentName who, boolean encrypt) {
1947 synchronized (this) {
1948 // Check for permissions
1949 if (who == null) {
1950 throw new NullPointerException("ComponentName is null");
1951 }
1952 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1953 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
1954
Andy Stadler22dbfda2011-01-17 12:47:31 -08001955 // Quick exit: If the filesystem does not support encryption, we can exit early.
1956 if (!isEncryptionSupported()) {
1957 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
1958 }
1959
1960 // (1) Record the value for the admin so it's sticky
1961 if (ap.encryptionRequested != encrypt) {
1962 ap.encryptionRequested = encrypt;
1963 saveSettingsLocked();
1964 }
1965
1966 // (2) Compute "max" for all admins
1967 boolean newRequested = false;
1968 final int N = mAdminList.size();
1969 for (int i = 0; i < N; i++) {
1970 newRequested |= mAdminList.get(i).encryptionRequested;
1971 }
1972
1973 // Notify OS of new request
1974 setEncryptionRequested(newRequested);
1975
1976 // Return the new global request status
1977 return newRequested
1978 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
1979 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001980 }
1981 }
1982
1983 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08001984 * Get the current storage encryption request status for a given admin, or aggregate of all
1985 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001986 */
Andy Stadler22dbfda2011-01-17 12:47:31 -08001987 public boolean getStorageEncryption(ComponentName who) {
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001988 synchronized (this) {
1989 // Check for permissions if a particular caller is specified
1990 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08001991 // When checking for a single caller, status is based on caller's request
Andy Stadlerc994d692011-06-01 15:30:54 -07001992 ActiveAdmin ap = getActiveAdminUncheckedLocked(who);
1993 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08001994 }
1995
Andy Stadler22dbfda2011-01-17 12:47:31 -08001996 // If no particular caller is specified, return the aggregate set of requests.
1997 // This is short circuited by returning true on the first hit.
1998 final int N = mAdminList.size();
1999 for (int i = 0; i < N; i++) {
2000 if (mAdminList.get(i).encryptionRequested) {
2001 return true;
2002 }
2003 }
2004 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002005 }
2006 }
2007
Andy Stadler22dbfda2011-01-17 12:47:31 -08002008 /**
2009 * Get the current encryption status of the device.
2010 */
2011 public int getStorageEncryptionStatus() {
2012 return getEncryptionStatus();
2013 }
2014
2015 /**
2016 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2017 */
2018 private boolean isEncryptionSupported() {
2019 // Note, this can be implemented as
2020 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2021 // But is provided as a separate internal method if there's a faster way to do a
2022 // simple check for supported-or-not.
2023 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2024 }
2025
2026 /**
2027 * Hook to low-levels: Reporting the current status of encryption.
2028 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2029 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2030 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2031 */
2032 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002033 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2034 if ("encrypted".equalsIgnoreCase(status)) {
2035 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2036 } else if ("unencrypted".equalsIgnoreCase(status)) {
2037 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2038 } else {
2039 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2040 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002041 }
2042
2043 /**
2044 * Hook to low-levels: If needed, record the new admin setting for encryption.
2045 */
2046 private void setEncryptionRequested(boolean encrypt) {
2047 }
2048
Ben Komalo2447edd2011-05-09 16:05:33 -07002049 /**
2050 * The system property used to share the state of the camera. The native camera service
2051 * is expected to read this property and act accordingly.
2052 */
2053 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2054
2055 /**
2056 * Disables all device cameras according to the specified admin.
2057 */
2058 public void setCameraDisabled(ComponentName who, boolean disabled) {
2059 synchronized (this) {
2060 if (who == null) {
2061 throw new NullPointerException("ComponentName is null");
2062 }
2063 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2064 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2065 if (ap.disableCamera != disabled) {
2066 ap.disableCamera = disabled;
2067 saveSettingsLocked();
2068 }
2069 syncDeviceCapabilitiesLocked();
2070 }
2071 }
2072
2073 /**
2074 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2075 * active admins.
2076 */
2077 public boolean getCameraDisabled(ComponentName who) {
2078 synchronized (this) {
2079 if (who != null) {
2080 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
2081 return (admin != null) ? admin.disableCamera : false;
2082 }
2083
2084 // Determine whether or not the device camera is disabled for any active admins.
2085 final int N = mAdminList.size();
2086 for (int i = 0; i < N; i++) {
2087 ActiveAdmin admin = mAdminList.get(i);
2088 if (admin.disableCamera) {
2089 return true;
2090 }
2091 }
2092 return false;
2093 }
2094 }
2095
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002096 @Override
2097 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2098 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2099 != PackageManager.PERMISSION_GRANTED) {
2100
2101 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2102 + Binder.getCallingPid()
2103 + ", uid=" + Binder.getCallingUid());
2104 return;
2105 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002106
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002107 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002108
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002109 synchronized (this) {
2110 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002111
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002112 p.println(" Enabled Device Admins:");
2113 final int N = mAdminList.size();
2114 for (int i=0; i<N; i++) {
2115 ActiveAdmin ap = mAdminList.get(i);
2116 if (ap != null) {
2117 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2118 pw.println(":");
2119 ap.dump(" ", pw);
2120 }
2121 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002122
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002123 pw.println(" ");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002124 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
2125 }
2126 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002127}