blob: b2de9632f6ddf15ed63e0281edc0df88909ae7e3 [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;
Ben Komaloed48c8b2011-10-17 17:30:21 -070049import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080050import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080051import android.os.IBinder;
52import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070053import android.os.PowerManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070054import android.os.Process;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080055import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080056import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080057import android.os.RemoteException;
58import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080059import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080060import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070061import android.os.UserHandle;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070062import android.os.UserManager;
Oscar Montemayor69238c62010-08-03 10:51:06 -070063import android.provider.Settings;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080064import android.util.PrintWriterPrinter;
65import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080066import android.util.Slog;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070067import android.util.SparseArray;
Dianne Hackbornd6847842010-01-12 18:14:19 -080068import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080069import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080070import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080071
72import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080073import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080074import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070075import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080076import java.io.FileOutputStream;
77import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080078import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080079import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080080import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080081import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080082import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080083import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070084import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080085
86/**
87 * Implementation of the device policy APIs.
88 */
89public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Amith Yamasani599dd7c2012-09-14 23:20:08 -070090 private static final String DEVICE_POLICIES_XML = "device_policies.xml";
91
Jim Miller6b857682011-02-16 16:27:41 -080092 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080093
Jim Miller6b857682011-02-16 16:27:41 -080094 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -070095
Amith Yamasani599dd7c2012-09-14 23:20:08 -070096 private static final long MS_PER_DAY = 86400 * 1000;
97
98 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
Jim Millera4e28d12010-11-08 16:15:47 -080099
100 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
101 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
102
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700103 private static final boolean DBG = false;
Jim Millera4e28d12010-11-08 16:15:47 -0800104
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800105 final Context mContext;
Dianne Hackborn42499172010-10-15 18:45:07 -0700106 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800107
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800108 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800109 IWindowManager mIWindowManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700110
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700111 public static class DevicePolicyData {
112 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
113 int mActivePasswordLength = 0;
114 int mActivePasswordUpperCase = 0;
115 int mActivePasswordLowerCase = 0;
116 int mActivePasswordLetters = 0;
117 int mActivePasswordNumeric = 0;
118 int mActivePasswordSymbols = 0;
119 int mActivePasswordNonLetter = 0;
120 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700121
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700122 int mUserHandle;;
123 int mPasswordOwner = -1;
124 long mLastMaximumTimeToLock = -1;
125
126 final HashMap<ComponentName, ActiveAdmin> mAdminMap
127 = new HashMap<ComponentName, ActiveAdmin>();
128 final ArrayList<ActiveAdmin> mAdminList
129 = new ArrayList<ActiveAdmin>();
130
131 public DevicePolicyData(int userHandle) {
132 mUserHandle = userHandle;
133 }
134 }
135
136 final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
137
Jim Millera4e28d12010-11-08 16:15:47 -0800138 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700139
Jim Millera4e28d12010-11-08 16:15:47 -0800140 BroadcastReceiver mReceiver = new BroadcastReceiver() {
141 @Override
142 public void onReceive(Context context, Intent intent) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700143 final String action = intent.getAction();
144 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
145 getSendingUserId());
Jim Millera4e28d12010-11-08 16:15:47 -0800146 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
147 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700148 Slog.v(TAG, "Sending password expiration notifications for action " + action
149 + " for user " + userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800150 mHandler.post(new Runnable() {
151 public void run() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700152 handlePasswordExpirationNotification(getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -0800153 }
154 });
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700155 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
156 removeUserData(userHandle);
157 } else if (Intent.ACTION_USER_STARTED.equals(action)
158 || Intent.ACTION_PACKAGE_CHANGED.equals(action)
159 || Intent.ACTION_PACKAGE_REMOVED.equals(action)
160 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
161
162 if (Intent.ACTION_USER_STARTED.equals(action)) {
163 // Reset the policy data
164 synchronized (DevicePolicyManagerService.this) {
165 mUserData.remove(userHandle);
166 }
167 }
168
169 handlePackagesChanged(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800170 }
171 }
172 };
173
Dianne Hackbornd6847842010-01-12 18:14:19 -0800174 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800175 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700176
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800177 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700178
179 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
180 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
181
182 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
183 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
184
185 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
186 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
187
188 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
189 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
190
191 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700192 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700193
194 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
195 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
196
197 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
198 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
199
200 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
201 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
202
203 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
204 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
205
206 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
207 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
208
209 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
210 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
211
212 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
213 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
214
Jim Miller48b9b0d2012-09-19 23:16:50 -0700215 static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
216 int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
Jim Millerb8ec4702012-08-31 17:19:10 -0700217
Andy Stadler22dbfda2011-01-17 12:47:31 -0800218 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700219 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700220
Oscar Montemayor69238c62010-08-03 10:51:06 -0700221 // TODO: review implementation decisions with frameworks team
222 boolean specifiesGlobalProxy = false;
223 String globalProxySpec = null;
224 String globalProxyExclusionList = null;
225
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800226 ActiveAdmin(DeviceAdminInfo _info) {
227 info = _info;
228 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700229
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800230 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700231
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700232 public UserHandle getUserHandle() {
233 return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
234 }
235
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800236 void writeToXml(XmlSerializer out)
237 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800238 out.startTag(null, "policies");
239 info.writePoliciesToXml(out);
240 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800241 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
242 out.startTag(null, "password-quality");
243 out.attribute(null, "value", Integer.toString(passwordQuality));
244 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700245 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800246 out.startTag(null, "min-password-length");
247 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700248 out.endTag(null, "min-password-length");
249 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700250 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700251 out.startTag(null, "password-history-length");
252 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
253 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800254 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700255 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700256 out.startTag(null, "min-password-uppercase");
257 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
258 out.endTag(null, "min-password-uppercase");
259 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700260 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700261 out.startTag(null, "min-password-lowercase");
262 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
263 out.endTag(null, "min-password-lowercase");
264 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700265 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700266 out.startTag(null, "min-password-letters");
267 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
268 out.endTag(null, "min-password-letters");
269 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700270 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700271 out.startTag(null, "min-password-numeric");
272 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
273 out.endTag(null, "min-password-numeric");
274 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700275 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700276 out.startTag(null, "min-password-symbols");
277 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
278 out.endTag(null, "min-password-symbols");
279 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700280 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700281 out.startTag(null, "min-password-nonletter");
282 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
283 out.endTag(null, "min-password-nonletter");
284 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800285 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700286 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800287 out.startTag(null, "max-time-to-unlock");
288 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
289 out.endTag(null, "max-time-to-unlock");
290 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700291 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800292 out.startTag(null, "max-failed-password-wipe");
293 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
294 out.endTag(null, "max-failed-password-wipe");
295 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700296 if (specifiesGlobalProxy) {
297 out.startTag(null, "specifies-global-proxy");
298 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
299 out.endTag(null, "specifies_global_proxy");
300 if (globalProxySpec != null) {
301 out.startTag(null, "global-proxy-spec");
302 out.attribute(null, "value", globalProxySpec);
303 out.endTag(null, "global-proxy-spec");
304 }
305 if (globalProxyExclusionList != null) {
306 out.startTag(null, "global-proxy-exclusion-list");
307 out.attribute(null, "value", globalProxyExclusionList);
308 out.endTag(null, "global-proxy-exclusion-list");
309 }
310 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700311 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800312 out.startTag(null, "password-expiration-timeout");
313 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
314 out.endTag(null, "password-expiration-timeout");
315 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700316 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800317 out.startTag(null, "password-expiration-date");
318 out.attribute(null, "value", Long.toString(passwordExpirationDate));
319 out.endTag(null, "password-expiration-date");
320 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800321 if (encryptionRequested) {
322 out.startTag(null, "encryption-requested");
323 out.attribute(null, "value", Boolean.toString(encryptionRequested));
324 out.endTag(null, "encryption-requested");
325 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700326 if (disableCamera) {
327 out.startTag(null, "disable-camera");
328 out.attribute(null, "value", Boolean.toString(disableCamera));
329 out.endTag(null, "disable-camera");
330 }
Jim Miller48b9b0d2012-09-19 23:16:50 -0700331 if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
332 out.startTag(null, "disable-keyguard-features");
333 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
334 out.endTag(null, "disable-keyguard-features");
Jim Millerb8ec4702012-08-31 17:19:10 -0700335 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800336 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700337
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800338 void readFromXml(XmlPullParser parser)
339 throws XmlPullParserException, IOException {
340 int outerDepth = parser.getDepth();
341 int type;
342 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
343 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
344 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
345 continue;
346 }
347 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800348 if ("policies".equals(tag)) {
349 info.readPoliciesFromXml(parser);
350 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800351 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800352 parser.getAttributeValue(null, "value"));
353 } else if ("min-password-length".equals(tag)) {
354 minimumPasswordLength = Integer.parseInt(
355 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700356 } else if ("password-history-length".equals(tag)) {
357 passwordHistoryLength = Integer.parseInt(
358 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700359 } else if ("min-password-uppercase".equals(tag)) {
360 minimumPasswordUpperCase = Integer.parseInt(
361 parser.getAttributeValue(null, "value"));
362 } else if ("min-password-lowercase".equals(tag)) {
363 minimumPasswordLowerCase = Integer.parseInt(
364 parser.getAttributeValue(null, "value"));
365 } else if ("min-password-letters".equals(tag)) {
366 minimumPasswordLetters = Integer.parseInt(
367 parser.getAttributeValue(null, "value"));
368 } else if ("min-password-numeric".equals(tag)) {
369 minimumPasswordNumeric = Integer.parseInt(
370 parser.getAttributeValue(null, "value"));
371 } else if ("min-password-symbols".equals(tag)) {
372 minimumPasswordSymbols = Integer.parseInt(
373 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700374 } else if ("min-password-nonletter".equals(tag)) {
375 minimumPasswordNonLetter = Integer.parseInt(
376 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800377 } else if ("max-time-to-unlock".equals(tag)) {
378 maximumTimeToUnlock = Long.parseLong(
379 parser.getAttributeValue(null, "value"));
380 } else if ("max-failed-password-wipe".equals(tag)) {
381 maximumFailedPasswordsForWipe = Integer.parseInt(
382 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700383 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800384 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700385 parser.getAttributeValue(null, "value"));
386 } else if ("global-proxy-spec".equals(tag)) {
387 globalProxySpec =
388 parser.getAttributeValue(null, "value");
389 } else if ("global-proxy-exclusion-list".equals(tag)) {
390 globalProxyExclusionList =
391 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800392 } else if ("password-expiration-timeout".equals(tag)) {
393 passwordExpirationTimeout = Long.parseLong(
394 parser.getAttributeValue(null, "value"));
395 } else if ("password-expiration-date".equals(tag)) {
396 passwordExpirationDate = Long.parseLong(
397 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800398 } else if ("encryption-requested".equals(tag)) {
399 encryptionRequested = Boolean.parseBoolean(
400 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700401 } else if ("disable-camera".equals(tag)) {
402 disableCamera = Boolean.parseBoolean(
403 parser.getAttributeValue(null, "value"));
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700404 } else if ("disable-keyguard-features".equals(tag)) {
405 disabledKeyguardFeatures = Integer.parseInt(
406 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800407 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700408 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800409 }
410 XmlUtils.skipCurrentTag(parser);
411 }
412 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700413
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800414 void dump(String prefix, PrintWriter pw) {
415 pw.print(prefix); pw.print("uid="); pw.println(getUid());
416 pw.print(prefix); pw.println("policies:");
417 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
418 if (pols != null) {
419 for (int i=0; i<pols.size(); i++) {
420 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
421 }
422 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700423 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700424 pw.println(Integer.toHexString(passwordQuality));
425 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800426 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700427 pw.print(prefix); pw.print("passwordHistoryLength=");
428 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700429 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
430 pw.println(minimumPasswordUpperCase);
431 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
432 pw.println(minimumPasswordLowerCase);
433 pw.print(prefix); pw.print("minimumPasswordLetters=");
434 pw.println(minimumPasswordLetters);
435 pw.print(prefix); pw.print("minimumPasswordNumeric=");
436 pw.println(minimumPasswordNumeric);
437 pw.print(prefix); pw.print("minimumPasswordSymbols=");
438 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700439 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
440 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800441 pw.print(prefix); pw.print("maximumTimeToUnlock=");
442 pw.println(maximumTimeToUnlock);
443 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
444 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700445 pw.print(prefix); pw.print("specifiesGlobalProxy=");
446 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800447 pw.print(prefix); pw.print("passwordExpirationTimeout=");
448 pw.println(passwordExpirationTimeout);
449 pw.print(prefix); pw.print("passwordExpirationDate=");
450 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700451 if (globalProxySpec != null) {
452 pw.print(prefix); pw.print("globalProxySpec=");
453 pw.println(globalProxySpec);
454 }
455 if (globalProxyExclusionList != null) {
456 pw.print(prefix); pw.print("globalProxyEclusionList=");
457 pw.println(globalProxyExclusionList);
458 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800459 pw.print(prefix); pw.print("encryptionRequested=");
460 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700461 pw.print(prefix); pw.print("disableCamera=");
462 pw.println(disableCamera);
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700463 pw.print(prefix); pw.print("disabledKeyguardFeatures=");
464 pw.println(disabledKeyguardFeatures);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800465 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800466 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700467
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700468 private void handlePackagesChanged(int userHandle) {
469 boolean removed = false;
470 Slog.d(TAG, "Handling package changes for user " + userHandle);
471 DevicePolicyData policy = getUserData(userHandle);
472 IPackageManager pm = AppGlobals.getPackageManager();
473 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
474 ActiveAdmin aa = policy.mAdminList.get(i);
475 try {
476 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
477 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
478 removed = true;
479 policy.mAdminList.remove(i);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800480 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700481 } catch (RemoteException re) {
482 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800483 }
484 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700485 if (removed) {
486 validatePasswordOwnerLocked(policy);
487 syncDeviceCapabilitiesLocked(policy);
488 saveSettingsLocked(policy.mUserHandle);
489 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800490 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700491
Dianne Hackbornd6847842010-01-12 18:14:19 -0800492 /**
493 * Instantiates the service.
494 */
495 public DevicePolicyManagerService(Context context) {
496 mContext = context;
Dianne Hackborn42499172010-10-15 18:45:07 -0700497 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
498 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800499 IntentFilter filter = new IntentFilter();
500 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
501 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700502 filter.addAction(Intent.ACTION_USER_REMOVED);
503 filter.addAction(Intent.ACTION_USER_STARTED);
504 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
505 filter = new IntentFilter();
506 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
507 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
508 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
509 filter.addDataScheme("package");
510 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
511 }
512
513 /**
514 * Creates and loads the policy data from xml.
515 * @param userHandle the user for whom to load the policy data
516 * @return
517 */
518 DevicePolicyData getUserData(int userHandle) {
519 synchronized (this) {
520 DevicePolicyData policy = mUserData.get(userHandle);
521 if (policy == null) {
522 policy = new DevicePolicyData(userHandle);
523 mUserData.append(userHandle, policy);
524 loadSettingsLocked(policy, userHandle);
525 }
526 return policy;
527 }
528 }
529
530 void removeUserData(int userHandle) {
531 synchronized (this) {
532 if (userHandle == UserHandle.USER_OWNER) {
533 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
534 return;
535 }
536 DevicePolicyData policy = mUserData.get(userHandle);
537 if (policy != null) {
538 mUserData.remove(userHandle);
539 }
540 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
541 DEVICE_POLICIES_XML);
542 policyFile.delete();
543 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
544 }
Jim Millera4e28d12010-11-08 16:15:47 -0800545 }
546
Andy Stadler043116a2010-11-29 17:43:32 -0800547 /**
548 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
549 * reminders. Clears alarm if no expirations are configured.
550 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700551 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
552 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800553 final long now = System.currentTimeMillis();
554 final long timeToExpire = expiration - now;
555 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800556 if (expiration == 0) {
557 // No expirations are currently configured: Cancel alarm.
558 alarmTime = 0;
559 } else if (timeToExpire <= 0) {
560 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800561 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800562 } else {
563 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
564 // the expiration time.
565 long alarmInterval = timeToExpire % MS_PER_DAY;
566 if (alarmInterval == 0) {
567 alarmInterval = MS_PER_DAY;
568 }
569 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800570 }
571
Andy Stadler1f35d482010-11-19 15:39:41 -0800572 long token = Binder.clearCallingIdentity();
573 try {
574 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700575 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800576 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700577 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
578 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800579 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800580 if (alarmTime != 0) {
581 am.set(AlarmManager.RTC, alarmTime, pi);
582 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800583 } finally {
584 Binder.restoreCallingIdentity(token);
585 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800586 }
587
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800588 private IPowerManager getIPowerManager() {
589 if (mIPowerManager == null) {
590 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
591 mIPowerManager = IPowerManager.Stub.asInterface(b);
592 }
593 return mIPowerManager;
594 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700595
Jim Miller93c518e2012-01-17 15:55:31 -0800596 private IWindowManager getWindowManager() {
597 if (mIWindowManager == null) {
598 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
599 mIWindowManager = IWindowManager.Stub.asInterface(b);
600 }
601 return mIWindowManager;
602 }
603
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700604 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
605 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800606 if (admin != null
607 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
608 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
609 return admin;
610 }
611 return null;
612 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700613
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800614 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
615 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800616 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700617 final int userHandle = UserHandle.getUserId(callingUid);
618 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800619 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700620 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800621 if (admin == null) {
622 throw new SecurityException("No active admin " + who);
623 }
624 if (admin.getUid() != callingUid) {
625 throw new SecurityException("Admin " + who + " is not owned by uid "
626 + Binder.getCallingUid());
627 }
628 if (!admin.info.usesPolicy(reqPolicy)) {
629 throw new SecurityException("Admin " + admin.info.getComponent()
630 + " did not specify uses-policy for: "
631 + admin.info.getTagForPolicy(reqPolicy));
632 }
633 return admin;
634 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700635 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800636 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700637 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800638 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
639 return admin;
640 }
641 }
642 throw new SecurityException("No active admin owned by uid "
643 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800644 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800645 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700646
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800647 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700648 sendAdminCommandLocked(admin, action, null);
649 }
650
651 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800652 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800653 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800654 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
655 intent.putExtra("expiration", admin.passwordExpirationDate);
656 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700657 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700658 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700659 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700660 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700661 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700662 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800663 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700664
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700665 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
666 final DevicePolicyData policy = getUserData(userHandle);
667 final int count = policy.mAdminList.size();
668 if (count > 0) {
669 for (int i = 0; i < count; i++) {
670 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800671 if (admin.info.usesPolicy(reqPolicy)) {
672 sendAdminCommandLocked(admin, action);
673 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800674 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800675 }
676 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700677
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700678 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
679 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800680 if (admin != null) {
681 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700682 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
683 new BroadcastReceiver() {
684 @Override
685 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700686 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700687 int userHandle = admin.getUserHandle().getIdentifier();
688 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700689 boolean doProxyCleanup = admin.info.usesPolicy(
690 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700691 policy.mAdminList.remove(admin);
692 policy.mAdminMap.remove(adminReceiver);
693 validatePasswordOwnerLocked(policy);
694 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700695 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700696 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700697 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700698 saveSettingsLocked(userHandle);
699 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700700 }
701 }
702 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800703 }
704 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700705
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700706 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
707 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800708 Intent resolveIntent = new Intent();
709 resolveIntent.setComponent(adminName);
710 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700711 resolveIntent, PackageManager.GET_META_DATA, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800712 if (infos == null || infos.size() <= 0) {
713 throw new IllegalArgumentException("Unknown admin: " + adminName);
714 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700715
Dianne Hackbornd6847842010-01-12 18:14:19 -0800716 try {
717 return new DeviceAdminInfo(mContext, infos.get(0));
718 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700719 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800720 return null;
721 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700722 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800723 return null;
724 }
725 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700726
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700727 private static JournaledFile makeJournaledFile(int userHandle) {
728 final String base = userHandle == 0
729 ? "/data/system/" + DEVICE_POLICIES_XML
730 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
731 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800732 return new JournaledFile(new File(base), new File(base + ".tmp"));
733 }
734
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700735 private void saveSettingsLocked(int userHandle) {
736 DevicePolicyData policy = getUserData(userHandle);
737 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800738 FileOutputStream stream = null;
739 try {
740 stream = new FileOutputStream(journal.chooseForWrite(), false);
741 XmlSerializer out = new FastXmlSerializer();
742 out.setOutput(stream, "utf-8");
743 out.startDocument(null, true);
744
745 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700746
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700747 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800748 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700749 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800750 if (ap != null) {
751 out.startTag(null, "admin");
752 out.attribute(null, "name", ap.info.getComponent().flattenToString());
753 ap.writeToXml(out);
754 out.endTag(null, "admin");
755 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800756 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700757
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700758 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800759 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700760 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800761 out.endTag(null, "password-owner");
762 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700763
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700764 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800765 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700766 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800767 out.endTag(null, "failed-password-attempts");
768 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700769
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700770 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
771 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
772 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
773 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700774 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700775 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
776 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
777 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
778 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
779 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700780 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700781 .toString(policy.mActivePasswordNumeric));
782 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
783 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700784 out.endTag(null, "active-password");
785 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700786
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700787 out.endTag(null, "policies");
788
Dianne Hackbornd6847842010-01-12 18:14:19 -0800789 out.endDocument();
790 stream.close();
791 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700792 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800793 } catch (IOException e) {
794 try {
795 if (stream != null) {
796 stream.close();
797 }
798 } catch (IOException ex) {
799 // Ignore
800 }
801 journal.rollback();
802 }
803 }
804
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700805 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700806 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
807 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700808 long ident = Binder.clearCallingIdentity();
809 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700810 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700811 } finally {
812 Binder.restoreCallingIdentity(ident);
813 }
Jim Miller284b62e2010-06-08 14:27:42 -0700814 }
815
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700816 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
817 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800818 FileInputStream stream = null;
819 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800820 try {
821 stream = new FileInputStream(file);
822 XmlPullParser parser = Xml.newPullParser();
823 parser.setInput(stream, null);
824
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800825 int type;
826 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
827 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800828 }
829 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800830 if (!"policies".equals(tag)) {
831 throw new XmlPullParserException(
832 "Settings do not start with policies tag: found " + tag);
833 }
834 type = parser.next();
835 int outerDepth = parser.getDepth();
836 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
837 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
838 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
839 continue;
840 }
841 tag = parser.getName();
842 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800843 String name = parser.getAttributeValue(null, "name");
844 try {
845 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700846 ComponentName.unflattenFromString(name), userHandle);
847 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
848 != userHandle)) {
849 Slog.w(TAG, "findAdmin returned an incorrect uid "
850 + dai.getActivityInfo().applicationInfo.uid + " for user "
851 + userHandle);
852 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800853 if (dai != null) {
854 ActiveAdmin ap = new ActiveAdmin(dai);
855 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700856 policy.mAdminMap.put(ap.info.getComponent(), ap);
857 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800858 }
859 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700860 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800861 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800862 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700863 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800864 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800865 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800866 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700867 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800868 parser.getAttributeValue(null, "value"));
869 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700870 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700871 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700872 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700873 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700874 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700875 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700876 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700877 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700878 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700879 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700880 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700881 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700882 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700883 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700884 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700885 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700886 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700887 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800888 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700889 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800890 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800891 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800892 }
893 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700894 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800895 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700896 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800897 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700898 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700899 } catch (FileNotFoundException e) {
900 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800901 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700902 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800903 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700904 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800905 }
906 try {
907 if (stream != null) {
908 stream.close();
909 }
910 } catch (IOException e) {
911 // Ignore
912 }
913
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700914 // Validate that what we stored for the password quality matches
915 // sufficiently what is currently set. Note that this is only
916 // a sanity check in case the two get out of sync; this should
917 // never normally happen.
918 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700919 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700920 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700921 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700922 + " does not match actual quality 0x"
923 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700924 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
925 policy.mActivePasswordLength = 0;
926 policy.mActivePasswordUpperCase = 0;
927 policy.mActivePasswordLowerCase = 0;
928 policy.mActivePasswordLetters = 0;
929 policy.mActivePasswordNumeric = 0;
930 policy.mActivePasswordSymbols = 0;
931 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700932 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700933
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700934 validatePasswordOwnerLocked(policy);
935 syncDeviceCapabilitiesLocked(policy);
936 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800937 }
938
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700939 static void validateQualityConstant(int quality) {
940 switch (quality) {
941 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500942 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700943 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
944 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
945 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
946 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700947 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700948 return;
949 }
950 throw new IllegalArgumentException("Invalid quality constant: 0x"
951 + Integer.toHexString(quality));
952 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700953
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700954 void validatePasswordOwnerLocked(DevicePolicyData policy) {
955 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800956 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700957 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
958 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800959 haveOwner = true;
960 break;
961 }
962 }
963 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700964 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800965 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700966 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800967 }
968 }
969 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700970
Ben Komalo2447edd2011-05-09 16:05:33 -0700971 /**
972 * Pushes down policy information to the system for any policies related to general device
973 * capabilities that need to be enforced by lower level services (e.g. Camera services).
974 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700975 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -0700976 // Ensure the status of the camera is synced down to the system. Interested native services
977 // should monitor this value and act accordingly.
978 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700979 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -0700980 if (cameraDisabled != systemState) {
981 long token = Binder.clearCallingIdentity();
982 try {
983 String value = cameraDisabled ? "1" : "0";
984 Slog.v(TAG, "Change in camera state ["
985 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
986 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
987 } finally {
988 Binder.restoreCallingIdentity(token);
989 }
990 }
991 }
992
Dianne Hackbornd6847842010-01-12 18:14:19 -0800993 public void systemReady() {
994 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700995 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800996 }
997 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700998
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700999 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -08001000 synchronized (this) {
1001 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001002 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001003 if (N <= 0) {
1004 return;
1005 }
1006 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001007 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001008 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1009 && admin.passwordExpirationTimeout > 0L
1010 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001011 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001012 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1013 }
1014 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001015 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001016 }
1017 }
1018
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001019 /**
1020 * @param adminReceiver The admin to add
1021 * @param refreshing true = update an active admin, no error
1022 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001023 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001024 mContext.enforceCallingOrSelfPermission(
1025 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001026 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001027
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001028 DevicePolicyData policy = getUserData(userHandle);
1029 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001030 if (info == null) {
1031 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1032 }
1033 synchronized (this) {
1034 long ident = Binder.clearCallingIdentity();
1035 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001036 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001037 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001038 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001039 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001040 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001041 int replaceIndex = -1;
1042 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001043 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001044 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001045 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001046 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1047 replaceIndex = i;
1048 break;
1049 }
1050 }
1051 }
1052 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001053 policy.mAdminList.add(newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001054 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001055 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001056 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001057 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001058 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001059 } finally {
1060 Binder.restoreCallingIdentity(ident);
1061 }
1062 }
1063 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001064
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001065 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
1066 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001067 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001068 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001069 }
1070 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001071
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001072 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
1073 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001074 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001075 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001076 if (administrator == null) {
1077 throw new SecurityException("No active admin " + adminReceiver);
1078 }
1079 return administrator.info.usesPolicy(policyId);
1080 }
1081 }
1082
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001083 public List<ComponentName> getActiveAdmins(int userHandle) {
1084 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001085 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001086 DevicePolicyData policy = getUserData(userHandle);
1087 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001088 if (N <= 0) {
1089 return null;
1090 }
1091 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1092 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001093 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001094 }
1095 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001096 }
1097 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001098
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001099 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
1100 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001101 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001102 DevicePolicyData policy = getUserData(userHandle);
1103 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001104 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001105 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001106 return true;
1107 }
1108 }
1109 return false;
1110 }
1111 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001112
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001113 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
1114 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001115 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001116 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001117 if (admin == null) {
1118 return;
1119 }
1120 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001121 mContext.enforceCallingOrSelfPermission(
1122 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1123 }
1124 long ident = Binder.clearCallingIdentity();
1125 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001126 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001127 } finally {
1128 Binder.restoreCallingIdentity(ident);
1129 }
1130 }
1131 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001132
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001133 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001134 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001135 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001136
Dianne Hackbornd6847842010-01-12 18:14:19 -08001137 synchronized (this) {
1138 if (who == null) {
1139 throw new NullPointerException("ComponentName is null");
1140 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001141 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1142 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001143 if (ap.passwordQuality != quality) {
1144 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001145 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001146 }
1147 }
1148 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001149
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001150 public int getPasswordQuality(ComponentName who, int userHandle) {
1151 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001152 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001153 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001154 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001155
Dianne Hackborn254cb442010-01-27 19:23:59 -08001156 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001157 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001158 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001159 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001160
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001161 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001162 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001163 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001164 if (mode < admin.passwordQuality) {
1165 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001166 }
1167 }
1168 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001169 }
1170 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001171
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001172 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
1173 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001174 synchronized (this) {
1175 if (who == null) {
1176 throw new NullPointerException("ComponentName is null");
1177 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001178 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1179 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001180 if (ap.minimumPasswordLength != length) {
1181 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001182 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001183 }
1184 }
1185 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001186
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001187 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
1188 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001189 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001190 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001191 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001192
Dianne Hackborn254cb442010-01-27 19:23:59 -08001193 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001194 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001195 return admin != null ? admin.minimumPasswordLength : length;
1196 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001197
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001198 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001199 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001200 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001201 if (length < admin.minimumPasswordLength) {
1202 length = admin.minimumPasswordLength;
1203 }
1204 }
1205 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001206 }
1207 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001208
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001209 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
1210 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001211 synchronized (this) {
1212 if (who == null) {
1213 throw new NullPointerException("ComponentName is null");
1214 }
1215 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1216 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1217 if (ap.passwordHistoryLength != length) {
1218 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001219 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001220 }
1221 }
1222 }
1223
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001224 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
1225 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001226 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001227 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001228 int length = 0;
1229
1230 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001231 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001232 return admin != null ? admin.passwordHistoryLength : length;
1233 }
1234
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001235 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001236 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001237 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001238 if (length < admin.passwordHistoryLength) {
1239 length = admin.passwordHistoryLength;
1240 }
1241 }
1242 return length;
1243 }
1244 }
1245
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001246 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
1247 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001248 synchronized (this) {
1249 if (who == null) {
1250 throw new NullPointerException("ComponentName is null");
1251 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001252 if (timeout < 0) {
1253 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001254 }
1255 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1256 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1257 // Calling this API automatically bumps the expiration date
1258 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1259 ap.passwordExpirationDate = expiration;
1260 ap.passwordExpirationTimeout = timeout;
1261 if (timeout > 0L) {
1262 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1263 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1264 .format(new Date(expiration)));
1265 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001266 saveSettingsLocked(userHandle);
1267 // in case this is the first one
1268 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001269 }
1270 }
1271
Andy Stadler043116a2010-11-29 17:43:32 -08001272 /**
1273 * Return a single admin's expiration cycle time, or the min of all cycle times.
1274 * Returns 0 if not configured.
1275 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001276 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
1277 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001278 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001279 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001280 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001281 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001282 }
1283
Andy Stadler043116a2010-11-29 17:43:32 -08001284 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001285 DevicePolicyData policy = getUserData(userHandle);
1286 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001287 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001288 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001289 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1290 && timeout > admin.passwordExpirationTimeout)) {
1291 timeout = admin.passwordExpirationTimeout;
1292 }
1293 }
1294 return timeout;
1295 }
1296 }
1297
Andy Stadler043116a2010-11-29 17:43:32 -08001298 /**
1299 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1300 * Returns 0 if not configured.
1301 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001302 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001303 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001304 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001305 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001306 }
1307
Andy Stadler043116a2010-11-29 17:43:32 -08001308 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001309 DevicePolicyData policy = getUserData(userHandle);
1310 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001311 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001312 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001313 if (timeout == 0L || (admin.passwordExpirationDate != 0
1314 && timeout > admin.passwordExpirationDate)) {
1315 timeout = admin.passwordExpirationDate;
1316 }
1317 }
1318 return timeout;
1319 }
1320
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001321 public long getPasswordExpiration(ComponentName who, int userHandle) {
1322 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001323 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001324 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001325 }
1326 }
1327
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001328 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
1329 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001330 synchronized (this) {
1331 if (who == null) {
1332 throw new NullPointerException("ComponentName is null");
1333 }
1334 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1335 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1336 if (ap.minimumPasswordUpperCase != length) {
1337 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001338 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001339 }
1340 }
1341 }
1342
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001343 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
1344 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001345 synchronized (this) {
1346 int length = 0;
1347
1348 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001349 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001350 return admin != null ? admin.minimumPasswordUpperCase : length;
1351 }
1352
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001353 DevicePolicyData policy = getUserData(userHandle);
1354 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001355 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001356 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001357 if (length < admin.minimumPasswordUpperCase) {
1358 length = admin.minimumPasswordUpperCase;
1359 }
1360 }
1361 return length;
1362 }
1363 }
1364
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001365 public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
1366 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001367 synchronized (this) {
1368 if (who == null) {
1369 throw new NullPointerException("ComponentName is null");
1370 }
1371 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1372 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1373 if (ap.minimumPasswordLowerCase != length) {
1374 ap.minimumPasswordLowerCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001375 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001376 }
1377 }
1378 }
1379
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001380 public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
1381 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001382 synchronized (this) {
1383 int length = 0;
1384
1385 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001386 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001387 return admin != null ? admin.minimumPasswordLowerCase : length;
1388 }
1389
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001390 DevicePolicyData policy = getUserData(userHandle);
1391 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001392 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001393 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001394 if (length < admin.minimumPasswordLowerCase) {
1395 length = admin.minimumPasswordLowerCase;
1396 }
1397 }
1398 return length;
1399 }
1400 }
1401
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001402 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
1403 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001404 synchronized (this) {
1405 if (who == null) {
1406 throw new NullPointerException("ComponentName is null");
1407 }
1408 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1409 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1410 if (ap.minimumPasswordLetters != length) {
1411 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001412 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001413 }
1414 }
1415 }
1416
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001417 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
1418 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001419 synchronized (this) {
1420 int length = 0;
1421
1422 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001423 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001424 return admin != null ? admin.minimumPasswordLetters : length;
1425 }
1426
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001427 DevicePolicyData policy = getUserData(userHandle);
1428 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001429 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001430 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001431 if (length < admin.minimumPasswordLetters) {
1432 length = admin.minimumPasswordLetters;
1433 }
1434 }
1435 return length;
1436 }
1437 }
1438
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001439 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
1440 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001441 synchronized (this) {
1442 if (who == null) {
1443 throw new NullPointerException("ComponentName is null");
1444 }
1445 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1446 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1447 if (ap.minimumPasswordNumeric != length) {
1448 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001449 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001450 }
1451 }
1452 }
1453
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001454 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
1455 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001456 synchronized (this) {
1457 int length = 0;
1458
1459 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001460 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001461 return admin != null ? admin.minimumPasswordNumeric : length;
1462 }
1463
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001464 DevicePolicyData policy = getUserData(userHandle);
1465 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001466 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001467 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001468 if (length < admin.minimumPasswordNumeric) {
1469 length = admin.minimumPasswordNumeric;
1470 }
1471 }
1472 return length;
1473 }
1474 }
1475
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001476 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
1477 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001478 synchronized (this) {
1479 if (who == null) {
1480 throw new NullPointerException("ComponentName is null");
1481 }
1482 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1483 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1484 if (ap.minimumPasswordSymbols != length) {
1485 ap.minimumPasswordSymbols = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001486 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001487 }
1488 }
1489 }
1490
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001491 public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
1492 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001493 synchronized (this) {
1494 int length = 0;
1495
1496 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001497 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001498 return admin != null ? admin.minimumPasswordSymbols : length;
1499 }
1500
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001501 DevicePolicyData policy = getUserData(userHandle);
1502 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001503 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001504 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001505 if (length < admin.minimumPasswordSymbols) {
1506 length = admin.minimumPasswordSymbols;
1507 }
1508 }
1509 return length;
1510 }
1511 }
1512
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001513 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
1514 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001515 synchronized (this) {
1516 if (who == null) {
1517 throw new NullPointerException("ComponentName is null");
1518 }
1519 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1520 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1521 if (ap.minimumPasswordNonLetter != length) {
1522 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001523 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001524 }
1525 }
1526 }
1527
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001528 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
1529 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001530 synchronized (this) {
1531 int length = 0;
1532
1533 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001534 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001535 return admin != null ? admin.minimumPasswordNonLetter : length;
1536 }
1537
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001538 DevicePolicyData policy = getUserData(userHandle);
1539 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001540 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001541 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001542 if (length < admin.minimumPasswordNonLetter) {
1543 length = admin.minimumPasswordNonLetter;
1544 }
1545 }
1546 return length;
1547 }
1548 }
1549
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001550 public boolean isActivePasswordSufficient(int userHandle) {
1551 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001552 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001553 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001554 // This API can only be called by an active device admin,
1555 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001556 getActiveAdminForCallerLocked(null,
1557 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001558 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1559 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001560 return false;
1561 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001562 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001563 return true;
1564 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001565 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1566 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1567 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1568 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1569 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1570 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001571 }
1572 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001573
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001574 public int getCurrentFailedPasswordAttempts(int userHandle) {
1575 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001576 synchronized (this) {
1577 // This API can only be called by an active device admin,
1578 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001579 getActiveAdminForCallerLocked(null,
1580 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001581 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001582 }
1583 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001584
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001585 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
1586 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001587 synchronized (this) {
1588 // This API can only be called by an active device admin,
1589 // so try to retrieve it to check that the caller is one.
1590 getActiveAdminForCallerLocked(who,
1591 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1592 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1593 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1594 if (ap.maximumFailedPasswordsForWipe != num) {
1595 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001596 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001597 }
1598 }
1599 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001600
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001601 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
1602 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001603 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001604 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001605 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001606
Dianne Hackborn254cb442010-01-27 19:23:59 -08001607 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001608 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001609 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1610 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001611
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001612 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001613 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001614 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001615 if (count == 0) {
1616 count = admin.maximumFailedPasswordsForWipe;
1617 } else if (admin.maximumFailedPasswordsForWipe != 0
1618 && count > admin.maximumFailedPasswordsForWipe) {
1619 count = admin.maximumFailedPasswordsForWipe;
1620 }
1621 }
1622 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001623 }
1624 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001625
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001626 public boolean resetPassword(String password, int flags, int userHandle) {
1627 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001628 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001629 synchronized (this) {
1630 // This API can only be called by an active device admin,
1631 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001632 getActiveAdminForCallerLocked(null,
1633 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001634 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001635 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001636 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001637 if (realQuality < quality
1638 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001639 Slog.w(TAG, "resetPassword: password quality 0x"
1640 + Integer.toHexString(quality)
1641 + " does not meet required quality 0x"
1642 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001643 return false;
1644 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001645 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001646 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001647 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001648 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001649 Slog.w(TAG, "resetPassword: password length " + password.length()
1650 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001651 return false;
1652 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001653 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1654 int letters = 0;
1655 int uppercase = 0;
1656 int lowercase = 0;
1657 int numbers = 0;
1658 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001659 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001660 for (int i = 0; i < password.length(); i++) {
1661 char c = password.charAt(i);
1662 if (c >= 'A' && c <= 'Z') {
1663 letters++;
1664 uppercase++;
1665 } else if (c >= 'a' && c <= 'z') {
1666 letters++;
1667 lowercase++;
1668 } else if (c >= '0' && c <= '9') {
1669 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001670 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001671 } else {
1672 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001673 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001674 }
1675 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001676 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001677 if(letters < neededLetters) {
1678 Slog.w(TAG, "resetPassword: number of letters " + letters
1679 + " does not meet required number of letters " + neededLetters);
1680 return false;
1681 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001682 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001683 if (numbers < neededNumbers) {
1684 Slog
1685 .w(TAG, "resetPassword: number of numerical digits " + numbers
1686 + " does not meet required number of numerical digits "
1687 + neededNumbers);
1688 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
1835 getWindowManager().lockNow();
1836 } 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 Yamasani599dd7c2012-09-14 23:20:08 -07001877 if (userHandle == UserHandle.USER_OWNER) {
1878 wipeDataLocked(flags);
1879 } else {
1880 lockNowUnchecked();
1881 mHandler.post(new Runnable() {
1882 public void run() {
1883 try {
1884 ActivityManagerNative.getDefault().switchUser(0);
1885 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
1886 .removeUser(userHandle);
1887 } catch (RemoteException re) {
1888 // Shouldn't happen
1889 }
1890 }
1891 });
1892 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001893 } finally {
1894 Binder.restoreCallingIdentity(ident);
1895 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001896 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001897 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001898
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001899 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
1900 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001901 mContext.enforceCallingOrSelfPermission(
1902 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001903
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001904 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001905 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001906 if (admin == null) {
1907 try {
1908 result.sendResult(null);
1909 } catch (RemoteException e) {
1910 }
1911 return;
1912 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001913 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001914 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001915 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001916 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001917 @Override
1918 public void onReceive(Context context, Intent intent) {
1919 try {
1920 result.sendResult(getResultExtras(false));
1921 } catch (RemoteException e) {
1922 }
1923 }
1924 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001925 }
1926 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001927
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001928 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001929 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
1930 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001931 mContext.enforceCallingOrSelfPermission(
1932 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001933 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001934
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001935 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001936
Dianne Hackbornd6847842010-01-12 18:14:19 -08001937 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001938 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
1939 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
1940 || p.mActivePasswordUpperCase != uppercase
1941 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
1942 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001943 long ident = Binder.clearCallingIdentity();
1944 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001945 p.mActivePasswordQuality = quality;
1946 p.mActivePasswordLength = length;
1947 p.mActivePasswordLetters = letters;
1948 p.mActivePasswordLowerCase = lowercase;
1949 p.mActivePasswordUpperCase = uppercase;
1950 p.mActivePasswordNumeric = numbers;
1951 p.mActivePasswordSymbols = symbols;
1952 p.mActivePasswordNonLetter = nonletter;
1953 p.mFailedPasswordAttempts = 0;
1954 saveSettingsLocked(userHandle);
1955 updatePasswordExpirationsLocked(userHandle);
1956 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001957 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001958 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001959 } finally {
1960 Binder.restoreCallingIdentity(ident);
1961 }
1962 }
1963 }
1964 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001965
Andy Stadler043116a2010-11-29 17:43:32 -08001966 /**
1967 * Called any time the device password is updated. Resets all password expiration clocks.
1968 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001969 private void updatePasswordExpirationsLocked(int userHandle) {
1970 DevicePolicyData policy = getUserData(userHandle);
1971 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001972 if (N > 0) {
1973 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001974 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001975 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001976 long timeout = admin.passwordExpirationTimeout;
1977 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1978 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001979 }
1980 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001981 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001982 }
1983 }
1984
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001985 public void reportFailedPasswordAttempt(int userHandle) {
1986 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001987 mContext.enforceCallingOrSelfPermission(
1988 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001989
Dianne Hackbornd6847842010-01-12 18:14:19 -08001990 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001991 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001992 long ident = Binder.clearCallingIdentity();
1993 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001994 policy.mFailedPasswordAttempts++;
1995 saveSettingsLocked(userHandle);
1996 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
1997 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001998 wipeDataLocked(0);
1999 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002000 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002001 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002002 } finally {
2003 Binder.restoreCallingIdentity(ident);
2004 }
2005 }
2006 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002007
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002008 public void reportSuccessfulPasswordAttempt(int userHandle) {
2009 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002010 mContext.enforceCallingOrSelfPermission(
2011 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002012
Dianne Hackbornd6847842010-01-12 18:14:19 -08002013 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002014 DevicePolicyData policy = getUserData(userHandle);
2015 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002016 long ident = Binder.clearCallingIdentity();
2017 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002018 policy.mFailedPasswordAttempts = 0;
2019 policy.mPasswordOwner = -1;
2020 saveSettingsLocked(userHandle);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002021 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002022 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002023 } finally {
2024 Binder.restoreCallingIdentity(ident);
2025 }
2026 }
2027 }
2028 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002029
Oscar Montemayor69238c62010-08-03 10:51:06 -07002030 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002031 String exclusionList, int userHandle) {
2032 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002033 synchronized(this) {
2034 if (who == null) {
2035 throw new NullPointerException("ComponentName is null");
2036 }
2037
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002038 // Only check if owner has set global proxy. We don't allow other users to set it.
2039 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002040 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2041 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2042
2043 // Scan through active admins and find if anyone has already
2044 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002045 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002046 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002047 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002048 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2049 // Another admin already sets the global proxy
2050 // Return it to the caller.
2051 return component;
2052 }
2053 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002054
2055 // If the user is not the owner, don't set the global proxy. Fail silently.
2056 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2057 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2058 + userHandle + " is not permitted.");
2059 return null;
2060 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002061 if (proxySpec == null) {
2062 admin.specifiesGlobalProxy = false;
2063 admin.globalProxySpec = null;
2064 admin.globalProxyExclusionList = null;
2065 } else {
2066
2067 admin.specifiesGlobalProxy = true;
2068 admin.globalProxySpec = proxySpec;
2069 admin.globalProxyExclusionList = exclusionList;
2070 }
2071
2072 // Reset the global proxy accordingly
2073 // Do this using system permissions, as apps cannot write to secure settings
2074 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002075 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002076 Binder.restoreCallingIdentity(origId);
2077 return null;
2078 }
2079 }
2080
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002081 public ComponentName getGlobalProxyAdmin(int userHandle) {
2082 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002083 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002084 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002085 // Scan through active admins and find if anyone has already
2086 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002087 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002088 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002089 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002090 if (ap.specifiesGlobalProxy) {
2091 // Device admin sets the global proxy
2092 // Return it to the caller.
2093 return ap.info.getComponent();
2094 }
2095 }
2096 }
2097 // No device admin sets the global proxy.
2098 return null;
2099 }
2100
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002101 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2102 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002103 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002104 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002105 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002106 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002107 return;
2108 }
2109 }
2110 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002111 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002112 }
2113
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002114 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002115 if (exclusionList == null) {
2116 exclusionList = "";
2117 }
2118 if (proxySpec == null) {
2119 proxySpec = "";
2120 }
2121 // Remove white spaces
2122 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002123 String data[] = proxySpec.split(":");
2124 int proxyPort = 8080;
2125 if (data.length > 1) {
2126 try {
2127 proxyPort = Integer.parseInt(data[1]);
2128 } catch (NumberFormatException e) {}
2129 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002130 exclusionList = exclusionList.trim();
2131 ContentResolver res = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -07002132 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
2133 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2134 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwalt434203a2010-10-11 16:00:27 -07002135 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002136 }
2137
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002138 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002139 * Set the storage encryption request for a single admin. Returns the new total request
2140 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002141 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002142 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
2143 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002144 synchronized (this) {
2145 // Check for permissions
2146 if (who == null) {
2147 throw new NullPointerException("ComponentName is null");
2148 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002149 // Only owner can set storage encryption
2150 if (userHandle != UserHandle.USER_OWNER
2151 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2152 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2153 + UserHandle.getCallingUserId() + " is not permitted.");
2154 return 0;
2155 }
2156
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002157 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2158 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2159
Andy Stadler22dbfda2011-01-17 12:47:31 -08002160 // Quick exit: If the filesystem does not support encryption, we can exit early.
2161 if (!isEncryptionSupported()) {
2162 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2163 }
2164
2165 // (1) Record the value for the admin so it's sticky
2166 if (ap.encryptionRequested != encrypt) {
2167 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002168 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002169 }
2170
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002171 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002172 // (2) Compute "max" for all admins
2173 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002174 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002175 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002176 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002177 }
2178
2179 // Notify OS of new request
2180 setEncryptionRequested(newRequested);
2181
2182 // Return the new global request status
2183 return newRequested
2184 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2185 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002186 }
2187 }
2188
2189 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002190 * Get the current storage encryption request status for a given admin, or aggregate of all
2191 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002192 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002193 public boolean getStorageEncryption(ComponentName who, int userHandle) {
2194 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002195 synchronized (this) {
2196 // Check for permissions if a particular caller is specified
2197 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002198 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002199 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002200 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002201 }
2202
Andy Stadler22dbfda2011-01-17 12:47:31 -08002203 // If no particular caller is specified, return the aggregate set of requests.
2204 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002205 DevicePolicyData policy = getUserData(userHandle);
2206 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002207 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002208 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002209 return true;
2210 }
2211 }
2212 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002213 }
2214 }
2215
Andy Stadler22dbfda2011-01-17 12:47:31 -08002216 /**
2217 * Get the current encryption status of the device.
2218 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002219 public int getStorageEncryptionStatus(int userHandle) {
2220 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002221 return getEncryptionStatus();
2222 }
2223
2224 /**
2225 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2226 */
2227 private boolean isEncryptionSupported() {
2228 // Note, this can be implemented as
2229 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2230 // But is provided as a separate internal method if there's a faster way to do a
2231 // simple check for supported-or-not.
2232 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2233 }
2234
2235 /**
2236 * Hook to low-levels: Reporting the current status of encryption.
2237 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2238 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2239 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2240 */
2241 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002242 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2243 if ("encrypted".equalsIgnoreCase(status)) {
2244 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2245 } else if ("unencrypted".equalsIgnoreCase(status)) {
2246 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2247 } else {
2248 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2249 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002250 }
2251
2252 /**
2253 * Hook to low-levels: If needed, record the new admin setting for encryption.
2254 */
2255 private void setEncryptionRequested(boolean encrypt) {
2256 }
2257
Ben Komalo2447edd2011-05-09 16:05:33 -07002258 /**
2259 * The system property used to share the state of the camera. The native camera service
2260 * is expected to read this property and act accordingly.
2261 */
2262 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2263
2264 /**
2265 * Disables all device cameras according to the specified admin.
2266 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002267 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
2268 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002269 synchronized (this) {
2270 if (who == null) {
2271 throw new NullPointerException("ComponentName is null");
2272 }
2273 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2274 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2275 if (ap.disableCamera != disabled) {
2276 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002277 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002278 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002279 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002280 }
2281 }
2282
2283 /**
2284 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2285 * active admins.
2286 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002287 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Ben Komalo2447edd2011-05-09 16:05:33 -07002288 synchronized (this) {
2289 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002290 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002291 return (admin != null) ? admin.disableCamera : false;
2292 }
2293
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002294 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002295 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002296 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002297 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002298 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002299 if (admin.disableCamera) {
2300 return true;
2301 }
2302 }
2303 return false;
2304 }
2305 }
2306
Jim Millerb8ec4702012-08-31 17:19:10 -07002307 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002308 * Selectively disable keyguard features.
Jim Millerb8ec4702012-08-31 17:19:10 -07002309 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002310 public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002311 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002312 synchronized (this) {
2313 if (who == null) {
2314 throw new NullPointerException("ComponentName is null");
2315 }
2316 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Jim Miller48b9b0d2012-09-19 23:16:50 -07002317 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
2318 if (ap.disabledKeyguardFeatures != which) {
2319 ap.disabledKeyguardFeatures = which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002320 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002321 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002322 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002323 }
2324 }
2325
2326 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002327 * Gets the disabled state for features in keyguard for the given admin,
Jim Millerb8ec4702012-08-31 17:19:10 -07002328 * or the aggregate of all active admins if who is null.
2329 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002330 public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002331 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002332 synchronized (this) {
2333 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002334 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002335 return (admin != null) ? admin.disabledKeyguardFeatures : 0;
Jim Millerb8ec4702012-08-31 17:19:10 -07002336 }
2337
Jim Miller48b9b0d2012-09-19 23:16:50 -07002338 // Determine which keyguard features are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002339 DevicePolicyData policy = getUserData(userHandle);
2340 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002341 int which = 0;
2342 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002343 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002344 which |= admin.disabledKeyguardFeatures;
Jim Millerb8ec4702012-08-31 17:19:10 -07002345 }
2346 return which;
2347 }
2348 }
2349
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002350 private void enforceCrossUserPermission(int userHandle) {
2351 if (userHandle < 0) {
2352 throw new IllegalArgumentException("Invalid userId " + userHandle);
2353 }
2354 final int callingUid = Binder.getCallingUid();
2355 if (userHandle == UserHandle.getUserId(callingUid)) return;
2356 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2357 mContext.enforceCallingOrSelfPermission(
2358 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2359 + " INTERACT_ACROSS_USERS_FULL permission");
2360 }
2361 }
2362
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002363 @Override
2364 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2365 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2366 != PackageManager.PERMISSION_GRANTED) {
2367
2368 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2369 + Binder.getCallingPid()
2370 + ", uid=" + Binder.getCallingUid());
2371 return;
2372 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002373
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002374 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002375
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002376 synchronized (this) {
2377 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002378
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002379 int userCount = mUserData.size();
2380 for (int u = 0; u < userCount; u++) {
2381 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2382 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2383 final int N = policy.mAdminList.size();
2384 for (int i=0; i<N; i++) {
2385 ActiveAdmin ap = policy.mAdminList.get(i);
2386 if (ap != null) {
2387 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2388 pw.println(":");
2389 ap.dump(" ", pw);
2390 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002391 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002392
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002393 pw.println(" ");
2394 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2395 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002396 }
2397 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002398}