blob: 6a62809f6fa0608ca99484eab00bd62cedc0799c [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 Hackborn42499172010-10-15 18:45:07 -070019import com.android.internal.os.storage.ExternalStorageFormatter;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080020import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070021import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080022import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080023import com.android.internal.widget.LockPatternUtils;
Dianne Hackbornd6847842010-01-12 18:14:19 -080024
25import org.xmlpull.v1.XmlPullParser;
26import org.xmlpull.v1.XmlPullParserException;
27import org.xmlpull.v1.XmlSerializer;
28
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080029import android.app.Activity;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070030import android.app.ActivityManagerNative;
Jim Millera4e28d12010-11-08 16:15:47 -080031import android.app.AlarmManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070032import android.app.AppGlobals;
Jim Millera4e28d12010-11-08 16:15:47 -080033import android.app.PendingIntent;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080034import android.app.admin.DeviceAdminInfo;
35import android.app.admin.DeviceAdminReceiver;
36import android.app.admin.DevicePolicyManager;
37import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080038import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080039import android.content.ComponentName;
Oscar Montemayor69238c62010-08-03 10:51:06 -070040import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080041import android.content.Context;
42import android.content.Intent;
Jim Millera4e28d12010-11-08 16:15:47 -080043import android.content.IntentFilter;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070044import android.content.pm.IPackageManager;
Dianne Hackbornd6847842010-01-12 18:14:19 -080045import android.content.pm.PackageManager;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080046import android.content.pm.PackageManager.NameNotFoundException;
Andy Stadler1f35d482010-11-19 15:39:41 -080047import android.content.pm.ResolveInfo;
Dianne Hackbornd6847842010-01-12 18:14:19 -080048import android.os.Binder;
Adam Cohenf7522022012-10-03 20:03:18 -070049import android.os.Bundle;
Ben Komaloed48c8b2011-10-17 17:30:21 -070050import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080051import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080052import android.os.IBinder;
53import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070054import android.os.PowerManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070055import android.os.Process;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080056import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080057import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080058import android.os.RemoteException;
59import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080060import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080061import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070062import android.os.UserHandle;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070063import android.os.UserManager;
Oscar Montemayor69238c62010-08-03 10:51:06 -070064import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080065import android.util.PrintWriterPrinter;
66import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080067import android.util.Slog;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070068import android.util.SparseArray;
Dianne Hackbornd6847842010-01-12 18:14:19 -080069import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080070import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080071import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080072
73import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080074import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080075import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070076import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077import java.io.FileOutputStream;
78import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080079import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080080import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080081import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080082import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080083import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080084import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070085import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080086
87/**
88 * Implementation of the device policy APIs.
89 */
90public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Amith Yamasani599dd7c2012-09-14 23:20:08 -070091 private static final String DEVICE_POLICIES_XML = "device_policies.xml";
92
Jim Miller6b857682011-02-16 16:27:41 -080093 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080094
Jim Miller6b857682011-02-16 16:27:41 -080095 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070096
Amith Yamasani599dd7c2012-09-14 23:20:08 -070097 private static final long MS_PER_DAY = 86400 * 1000;
98
99 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
Jim Millera4e28d12010-11-08 16:15:47 -0800100
101 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
102 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
103
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700104 private static final boolean DBG = false;
Jim Millera4e28d12010-11-08 16:15:47 -0800105
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800106 final Context mContext;
Dianne Hackborn42499172010-10-15 18:45:07 -0700107 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800108
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800109 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800110 IWindowManager mIWindowManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700111
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700112 public static class DevicePolicyData {
113 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
114 int mActivePasswordLength = 0;
115 int mActivePasswordUpperCase = 0;
116 int mActivePasswordLowerCase = 0;
117 int mActivePasswordLetters = 0;
118 int mActivePasswordNumeric = 0;
119 int mActivePasswordSymbols = 0;
120 int mActivePasswordNonLetter = 0;
121 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700122
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700123 int mUserHandle;;
124 int mPasswordOwner = -1;
125 long mLastMaximumTimeToLock = -1;
126
127 final HashMap<ComponentName, ActiveAdmin> mAdminMap
128 = new HashMap<ComponentName, ActiveAdmin>();
129 final ArrayList<ActiveAdmin> mAdminList
130 = new ArrayList<ActiveAdmin>();
131
132 public DevicePolicyData(int userHandle) {
133 mUserHandle = userHandle;
134 }
135 }
136
137 final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
138
Jim Millera4e28d12010-11-08 16:15:47 -0800139 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700140
Jim Millera4e28d12010-11-08 16:15:47 -0800141 BroadcastReceiver mReceiver = new BroadcastReceiver() {
142 @Override
143 public void onReceive(Context context, Intent intent) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700144 final String action = intent.getAction();
145 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
146 getSendingUserId());
Jim Millera4e28d12010-11-08 16:15:47 -0800147 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
148 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800149 if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
150 + action + " for user " + userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800151 mHandler.post(new Runnable() {
152 public void run() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700153 handlePasswordExpirationNotification(getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -0800154 }
155 });
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700156 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
157 removeUserData(userHandle);
158 } else if (Intent.ACTION_USER_STARTED.equals(action)
159 || Intent.ACTION_PACKAGE_CHANGED.equals(action)
160 || Intent.ACTION_PACKAGE_REMOVED.equals(action)
161 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
162
163 if (Intent.ACTION_USER_STARTED.equals(action)) {
164 // Reset the policy data
165 synchronized (DevicePolicyManagerService.this) {
166 mUserData.remove(userHandle);
167 }
168 }
169
170 handlePackagesChanged(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800171 }
172 }
173 };
174
Dianne Hackbornd6847842010-01-12 18:14:19 -0800175 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800176 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700177
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800178 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700179
180 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
181 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
182
183 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
184 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
185
186 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
187 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
188
189 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
190 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
191
192 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700193 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700194
195 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
196 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
197
198 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
199 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
200
201 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
202 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
203
204 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
205 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
206
207 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
208 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
209
210 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
211 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
212
213 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
214 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
215
Jim Miller48b9b0d2012-09-19 23:16:50 -0700216 static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
217 int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
Jim Millerb8ec4702012-08-31 17:19:10 -0700218
Andy Stadler22dbfda2011-01-17 12:47:31 -0800219 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700220 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700221
Oscar Montemayor69238c62010-08-03 10:51:06 -0700222 // TODO: review implementation decisions with frameworks team
223 boolean specifiesGlobalProxy = false;
224 String globalProxySpec = null;
225 String globalProxyExclusionList = null;
226
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800227 ActiveAdmin(DeviceAdminInfo _info) {
228 info = _info;
229 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700230
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800231 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700232
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700233 public UserHandle getUserHandle() {
234 return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
235 }
236
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800237 void writeToXml(XmlSerializer out)
238 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800239 out.startTag(null, "policies");
240 info.writePoliciesToXml(out);
241 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800242 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
243 out.startTag(null, "password-quality");
244 out.attribute(null, "value", Integer.toString(passwordQuality));
245 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700246 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800247 out.startTag(null, "min-password-length");
248 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700249 out.endTag(null, "min-password-length");
250 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700251 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700252 out.startTag(null, "password-history-length");
253 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
254 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800255 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700256 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700257 out.startTag(null, "min-password-uppercase");
258 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
259 out.endTag(null, "min-password-uppercase");
260 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700261 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700262 out.startTag(null, "min-password-lowercase");
263 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
264 out.endTag(null, "min-password-lowercase");
265 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700266 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700267 out.startTag(null, "min-password-letters");
268 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
269 out.endTag(null, "min-password-letters");
270 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700271 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700272 out.startTag(null, "min-password-numeric");
273 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
274 out.endTag(null, "min-password-numeric");
275 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700276 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700277 out.startTag(null, "min-password-symbols");
278 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
279 out.endTag(null, "min-password-symbols");
280 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700281 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700282 out.startTag(null, "min-password-nonletter");
283 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
284 out.endTag(null, "min-password-nonletter");
285 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800286 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700287 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800288 out.startTag(null, "max-time-to-unlock");
289 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
290 out.endTag(null, "max-time-to-unlock");
291 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700292 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800293 out.startTag(null, "max-failed-password-wipe");
294 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
295 out.endTag(null, "max-failed-password-wipe");
296 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700297 if (specifiesGlobalProxy) {
298 out.startTag(null, "specifies-global-proxy");
299 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
300 out.endTag(null, "specifies_global_proxy");
301 if (globalProxySpec != null) {
302 out.startTag(null, "global-proxy-spec");
303 out.attribute(null, "value", globalProxySpec);
304 out.endTag(null, "global-proxy-spec");
305 }
306 if (globalProxyExclusionList != null) {
307 out.startTag(null, "global-proxy-exclusion-list");
308 out.attribute(null, "value", globalProxyExclusionList);
309 out.endTag(null, "global-proxy-exclusion-list");
310 }
311 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700312 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800313 out.startTag(null, "password-expiration-timeout");
314 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
315 out.endTag(null, "password-expiration-timeout");
316 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700317 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800318 out.startTag(null, "password-expiration-date");
319 out.attribute(null, "value", Long.toString(passwordExpirationDate));
320 out.endTag(null, "password-expiration-date");
321 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800322 if (encryptionRequested) {
323 out.startTag(null, "encryption-requested");
324 out.attribute(null, "value", Boolean.toString(encryptionRequested));
325 out.endTag(null, "encryption-requested");
326 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700327 if (disableCamera) {
328 out.startTag(null, "disable-camera");
329 out.attribute(null, "value", Boolean.toString(disableCamera));
330 out.endTag(null, "disable-camera");
331 }
Jim Miller48b9b0d2012-09-19 23:16:50 -0700332 if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
333 out.startTag(null, "disable-keyguard-features");
334 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
335 out.endTag(null, "disable-keyguard-features");
Jim Millerb8ec4702012-08-31 17:19:10 -0700336 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800337 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700338
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800339 void readFromXml(XmlPullParser parser)
340 throws XmlPullParserException, IOException {
341 int outerDepth = parser.getDepth();
342 int type;
343 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
344 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
345 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
346 continue;
347 }
348 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800349 if ("policies".equals(tag)) {
350 info.readPoliciesFromXml(parser);
351 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800352 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800353 parser.getAttributeValue(null, "value"));
354 } else if ("min-password-length".equals(tag)) {
355 minimumPasswordLength = Integer.parseInt(
356 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700357 } else if ("password-history-length".equals(tag)) {
358 passwordHistoryLength = Integer.parseInt(
359 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700360 } else if ("min-password-uppercase".equals(tag)) {
361 minimumPasswordUpperCase = Integer.parseInt(
362 parser.getAttributeValue(null, "value"));
363 } else if ("min-password-lowercase".equals(tag)) {
364 minimumPasswordLowerCase = Integer.parseInt(
365 parser.getAttributeValue(null, "value"));
366 } else if ("min-password-letters".equals(tag)) {
367 minimumPasswordLetters = Integer.parseInt(
368 parser.getAttributeValue(null, "value"));
369 } else if ("min-password-numeric".equals(tag)) {
370 minimumPasswordNumeric = Integer.parseInt(
371 parser.getAttributeValue(null, "value"));
372 } else if ("min-password-symbols".equals(tag)) {
373 minimumPasswordSymbols = Integer.parseInt(
374 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700375 } else if ("min-password-nonletter".equals(tag)) {
376 minimumPasswordNonLetter = Integer.parseInt(
377 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800378 } else if ("max-time-to-unlock".equals(tag)) {
379 maximumTimeToUnlock = Long.parseLong(
380 parser.getAttributeValue(null, "value"));
381 } else if ("max-failed-password-wipe".equals(tag)) {
382 maximumFailedPasswordsForWipe = Integer.parseInt(
383 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700384 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800385 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700386 parser.getAttributeValue(null, "value"));
387 } else if ("global-proxy-spec".equals(tag)) {
388 globalProxySpec =
389 parser.getAttributeValue(null, "value");
390 } else if ("global-proxy-exclusion-list".equals(tag)) {
391 globalProxyExclusionList =
392 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800393 } else if ("password-expiration-timeout".equals(tag)) {
394 passwordExpirationTimeout = Long.parseLong(
395 parser.getAttributeValue(null, "value"));
396 } else if ("password-expiration-date".equals(tag)) {
397 passwordExpirationDate = Long.parseLong(
398 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800399 } else if ("encryption-requested".equals(tag)) {
400 encryptionRequested = Boolean.parseBoolean(
401 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700402 } else if ("disable-camera".equals(tag)) {
403 disableCamera = Boolean.parseBoolean(
404 parser.getAttributeValue(null, "value"));
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700405 } else if ("disable-keyguard-features".equals(tag)) {
406 disabledKeyguardFeatures = Integer.parseInt(
407 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800408 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700409 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800410 }
411 XmlUtils.skipCurrentTag(parser);
412 }
413 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700414
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800415 void dump(String prefix, PrintWriter pw) {
416 pw.print(prefix); pw.print("uid="); pw.println(getUid());
417 pw.print(prefix); pw.println("policies:");
418 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
419 if (pols != null) {
420 for (int i=0; i<pols.size(); i++) {
421 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
422 }
423 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700424 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700425 pw.println(Integer.toHexString(passwordQuality));
426 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800427 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700428 pw.print(prefix); pw.print("passwordHistoryLength=");
429 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700430 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
431 pw.println(minimumPasswordUpperCase);
432 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
433 pw.println(minimumPasswordLowerCase);
434 pw.print(prefix); pw.print("minimumPasswordLetters=");
435 pw.println(minimumPasswordLetters);
436 pw.print(prefix); pw.print("minimumPasswordNumeric=");
437 pw.println(minimumPasswordNumeric);
438 pw.print(prefix); pw.print("minimumPasswordSymbols=");
439 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700440 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
441 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800442 pw.print(prefix); pw.print("maximumTimeToUnlock=");
443 pw.println(maximumTimeToUnlock);
444 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
445 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700446 pw.print(prefix); pw.print("specifiesGlobalProxy=");
447 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800448 pw.print(prefix); pw.print("passwordExpirationTimeout=");
449 pw.println(passwordExpirationTimeout);
450 pw.print(prefix); pw.print("passwordExpirationDate=");
451 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700452 if (globalProxySpec != null) {
453 pw.print(prefix); pw.print("globalProxySpec=");
454 pw.println(globalProxySpec);
455 }
456 if (globalProxyExclusionList != null) {
457 pw.print(prefix); pw.print("globalProxyEclusionList=");
458 pw.println(globalProxyExclusionList);
459 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800460 pw.print(prefix); pw.print("encryptionRequested=");
461 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700462 pw.print(prefix); pw.print("disableCamera=");
463 pw.println(disableCamera);
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700464 pw.print(prefix); pw.print("disabledKeyguardFeatures=");
465 pw.println(disabledKeyguardFeatures);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800466 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800467 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700468
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700469 private void handlePackagesChanged(int userHandle) {
470 boolean removed = false;
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800471 if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700472 DevicePolicyData policy = getUserData(userHandle);
473 IPackageManager pm = AppGlobals.getPackageManager();
474 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
475 ActiveAdmin aa = policy.mAdminList.get(i);
476 try {
477 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
478 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
479 removed = true;
480 policy.mAdminList.remove(i);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800481 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700482 } catch (RemoteException re) {
483 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800484 }
485 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700486 if (removed) {
487 validatePasswordOwnerLocked(policy);
488 syncDeviceCapabilitiesLocked(policy);
489 saveSettingsLocked(policy.mUserHandle);
490 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800491 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700492
Dianne Hackbornd6847842010-01-12 18:14:19 -0800493 /**
494 * Instantiates the service.
495 */
496 public DevicePolicyManagerService(Context context) {
497 mContext = context;
Dianne Hackborn42499172010-10-15 18:45:07 -0700498 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
499 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800500 IntentFilter filter = new IntentFilter();
501 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
502 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700503 filter.addAction(Intent.ACTION_USER_REMOVED);
504 filter.addAction(Intent.ACTION_USER_STARTED);
505 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
506 filter = new IntentFilter();
507 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
508 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
509 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
510 filter.addDataScheme("package");
511 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
512 }
513
514 /**
515 * Creates and loads the policy data from xml.
516 * @param userHandle the user for whom to load the policy data
517 * @return
518 */
519 DevicePolicyData getUserData(int userHandle) {
520 synchronized (this) {
521 DevicePolicyData policy = mUserData.get(userHandle);
522 if (policy == null) {
523 policy = new DevicePolicyData(userHandle);
524 mUserData.append(userHandle, policy);
525 loadSettingsLocked(policy, userHandle);
526 }
527 return policy;
528 }
529 }
530
531 void removeUserData(int userHandle) {
532 synchronized (this) {
533 if (userHandle == UserHandle.USER_OWNER) {
534 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
535 return;
536 }
537 DevicePolicyData policy = mUserData.get(userHandle);
538 if (policy != null) {
539 mUserData.remove(userHandle);
540 }
541 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
542 DEVICE_POLICIES_XML);
543 policyFile.delete();
544 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
545 }
Jim Millera4e28d12010-11-08 16:15:47 -0800546 }
547
Andy Stadler043116a2010-11-29 17:43:32 -0800548 /**
549 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
550 * reminders. Clears alarm if no expirations are configured.
551 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700552 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
553 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800554 final long now = System.currentTimeMillis();
555 final long timeToExpire = expiration - now;
556 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800557 if (expiration == 0) {
558 // No expirations are currently configured: Cancel alarm.
559 alarmTime = 0;
560 } else if (timeToExpire <= 0) {
561 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800562 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800563 } else {
564 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
565 // the expiration time.
566 long alarmInterval = timeToExpire % MS_PER_DAY;
567 if (alarmInterval == 0) {
568 alarmInterval = MS_PER_DAY;
569 }
570 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800571 }
572
Andy Stadler1f35d482010-11-19 15:39:41 -0800573 long token = Binder.clearCallingIdentity();
574 try {
575 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700576 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800577 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700578 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
579 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800580 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800581 if (alarmTime != 0) {
582 am.set(AlarmManager.RTC, alarmTime, pi);
583 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800584 } finally {
585 Binder.restoreCallingIdentity(token);
586 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800587 }
588
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800589 private IPowerManager getIPowerManager() {
590 if (mIPowerManager == null) {
591 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
592 mIPowerManager = IPowerManager.Stub.asInterface(b);
593 }
594 return mIPowerManager;
595 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700596
Jim Miller93c518e2012-01-17 15:55:31 -0800597 private IWindowManager getWindowManager() {
598 if (mIWindowManager == null) {
599 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
600 mIWindowManager = IWindowManager.Stub.asInterface(b);
601 }
602 return mIWindowManager;
603 }
604
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700605 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
606 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800607 if (admin != null
608 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
609 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
610 return admin;
611 }
612 return null;
613 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700614
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800615 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
616 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800617 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700618 final int userHandle = UserHandle.getUserId(callingUid);
619 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800620 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700621 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800622 if (admin == null) {
623 throw new SecurityException("No active admin " + who);
624 }
625 if (admin.getUid() != callingUid) {
626 throw new SecurityException("Admin " + who + " is not owned by uid "
627 + Binder.getCallingUid());
628 }
629 if (!admin.info.usesPolicy(reqPolicy)) {
630 throw new SecurityException("Admin " + admin.info.getComponent()
631 + " did not specify uses-policy for: "
632 + admin.info.getTagForPolicy(reqPolicy));
633 }
634 return admin;
635 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700636 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800637 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700638 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800639 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
640 return admin;
641 }
642 }
643 throw new SecurityException("No active admin owned by uid "
644 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800645 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800646 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700647
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800648 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700649 sendAdminCommandLocked(admin, action, null);
650 }
651
652 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800653 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800654 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800655 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
656 intent.putExtra("expiration", admin.passwordExpirationDate);
657 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700658 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700659 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700660 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700661 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700662 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700663 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800664 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700665
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700666 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
667 final DevicePolicyData policy = getUserData(userHandle);
668 final int count = policy.mAdminList.size();
669 if (count > 0) {
670 for (int i = 0; i < count; i++) {
671 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800672 if (admin.info.usesPolicy(reqPolicy)) {
673 sendAdminCommandLocked(admin, action);
674 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800675 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800676 }
677 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700678
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700679 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
680 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800681 if (admin != null) {
682 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700683 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
684 new BroadcastReceiver() {
685 @Override
686 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700687 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700688 int userHandle = admin.getUserHandle().getIdentifier();
689 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700690 boolean doProxyCleanup = admin.info.usesPolicy(
691 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700692 policy.mAdminList.remove(admin);
693 policy.mAdminMap.remove(adminReceiver);
694 validatePasswordOwnerLocked(policy);
695 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700696 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700697 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700698 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700699 saveSettingsLocked(userHandle);
700 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700701 }
702 }
703 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800704 }
705 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700706
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700707 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
708 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800709 Intent resolveIntent = new Intent();
710 resolveIntent.setComponent(adminName);
711 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700712 resolveIntent, PackageManager.GET_META_DATA, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800713 if (infos == null || infos.size() <= 0) {
714 throw new IllegalArgumentException("Unknown admin: " + adminName);
715 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700716
Dianne Hackbornd6847842010-01-12 18:14:19 -0800717 try {
718 return new DeviceAdminInfo(mContext, infos.get(0));
719 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700720 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800721 return null;
722 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700723 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800724 return null;
725 }
726 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700727
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700728 private static JournaledFile makeJournaledFile(int userHandle) {
729 final String base = userHandle == 0
730 ? "/data/system/" + DEVICE_POLICIES_XML
731 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
732 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800733 return new JournaledFile(new File(base), new File(base + ".tmp"));
734 }
735
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700736 private void saveSettingsLocked(int userHandle) {
737 DevicePolicyData policy = getUserData(userHandle);
738 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800739 FileOutputStream stream = null;
740 try {
741 stream = new FileOutputStream(journal.chooseForWrite(), false);
742 XmlSerializer out = new FastXmlSerializer();
743 out.setOutput(stream, "utf-8");
744 out.startDocument(null, true);
745
746 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700747
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700748 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800749 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700750 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800751 if (ap != null) {
752 out.startTag(null, "admin");
753 out.attribute(null, "name", ap.info.getComponent().flattenToString());
754 ap.writeToXml(out);
755 out.endTag(null, "admin");
756 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800757 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700758
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700759 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800760 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700761 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800762 out.endTag(null, "password-owner");
763 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700764
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700765 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800766 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700767 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800768 out.endTag(null, "failed-password-attempts");
769 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700770
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700771 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
772 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
773 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
774 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700775 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700776 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
777 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
778 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
779 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
780 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700781 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700782 .toString(policy.mActivePasswordNumeric));
783 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
784 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700785 out.endTag(null, "active-password");
786 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700787
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700788 out.endTag(null, "policies");
789
Dianne Hackbornd6847842010-01-12 18:14:19 -0800790 out.endDocument();
791 stream.close();
792 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700793 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800794 } catch (IOException e) {
795 try {
796 if (stream != null) {
797 stream.close();
798 }
799 } catch (IOException ex) {
800 // Ignore
801 }
802 journal.rollback();
803 }
804 }
805
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700806 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700807 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
808 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700809 long ident = Binder.clearCallingIdentity();
810 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700811 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700812 } finally {
813 Binder.restoreCallingIdentity(ident);
814 }
Jim Miller284b62e2010-06-08 14:27:42 -0700815 }
816
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700817 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
818 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800819 FileInputStream stream = null;
820 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800821 try {
822 stream = new FileInputStream(file);
823 XmlPullParser parser = Xml.newPullParser();
824 parser.setInput(stream, null);
825
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800826 int type;
827 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
828 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800829 }
830 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800831 if (!"policies".equals(tag)) {
832 throw new XmlPullParserException(
833 "Settings do not start with policies tag: found " + tag);
834 }
835 type = parser.next();
836 int outerDepth = parser.getDepth();
837 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
838 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
839 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
840 continue;
841 }
842 tag = parser.getName();
843 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800844 String name = parser.getAttributeValue(null, "name");
845 try {
846 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700847 ComponentName.unflattenFromString(name), userHandle);
848 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
849 != userHandle)) {
850 Slog.w(TAG, "findAdmin returned an incorrect uid "
851 + dai.getActivityInfo().applicationInfo.uid + " for user "
852 + userHandle);
853 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800854 if (dai != null) {
855 ActiveAdmin ap = new ActiveAdmin(dai);
856 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700857 policy.mAdminMap.put(ap.info.getComponent(), ap);
858 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800859 }
860 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700861 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800862 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800863 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700864 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800865 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800866 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800867 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700868 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800869 parser.getAttributeValue(null, "value"));
870 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700871 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700872 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700873 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700874 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700875 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700876 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700877 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700878 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700879 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700880 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700881 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700882 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700883 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700884 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700885 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700886 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700887 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700888 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800889 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700890 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800891 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800892 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800893 }
894 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700895 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800896 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700897 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800898 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700899 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700900 } catch (FileNotFoundException e) {
901 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800902 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700903 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800904 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700905 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800906 }
907 try {
908 if (stream != null) {
909 stream.close();
910 }
911 } catch (IOException e) {
912 // Ignore
913 }
914
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700915 // Validate that what we stored for the password quality matches
916 // sufficiently what is currently set. Note that this is only
917 // a sanity check in case the two get out of sync; this should
918 // never normally happen.
919 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700920 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700921 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700922 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700923 + " does not match actual quality 0x"
924 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700925 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
926 policy.mActivePasswordLength = 0;
927 policy.mActivePasswordUpperCase = 0;
928 policy.mActivePasswordLowerCase = 0;
929 policy.mActivePasswordLetters = 0;
930 policy.mActivePasswordNumeric = 0;
931 policy.mActivePasswordSymbols = 0;
932 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700933 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700934
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700935 validatePasswordOwnerLocked(policy);
936 syncDeviceCapabilitiesLocked(policy);
937 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800938 }
939
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700940 static void validateQualityConstant(int quality) {
941 switch (quality) {
942 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500943 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700944 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
945 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
946 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
947 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700948 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700949 return;
950 }
951 throw new IllegalArgumentException("Invalid quality constant: 0x"
952 + Integer.toHexString(quality));
953 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700954
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700955 void validatePasswordOwnerLocked(DevicePolicyData policy) {
956 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800957 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700958 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
959 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800960 haveOwner = true;
961 break;
962 }
963 }
964 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700965 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800966 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700967 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800968 }
969 }
970 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700971
Ben Komalo2447edd2011-05-09 16:05:33 -0700972 /**
973 * Pushes down policy information to the system for any policies related to general device
974 * capabilities that need to be enforced by lower level services (e.g. Camera services).
975 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700976 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -0700977 // Ensure the status of the camera is synced down to the system. Interested native services
978 // should monitor this value and act accordingly.
979 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700980 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -0700981 if (cameraDisabled != systemState) {
982 long token = Binder.clearCallingIdentity();
983 try {
984 String value = cameraDisabled ? "1" : "0";
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800985 if (DBG) Slog.v(TAG, "Change in camera state ["
Ben Komalo2447edd2011-05-09 16:05:33 -0700986 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
987 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
988 } finally {
989 Binder.restoreCallingIdentity(token);
990 }
991 }
992 }
993
Dianne Hackbornd6847842010-01-12 18:14:19 -0800994 public void systemReady() {
995 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700996 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800997 }
998 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700999
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001000 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -08001001 synchronized (this) {
1002 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001003 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001004 if (N <= 0) {
1005 return;
1006 }
1007 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001008 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001009 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1010 && admin.passwordExpirationTimeout > 0L
1011 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001012 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001013 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1014 }
1015 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001016 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001017 }
1018 }
1019
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001020 /**
1021 * @param adminReceiver The admin to add
1022 * @param refreshing true = update an active admin, no error
1023 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001024 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001025 mContext.enforceCallingOrSelfPermission(
1026 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001027 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001028
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001029 DevicePolicyData policy = getUserData(userHandle);
1030 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001031 if (info == null) {
1032 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1033 }
1034 synchronized (this) {
1035 long ident = Binder.clearCallingIdentity();
1036 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001037 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001038 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001039 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001040 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001041 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001042 int replaceIndex = -1;
1043 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001044 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001045 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001046 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001047 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1048 replaceIndex = i;
1049 break;
1050 }
1051 }
1052 }
1053 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001054 policy.mAdminList.add(newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001055 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001056 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001057 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001058 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001059 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001060 } finally {
1061 Binder.restoreCallingIdentity(ident);
1062 }
1063 }
1064 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001065
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001066 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
1067 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001068 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001069 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001070 }
1071 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001072
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001073 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
1074 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001075 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001076 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001077 if (administrator == null) {
1078 throw new SecurityException("No active admin " + adminReceiver);
1079 }
1080 return administrator.info.usesPolicy(policyId);
1081 }
1082 }
1083
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001084 public List<ComponentName> getActiveAdmins(int userHandle) {
1085 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001086 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001087 DevicePolicyData policy = getUserData(userHandle);
1088 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001089 if (N <= 0) {
1090 return null;
1091 }
1092 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1093 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001094 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001095 }
1096 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001097 }
1098 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001099
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001100 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
1101 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001102 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001103 DevicePolicyData policy = getUserData(userHandle);
1104 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001105 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001106 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001107 return true;
1108 }
1109 }
1110 return false;
1111 }
1112 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001113
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001114 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
1115 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001116 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001117 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001118 if (admin == null) {
1119 return;
1120 }
1121 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001122 mContext.enforceCallingOrSelfPermission(
1123 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1124 }
1125 long ident = Binder.clearCallingIdentity();
1126 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001127 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001128 } finally {
1129 Binder.restoreCallingIdentity(ident);
1130 }
1131 }
1132 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001133
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001134 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001135 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001136 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001137
Dianne Hackbornd6847842010-01-12 18:14:19 -08001138 synchronized (this) {
1139 if (who == null) {
1140 throw new NullPointerException("ComponentName is null");
1141 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001142 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1143 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001144 if (ap.passwordQuality != quality) {
1145 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001146 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001147 }
1148 }
1149 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001150
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001151 public int getPasswordQuality(ComponentName who, int userHandle) {
1152 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001153 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001154 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001155 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001156
Dianne Hackborn254cb442010-01-27 19:23:59 -08001157 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001158 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001159 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001160 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001161
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001162 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001163 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001164 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001165 if (mode < admin.passwordQuality) {
1166 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001167 }
1168 }
1169 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001170 }
1171 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001172
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001173 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
1174 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001175 synchronized (this) {
1176 if (who == null) {
1177 throw new NullPointerException("ComponentName is null");
1178 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001179 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1180 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001181 if (ap.minimumPasswordLength != length) {
1182 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001183 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001184 }
1185 }
1186 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001187
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001188 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
1189 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001190 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001191 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001192 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001193
Dianne Hackborn254cb442010-01-27 19:23:59 -08001194 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001195 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001196 return admin != null ? admin.minimumPasswordLength : length;
1197 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001198
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001199 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001200 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001201 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001202 if (length < admin.minimumPasswordLength) {
1203 length = admin.minimumPasswordLength;
1204 }
1205 }
1206 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001207 }
1208 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001209
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001210 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
1211 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001212 synchronized (this) {
1213 if (who == null) {
1214 throw new NullPointerException("ComponentName is null");
1215 }
1216 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1217 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1218 if (ap.passwordHistoryLength != length) {
1219 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001220 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001221 }
1222 }
1223 }
1224
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001225 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
1226 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001227 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001228 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001229 int length = 0;
1230
1231 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001232 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001233 return admin != null ? admin.passwordHistoryLength : length;
1234 }
1235
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001236 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001237 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001238 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001239 if (length < admin.passwordHistoryLength) {
1240 length = admin.passwordHistoryLength;
1241 }
1242 }
1243 return length;
1244 }
1245 }
1246
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001247 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
1248 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001249 synchronized (this) {
1250 if (who == null) {
1251 throw new NullPointerException("ComponentName is null");
1252 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001253 if (timeout < 0) {
1254 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001255 }
1256 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1257 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1258 // Calling this API automatically bumps the expiration date
1259 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1260 ap.passwordExpirationDate = expiration;
1261 ap.passwordExpirationTimeout = timeout;
1262 if (timeout > 0L) {
1263 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1264 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1265 .format(new Date(expiration)));
1266 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001267 saveSettingsLocked(userHandle);
1268 // in case this is the first one
1269 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001270 }
1271 }
1272
Andy Stadler043116a2010-11-29 17:43:32 -08001273 /**
1274 * Return a single admin's expiration cycle time, or the min of all cycle times.
1275 * Returns 0 if not configured.
1276 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001277 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
1278 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001279 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001280 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001281 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001282 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001283 }
1284
Andy Stadler043116a2010-11-29 17:43:32 -08001285 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001286 DevicePolicyData policy = getUserData(userHandle);
1287 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001288 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001289 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001290 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1291 && timeout > admin.passwordExpirationTimeout)) {
1292 timeout = admin.passwordExpirationTimeout;
1293 }
1294 }
1295 return timeout;
1296 }
1297 }
1298
Andy Stadler043116a2010-11-29 17:43:32 -08001299 /**
1300 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1301 * Returns 0 if not configured.
1302 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001303 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001304 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001305 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001306 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001307 }
1308
Andy Stadler043116a2010-11-29 17:43:32 -08001309 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001310 DevicePolicyData policy = getUserData(userHandle);
1311 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001312 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001313 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001314 if (timeout == 0L || (admin.passwordExpirationDate != 0
1315 && timeout > admin.passwordExpirationDate)) {
1316 timeout = admin.passwordExpirationDate;
1317 }
1318 }
1319 return timeout;
1320 }
1321
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001322 public long getPasswordExpiration(ComponentName who, int userHandle) {
1323 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001324 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001325 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001326 }
1327 }
1328
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001329 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
1330 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001331 synchronized (this) {
1332 if (who == null) {
1333 throw new NullPointerException("ComponentName is null");
1334 }
1335 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1336 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1337 if (ap.minimumPasswordUpperCase != length) {
1338 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001339 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001340 }
1341 }
1342 }
1343
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001344 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
1345 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001346 synchronized (this) {
1347 int length = 0;
1348
1349 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001350 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001351 return admin != null ? admin.minimumPasswordUpperCase : length;
1352 }
1353
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001354 DevicePolicyData policy = getUserData(userHandle);
1355 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001356 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001357 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001358 if (length < admin.minimumPasswordUpperCase) {
1359 length = admin.minimumPasswordUpperCase;
1360 }
1361 }
1362 return length;
1363 }
1364 }
1365
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001366 public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
1367 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001368 synchronized (this) {
1369 if (who == null) {
1370 throw new NullPointerException("ComponentName is null");
1371 }
1372 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1373 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1374 if (ap.minimumPasswordLowerCase != length) {
1375 ap.minimumPasswordLowerCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001376 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001377 }
1378 }
1379 }
1380
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001381 public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
1382 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001383 synchronized (this) {
1384 int length = 0;
1385
1386 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001387 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001388 return admin != null ? admin.minimumPasswordLowerCase : length;
1389 }
1390
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001391 DevicePolicyData policy = getUserData(userHandle);
1392 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001393 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001394 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001395 if (length < admin.minimumPasswordLowerCase) {
1396 length = admin.minimumPasswordLowerCase;
1397 }
1398 }
1399 return length;
1400 }
1401 }
1402
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001403 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
1404 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001405 synchronized (this) {
1406 if (who == null) {
1407 throw new NullPointerException("ComponentName is null");
1408 }
1409 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1410 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1411 if (ap.minimumPasswordLetters != length) {
1412 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001413 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001414 }
1415 }
1416 }
1417
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001418 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
1419 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001420 synchronized (this) {
1421 int length = 0;
1422
1423 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001424 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001425 return admin != null ? admin.minimumPasswordLetters : length;
1426 }
1427
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001428 DevicePolicyData policy = getUserData(userHandle);
1429 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001430 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001431 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001432 if (length < admin.minimumPasswordLetters) {
1433 length = admin.minimumPasswordLetters;
1434 }
1435 }
1436 return length;
1437 }
1438 }
1439
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001440 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
1441 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001442 synchronized (this) {
1443 if (who == null) {
1444 throw new NullPointerException("ComponentName is null");
1445 }
1446 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1447 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1448 if (ap.minimumPasswordNumeric != length) {
1449 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001450 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001451 }
1452 }
1453 }
1454
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001455 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
1456 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001457 synchronized (this) {
1458 int length = 0;
1459
1460 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001461 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001462 return admin != null ? admin.minimumPasswordNumeric : length;
1463 }
1464
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001465 DevicePolicyData policy = getUserData(userHandle);
1466 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001467 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001468 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001469 if (length < admin.minimumPasswordNumeric) {
1470 length = admin.minimumPasswordNumeric;
1471 }
1472 }
1473 return length;
1474 }
1475 }
1476
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001477 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
1478 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001479 synchronized (this) {
1480 if (who == null) {
1481 throw new NullPointerException("ComponentName is null");
1482 }
1483 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1484 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1485 if (ap.minimumPasswordSymbols != length) {
1486 ap.minimumPasswordSymbols = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001487 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001488 }
1489 }
1490 }
1491
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001492 public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
1493 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001494 synchronized (this) {
1495 int length = 0;
1496
1497 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001498 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001499 return admin != null ? admin.minimumPasswordSymbols : length;
1500 }
1501
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001502 DevicePolicyData policy = getUserData(userHandle);
1503 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001504 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001505 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001506 if (length < admin.minimumPasswordSymbols) {
1507 length = admin.minimumPasswordSymbols;
1508 }
1509 }
1510 return length;
1511 }
1512 }
1513
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001514 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
1515 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001516 synchronized (this) {
1517 if (who == null) {
1518 throw new NullPointerException("ComponentName is null");
1519 }
1520 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1521 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1522 if (ap.minimumPasswordNonLetter != length) {
1523 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001524 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001525 }
1526 }
1527 }
1528
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001529 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
1530 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001531 synchronized (this) {
1532 int length = 0;
1533
1534 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001535 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001536 return admin != null ? admin.minimumPasswordNonLetter : length;
1537 }
1538
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001539 DevicePolicyData policy = getUserData(userHandle);
1540 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001541 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001542 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001543 if (length < admin.minimumPasswordNonLetter) {
1544 length = admin.minimumPasswordNonLetter;
1545 }
1546 }
1547 return length;
1548 }
1549 }
1550
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001551 public boolean isActivePasswordSufficient(int userHandle) {
1552 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001553 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001554 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001555 // This API can only be called by an active device admin,
1556 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001557 getActiveAdminForCallerLocked(null,
1558 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001559 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1560 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001561 return false;
1562 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001563 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001564 return true;
1565 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001566 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1567 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1568 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1569 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1570 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1571 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001572 }
1573 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001574
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001575 public int getCurrentFailedPasswordAttempts(int userHandle) {
1576 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001577 synchronized (this) {
1578 // This API can only be called by an active device admin,
1579 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001580 getActiveAdminForCallerLocked(null,
1581 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001582 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001583 }
1584 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001585
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001586 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
1587 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001588 synchronized (this) {
1589 // This API can only be called by an active device admin,
1590 // so try to retrieve it to check that the caller is one.
1591 getActiveAdminForCallerLocked(who,
1592 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1593 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1594 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1595 if (ap.maximumFailedPasswordsForWipe != num) {
1596 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001597 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001598 }
1599 }
1600 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001601
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001602 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
1603 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001604 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001605 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001606 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001607
Dianne Hackborn254cb442010-01-27 19:23:59 -08001608 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001609 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001610 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1611 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001612
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001613 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001614 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001615 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001616 if (count == 0) {
1617 count = admin.maximumFailedPasswordsForWipe;
1618 } else if (admin.maximumFailedPasswordsForWipe != 0
1619 && count > admin.maximumFailedPasswordsForWipe) {
1620 count = admin.maximumFailedPasswordsForWipe;
1621 }
1622 }
1623 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001624 }
1625 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001626
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001627 public boolean resetPassword(String password, int flags, int userHandle) {
1628 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001629 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001630 synchronized (this) {
1631 // This API can only be called by an active device admin,
1632 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001633 getActiveAdminForCallerLocked(null,
1634 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001635 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001636 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001637 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001638 if (realQuality < quality
1639 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001640 Slog.w(TAG, "resetPassword: password quality 0x"
1641 + Integer.toHexString(quality)
1642 + " does not meet required quality 0x"
1643 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001644 return false;
1645 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001646 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001647 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001648 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001649 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001650 Slog.w(TAG, "resetPassword: password length " + password.length()
1651 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001652 return false;
1653 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001654 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1655 int letters = 0;
1656 int uppercase = 0;
1657 int lowercase = 0;
1658 int numbers = 0;
1659 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001660 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001661 for (int i = 0; i < password.length(); i++) {
1662 char c = password.charAt(i);
1663 if (c >= 'A' && c <= 'Z') {
1664 letters++;
1665 uppercase++;
1666 } else if (c >= 'a' && c <= 'z') {
1667 letters++;
1668 lowercase++;
1669 } else if (c >= '0' && c <= '9') {
1670 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001671 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001672 } else {
1673 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001674 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001675 }
1676 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001677 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001678 if(letters < neededLetters) {
1679 Slog.w(TAG, "resetPassword: number of letters " + letters
1680 + " does not meet required number of letters " + neededLetters);
1681 return false;
1682 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001683 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001684 if (numbers < neededNumbers) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001685 Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
1686 + " does not meet required number of numerical digits "
1687 + neededNumbers);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001688 return false;
1689 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001690 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001691 if (lowercase < neededLowerCase) {
1692 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1693 + " does not meet required number of lowercase letters "
1694 + neededLowerCase);
1695 return false;
1696 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001697 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001698 if (uppercase < neededUpperCase) {
1699 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1700 + " does not meet required number of uppercase letters "
1701 + neededUpperCase);
1702 return false;
1703 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001704 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001705 if (symbols < neededSymbols) {
1706 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1707 + " does not meet required number of special symbols " + neededSymbols);
1708 return false;
1709 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001710 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001711 if (nonletter < neededNonLetter) {
1712 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1713 + " does not meet required number of non-letter characters "
1714 + neededNonLetter);
1715 return false;
1716 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001717 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001718 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001719
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001720 int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001721 DevicePolicyData policy = getUserData(userHandle);
1722 if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001723 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001724 return false;
1725 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001726
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001727 // Don't do this with the lock held, because it is going to call
1728 // back in to the service.
1729 long ident = Binder.clearCallingIdentity();
1730 try {
1731 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001732 utils.saveLockPassword(password, quality, false, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001733 synchronized (this) {
1734 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1735 != 0 ? callingUid : -1;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001736 if (policy.mPasswordOwner != newOwner) {
1737 policy.mPasswordOwner = newOwner;
1738 saveSettingsLocked(userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001739 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001740 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001741 } finally {
1742 Binder.restoreCallingIdentity(ident);
1743 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001744
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001745 return true;
1746 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001747
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001748 public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
1749 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001750 synchronized (this) {
1751 if (who == null) {
1752 throw new NullPointerException("ComponentName is null");
1753 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001754 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001755 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001756 if (ap.maximumTimeToUnlock != timeMs) {
1757 ap.maximumTimeToUnlock = timeMs;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001758 saveSettingsLocked(userHandle);
1759 updateMaximumTimeToLockLocked(getUserData(userHandle));
Dianne Hackbornd6847842010-01-12 18:14:19 -08001760 }
1761 }
1762 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001763
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001764 void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
1765 long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
1766 if (policy.mLastMaximumTimeToLock == timeMs) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001767 return;
1768 }
1769
1770 long ident = Binder.clearCallingIdentity();
1771 try {
1772 if (timeMs <= 0) {
1773 timeMs = Integer.MAX_VALUE;
1774 } else {
1775 // Make sure KEEP_SCREEN_ON is disabled, since that
1776 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07001777 Settings.Global.putInt(mContext.getContentResolver(),
1778 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001779 }
1780
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001781 policy.mLastMaximumTimeToLock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001782
1783 try {
Jeff Brown96307042012-07-27 15:51:34 -07001784 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001785 } catch (RemoteException e) {
1786 Slog.w(TAG, "Failure talking with power manager", e);
1787 }
1788 } finally {
1789 Binder.restoreCallingIdentity(ident);
1790 }
1791 }
1792
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001793 public long getMaximumTimeToLock(ComponentName who, int userHandle) {
1794 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001795 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001796 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001797
Dianne Hackborn254cb442010-01-27 19:23:59 -08001798 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001799 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001800 return admin != null ? admin.maximumTimeToUnlock : time;
1801 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001802
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001803 DevicePolicyData policy = getUserData(userHandle);
1804 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001805 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001806 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001807 if (time == 0) {
1808 time = admin.maximumTimeToUnlock;
1809 } else if (admin.maximumTimeToUnlock != 0
1810 && time > admin.maximumTimeToUnlock) {
1811 time = admin.maximumTimeToUnlock;
1812 }
1813 }
1814 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001815 }
1816 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001817
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001818 public void lockNow() {
1819 synchronized (this) {
1820 // This API can only be called by an active device admin,
1821 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001822 getActiveAdminForCallerLocked(null,
1823 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001824 lockNowUnchecked();
1825 }
1826 }
1827
1828 private void lockNowUnchecked() {
1829 long ident = Binder.clearCallingIdentity();
1830 try {
1831 // Power off the display
1832 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1833 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
1834 // Ensure the device is locked
Adam Cohenf7522022012-10-03 20:03:18 -07001835 getWindowManager().lockNow(null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001836 } catch (RemoteException e) {
1837 } finally {
1838 Binder.restoreCallingIdentity(ident);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001839 }
1840 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001841
Ben Komaloed48c8b2011-10-17 17:30:21 -07001842 private boolean isExtStorageEncrypted() {
1843 String state = SystemProperties.get("vold.decrypt");
1844 return !"".equals(state);
1845 }
1846
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001847 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001848 // If the SD card is encrypted and non-removable, we have to force a wipe.
1849 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1850 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1851
1852 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1853 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001854 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001855 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001856 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1857 mWakeLock.acquire(10000);
1858 mContext.startService(intent);
1859 } else {
1860 try {
1861 RecoverySystem.rebootWipeUserData(mContext);
1862 } catch (IOException e) {
1863 Slog.w(TAG, "Failed requesting data wipe", e);
1864 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001865 }
1866 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001867
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001868 public void wipeData(int flags, final int userHandle) {
1869 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001870 synchronized (this) {
1871 // This API can only be called by an active device admin,
1872 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001873 getActiveAdminForCallerLocked(null,
1874 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001875 long ident = Binder.clearCallingIdentity();
1876 try {
Amith Yamasani32f07422012-11-16 15:09:13 -08001877 wipeDeviceOrUserLocked(flags, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001878 } finally {
1879 Binder.restoreCallingIdentity(ident);
1880 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001881 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001882 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001883
Amith Yamasani32f07422012-11-16 15:09:13 -08001884 private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
1885 if (userHandle == UserHandle.USER_OWNER) {
1886 wipeDataLocked(flags);
1887 } else {
1888 lockNowUnchecked();
1889 mHandler.post(new Runnable() {
1890 public void run() {
1891 try {
1892 ActivityManagerNative.getDefault().switchUser(0);
1893 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
1894 .removeUser(userHandle);
1895 } catch (RemoteException re) {
1896 // Shouldn't happen
1897 }
1898 }
1899 });
1900 }
1901 }
1902
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001903 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
1904 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001905 mContext.enforceCallingOrSelfPermission(
1906 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001907
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001908 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001909 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001910 if (admin == null) {
1911 try {
1912 result.sendResult(null);
1913 } catch (RemoteException e) {
1914 }
1915 return;
1916 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001917 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001918 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001919 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001920 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001921 @Override
1922 public void onReceive(Context context, Intent intent) {
1923 try {
1924 result.sendResult(getResultExtras(false));
1925 } catch (RemoteException e) {
1926 }
1927 }
1928 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001929 }
1930 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001931
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001932 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001933 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
1934 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001935 mContext.enforceCallingOrSelfPermission(
1936 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001937 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001938
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001939 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001940
Dianne Hackbornd6847842010-01-12 18:14:19 -08001941 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001942 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
1943 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
1944 || p.mActivePasswordUpperCase != uppercase
1945 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
1946 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001947 long ident = Binder.clearCallingIdentity();
1948 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001949 p.mActivePasswordQuality = quality;
1950 p.mActivePasswordLength = length;
1951 p.mActivePasswordLetters = letters;
1952 p.mActivePasswordLowerCase = lowercase;
1953 p.mActivePasswordUpperCase = uppercase;
1954 p.mActivePasswordNumeric = numbers;
1955 p.mActivePasswordSymbols = symbols;
1956 p.mActivePasswordNonLetter = nonletter;
1957 p.mFailedPasswordAttempts = 0;
1958 saveSettingsLocked(userHandle);
1959 updatePasswordExpirationsLocked(userHandle);
1960 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001961 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001962 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001963 } finally {
1964 Binder.restoreCallingIdentity(ident);
1965 }
1966 }
1967 }
1968 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001969
Andy Stadler043116a2010-11-29 17:43:32 -08001970 /**
1971 * Called any time the device password is updated. Resets all password expiration clocks.
1972 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001973 private void updatePasswordExpirationsLocked(int userHandle) {
1974 DevicePolicyData policy = getUserData(userHandle);
1975 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001976 if (N > 0) {
1977 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001978 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001979 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001980 long timeout = admin.passwordExpirationTimeout;
1981 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1982 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001983 }
1984 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001985 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001986 }
1987 }
1988
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001989 public void reportFailedPasswordAttempt(int userHandle) {
1990 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001991 mContext.enforceCallingOrSelfPermission(
1992 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001993
Dianne Hackbornd6847842010-01-12 18:14:19 -08001994 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001995 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001996 long ident = Binder.clearCallingIdentity();
1997 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001998 policy.mFailedPasswordAttempts++;
1999 saveSettingsLocked(userHandle);
2000 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
2001 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
Amith Yamasani32f07422012-11-16 15:09:13 -08002002 wipeDeviceOrUserLocked(0, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002003 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002004 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002005 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002006 } finally {
2007 Binder.restoreCallingIdentity(ident);
2008 }
2009 }
2010 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002011
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002012 public void reportSuccessfulPasswordAttempt(int userHandle) {
2013 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002014 mContext.enforceCallingOrSelfPermission(
2015 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002016
Dianne Hackbornd6847842010-01-12 18:14:19 -08002017 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002018 DevicePolicyData policy = getUserData(userHandle);
2019 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002020 long ident = Binder.clearCallingIdentity();
2021 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002022 policy.mFailedPasswordAttempts = 0;
2023 policy.mPasswordOwner = -1;
2024 saveSettingsLocked(userHandle);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002025 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002026 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002027 } finally {
2028 Binder.restoreCallingIdentity(ident);
2029 }
2030 }
2031 }
2032 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002033
Oscar Montemayor69238c62010-08-03 10:51:06 -07002034 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002035 String exclusionList, int userHandle) {
2036 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002037 synchronized(this) {
2038 if (who == null) {
2039 throw new NullPointerException("ComponentName is null");
2040 }
2041
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002042 // Only check if owner has set global proxy. We don't allow other users to set it.
2043 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002044 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2045 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2046
2047 // Scan through active admins and find if anyone has already
2048 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002049 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002050 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002051 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002052 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2053 // Another admin already sets the global proxy
2054 // Return it to the caller.
2055 return component;
2056 }
2057 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002058
2059 // If the user is not the owner, don't set the global proxy. Fail silently.
2060 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2061 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2062 + userHandle + " is not permitted.");
2063 return null;
2064 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002065 if (proxySpec == null) {
2066 admin.specifiesGlobalProxy = false;
2067 admin.globalProxySpec = null;
2068 admin.globalProxyExclusionList = null;
2069 } else {
2070
2071 admin.specifiesGlobalProxy = true;
2072 admin.globalProxySpec = proxySpec;
2073 admin.globalProxyExclusionList = exclusionList;
2074 }
2075
2076 // Reset the global proxy accordingly
2077 // Do this using system permissions, as apps cannot write to secure settings
2078 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002079 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002080 Binder.restoreCallingIdentity(origId);
2081 return null;
2082 }
2083 }
2084
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002085 public ComponentName getGlobalProxyAdmin(int userHandle) {
2086 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002087 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002088 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002089 // Scan through active admins and find if anyone has already
2090 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002091 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002092 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002093 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002094 if (ap.specifiesGlobalProxy) {
2095 // Device admin sets the global proxy
2096 // Return it to the caller.
2097 return ap.info.getComponent();
2098 }
2099 }
2100 }
2101 // No device admin sets the global proxy.
2102 return null;
2103 }
2104
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002105 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2106 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002107 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002108 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002109 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002110 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002111 return;
2112 }
2113 }
2114 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002115 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002116 }
2117
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002118 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002119 if (exclusionList == null) {
2120 exclusionList = "";
2121 }
2122 if (proxySpec == null) {
2123 proxySpec = "";
2124 }
2125 // Remove white spaces
2126 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002127 String data[] = proxySpec.split(":");
2128 int proxyPort = 8080;
2129 if (data.length > 1) {
2130 try {
2131 proxyPort = Integer.parseInt(data[1]);
2132 } catch (NumberFormatException e) {}
2133 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002134 exclusionList = exclusionList.trim();
2135 ContentResolver res = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -07002136 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
2137 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2138 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwalt434203a2010-10-11 16:00:27 -07002139 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002140 }
2141
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002142 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002143 * Set the storage encryption request for a single admin. Returns the new total request
2144 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002145 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002146 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
2147 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002148 synchronized (this) {
2149 // Check for permissions
2150 if (who == null) {
2151 throw new NullPointerException("ComponentName is null");
2152 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002153 // Only owner can set storage encryption
2154 if (userHandle != UserHandle.USER_OWNER
2155 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2156 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2157 + UserHandle.getCallingUserId() + " is not permitted.");
2158 return 0;
2159 }
2160
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002161 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2162 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2163
Andy Stadler22dbfda2011-01-17 12:47:31 -08002164 // Quick exit: If the filesystem does not support encryption, we can exit early.
2165 if (!isEncryptionSupported()) {
2166 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2167 }
2168
2169 // (1) Record the value for the admin so it's sticky
2170 if (ap.encryptionRequested != encrypt) {
2171 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002172 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002173 }
2174
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002175 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002176 // (2) Compute "max" for all admins
2177 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002178 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002179 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002180 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002181 }
2182
2183 // Notify OS of new request
2184 setEncryptionRequested(newRequested);
2185
2186 // Return the new global request status
2187 return newRequested
2188 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2189 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002190 }
2191 }
2192
2193 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002194 * Get the current storage encryption request status for a given admin, or aggregate of all
2195 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002196 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002197 public boolean getStorageEncryption(ComponentName who, int userHandle) {
2198 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002199 synchronized (this) {
2200 // Check for permissions if a particular caller is specified
2201 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002202 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002203 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002204 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002205 }
2206
Andy Stadler22dbfda2011-01-17 12:47:31 -08002207 // If no particular caller is specified, return the aggregate set of requests.
2208 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002209 DevicePolicyData policy = getUserData(userHandle);
2210 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002211 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002212 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002213 return true;
2214 }
2215 }
2216 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002217 }
2218 }
2219
Andy Stadler22dbfda2011-01-17 12:47:31 -08002220 /**
2221 * Get the current encryption status of the device.
2222 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002223 public int getStorageEncryptionStatus(int userHandle) {
2224 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002225 return getEncryptionStatus();
2226 }
2227
2228 /**
2229 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2230 */
2231 private boolean isEncryptionSupported() {
2232 // Note, this can be implemented as
2233 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2234 // But is provided as a separate internal method if there's a faster way to do a
2235 // simple check for supported-or-not.
2236 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2237 }
2238
2239 /**
2240 * Hook to low-levels: Reporting the current status of encryption.
2241 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2242 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2243 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2244 */
2245 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002246 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2247 if ("encrypted".equalsIgnoreCase(status)) {
2248 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2249 } else if ("unencrypted".equalsIgnoreCase(status)) {
2250 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2251 } else {
2252 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2253 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002254 }
2255
2256 /**
2257 * Hook to low-levels: If needed, record the new admin setting for encryption.
2258 */
2259 private void setEncryptionRequested(boolean encrypt) {
2260 }
2261
Ben Komalo2447edd2011-05-09 16:05:33 -07002262 /**
2263 * The system property used to share the state of the camera. The native camera service
2264 * is expected to read this property and act accordingly.
2265 */
2266 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2267
2268 /**
2269 * Disables all device cameras according to the specified admin.
2270 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002271 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
2272 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002273 synchronized (this) {
2274 if (who == null) {
2275 throw new NullPointerException("ComponentName is null");
2276 }
2277 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2278 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2279 if (ap.disableCamera != disabled) {
2280 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002281 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002282 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002283 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002284 }
2285 }
2286
2287 /**
2288 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2289 * active admins.
2290 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002291 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Ben Komalo2447edd2011-05-09 16:05:33 -07002292 synchronized (this) {
2293 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002294 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002295 return (admin != null) ? admin.disableCamera : false;
2296 }
2297
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002298 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002299 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002300 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002301 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002302 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002303 if (admin.disableCamera) {
2304 return true;
2305 }
2306 }
2307 return false;
2308 }
2309 }
2310
Jim Millerb8ec4702012-08-31 17:19:10 -07002311 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002312 * Selectively disable keyguard features.
Jim Millerb8ec4702012-08-31 17:19:10 -07002313 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002314 public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002315 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002316 synchronized (this) {
2317 if (who == null) {
2318 throw new NullPointerException("ComponentName is null");
2319 }
2320 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Jim Miller48b9b0d2012-09-19 23:16:50 -07002321 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
2322 if (ap.disabledKeyguardFeatures != which) {
2323 ap.disabledKeyguardFeatures = which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002324 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002325 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002326 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002327 }
2328 }
2329
2330 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002331 * Gets the disabled state for features in keyguard for the given admin,
Jim Millerb8ec4702012-08-31 17:19:10 -07002332 * or the aggregate of all active admins if who is null.
2333 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002334 public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002335 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002336 synchronized (this) {
2337 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002338 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002339 return (admin != null) ? admin.disabledKeyguardFeatures : 0;
Jim Millerb8ec4702012-08-31 17:19:10 -07002340 }
2341
Jim Miller48b9b0d2012-09-19 23:16:50 -07002342 // Determine which keyguard features are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002343 DevicePolicyData policy = getUserData(userHandle);
2344 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002345 int which = 0;
2346 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002347 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002348 which |= admin.disabledKeyguardFeatures;
Jim Millerb8ec4702012-08-31 17:19:10 -07002349 }
2350 return which;
2351 }
2352 }
2353
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002354 private void enforceCrossUserPermission(int userHandle) {
2355 if (userHandle < 0) {
2356 throw new IllegalArgumentException("Invalid userId " + userHandle);
2357 }
2358 final int callingUid = Binder.getCallingUid();
2359 if (userHandle == UserHandle.getUserId(callingUid)) return;
2360 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2361 mContext.enforceCallingOrSelfPermission(
2362 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2363 + " INTERACT_ACROSS_USERS_FULL permission");
2364 }
2365 }
2366
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002367 @Override
2368 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2369 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2370 != PackageManager.PERMISSION_GRANTED) {
2371
2372 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2373 + Binder.getCallingPid()
2374 + ", uid=" + Binder.getCallingUid());
2375 return;
2376 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002377
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002378 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002379
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002380 synchronized (this) {
2381 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002382
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002383 int userCount = mUserData.size();
2384 for (int u = 0; u < userCount; u++) {
2385 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2386 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2387 final int N = policy.mAdminList.size();
2388 for (int i=0; i<N; i++) {
2389 ActiveAdmin ap = policy.mAdminList.get(i);
2390 if (ap != null) {
2391 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2392 pw.println(":");
2393 ap.dump(" ", pw);
2394 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002395 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002396
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002397 pw.println(" ");
2398 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2399 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002400 }
2401 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002402}