blob: aec5d6ed2555bea4609d27d28178b6886b3a0f59 [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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Millerb8ec4702012-08-31 17:19:10 -0700215 static final int DEF_KEYGUARD_WIDGET_DISABLED = 0; // none
216 int disableKeyguardWidgets = DEF_KEYGUARD_WIDGET_DISABLED;
217
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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Hackbornd998acb32011-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 Millerb8ec4702012-08-31 17:19:10 -0700331 if (disableKeyguardWidgets != DEF_KEYGUARD_WIDGET_DISABLED) {
332 out.startTag(null, "disable-keyguard-widgets");
333 out.attribute(null, "value", Integer.toString(disableKeyguardWidgets));
334 out.endTag(null, "disable-keyguard-widgets");
335 }
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"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800404 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700405 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800406 }
407 XmlUtils.skipCurrentTag(parser);
408 }
409 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700410
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800411 void dump(String prefix, PrintWriter pw) {
412 pw.print(prefix); pw.print("uid="); pw.println(getUid());
413 pw.print(prefix); pw.println("policies:");
414 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
415 if (pols != null) {
416 for (int i=0; i<pols.size(); i++) {
417 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
418 }
419 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700420 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700421 pw.println(Integer.toHexString(passwordQuality));
422 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800423 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700424 pw.print(prefix); pw.print("passwordHistoryLength=");
425 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700426 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
427 pw.println(minimumPasswordUpperCase);
428 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
429 pw.println(minimumPasswordLowerCase);
430 pw.print(prefix); pw.print("minimumPasswordLetters=");
431 pw.println(minimumPasswordLetters);
432 pw.print(prefix); pw.print("minimumPasswordNumeric=");
433 pw.println(minimumPasswordNumeric);
434 pw.print(prefix); pw.print("minimumPasswordSymbols=");
435 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700436 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
437 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800438 pw.print(prefix); pw.print("maximumTimeToUnlock=");
439 pw.println(maximumTimeToUnlock);
440 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
441 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700442 pw.print(prefix); pw.print("specifiesGlobalProxy=");
443 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800444 pw.print(prefix); pw.print("passwordExpirationTimeout=");
445 pw.println(passwordExpirationTimeout);
446 pw.print(prefix); pw.print("passwordExpirationDate=");
447 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700448 if (globalProxySpec != null) {
449 pw.print(prefix); pw.print("globalProxySpec=");
450 pw.println(globalProxySpec);
451 }
452 if (globalProxyExclusionList != null) {
453 pw.print(prefix); pw.print("globalProxyEclusionList=");
454 pw.println(globalProxyExclusionList);
455 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800456 pw.print(prefix); pw.print("encryptionRequested=");
457 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700458 pw.print(prefix); pw.print("disableCamera=");
459 pw.println(disableCamera);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800460 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800461 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700462
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700463 private void handlePackagesChanged(int userHandle) {
464 boolean removed = false;
465 Slog.d(TAG, "Handling package changes for user " + userHandle);
466 DevicePolicyData policy = getUserData(userHandle);
467 IPackageManager pm = AppGlobals.getPackageManager();
468 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
469 ActiveAdmin aa = policy.mAdminList.get(i);
470 try {
471 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
472 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
473 removed = true;
474 policy.mAdminList.remove(i);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800475 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700476 } catch (RemoteException re) {
477 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800478 }
479 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700480 if (removed) {
481 validatePasswordOwnerLocked(policy);
482 syncDeviceCapabilitiesLocked(policy);
483 saveSettingsLocked(policy.mUserHandle);
484 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800485 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700486
Dianne Hackbornd6847842010-01-12 18:14:19 -0800487 /**
488 * Instantiates the service.
489 */
490 public DevicePolicyManagerService(Context context) {
491 mContext = context;
Dianne Hackborn42499172010-10-15 18:45:07 -0700492 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
493 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800494 IntentFilter filter = new IntentFilter();
495 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
496 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700497 filter.addAction(Intent.ACTION_USER_REMOVED);
498 filter.addAction(Intent.ACTION_USER_STARTED);
499 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
500 filter = new IntentFilter();
501 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
502 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
503 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
504 filter.addDataScheme("package");
505 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
506 }
507
508 /**
509 * Creates and loads the policy data from xml.
510 * @param userHandle the user for whom to load the policy data
511 * @return
512 */
513 DevicePolicyData getUserData(int userHandle) {
514 synchronized (this) {
515 DevicePolicyData policy = mUserData.get(userHandle);
516 if (policy == null) {
517 policy = new DevicePolicyData(userHandle);
518 mUserData.append(userHandle, policy);
519 loadSettingsLocked(policy, userHandle);
520 }
521 return policy;
522 }
523 }
524
525 void removeUserData(int userHandle) {
526 synchronized (this) {
527 if (userHandle == UserHandle.USER_OWNER) {
528 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
529 return;
530 }
531 DevicePolicyData policy = mUserData.get(userHandle);
532 if (policy != null) {
533 mUserData.remove(userHandle);
534 }
535 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
536 DEVICE_POLICIES_XML);
537 policyFile.delete();
538 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
539 }
Jim Millera4e28d12010-11-08 16:15:47 -0800540 }
541
Andy Stadler043116a2010-11-29 17:43:32 -0800542 /**
543 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
544 * reminders. Clears alarm if no expirations are configured.
545 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700546 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
547 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800548 final long now = System.currentTimeMillis();
549 final long timeToExpire = expiration - now;
550 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800551 if (expiration == 0) {
552 // No expirations are currently configured: Cancel alarm.
553 alarmTime = 0;
554 } else if (timeToExpire <= 0) {
555 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800556 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800557 } else {
558 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
559 // the expiration time.
560 long alarmInterval = timeToExpire % MS_PER_DAY;
561 if (alarmInterval == 0) {
562 alarmInterval = MS_PER_DAY;
563 }
564 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800565 }
566
Andy Stadler1f35d482010-11-19 15:39:41 -0800567 long token = Binder.clearCallingIdentity();
568 try {
569 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700570 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800571 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700572 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
573 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800574 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800575 if (alarmTime != 0) {
576 am.set(AlarmManager.RTC, alarmTime, pi);
577 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800578 } finally {
579 Binder.restoreCallingIdentity(token);
580 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800581 }
582
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800583 private IPowerManager getIPowerManager() {
584 if (mIPowerManager == null) {
585 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
586 mIPowerManager = IPowerManager.Stub.asInterface(b);
587 }
588 return mIPowerManager;
589 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700590
Jim Miller93c518e2012-01-17 15:55:31 -0800591 private IWindowManager getWindowManager() {
592 if (mIWindowManager == null) {
593 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
594 mIWindowManager = IWindowManager.Stub.asInterface(b);
595 }
596 return mIWindowManager;
597 }
598
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700599 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
600 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800601 if (admin != null
602 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
603 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
604 return admin;
605 }
606 return null;
607 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700608
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800609 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
610 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800611 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700612 final int userHandle = UserHandle.getUserId(callingUid);
613 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800614 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700615 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800616 if (admin == null) {
617 throw new SecurityException("No active admin " + who);
618 }
619 if (admin.getUid() != callingUid) {
620 throw new SecurityException("Admin " + who + " is not owned by uid "
621 + Binder.getCallingUid());
622 }
623 if (!admin.info.usesPolicy(reqPolicy)) {
624 throw new SecurityException("Admin " + admin.info.getComponent()
625 + " did not specify uses-policy for: "
626 + admin.info.getTagForPolicy(reqPolicy));
627 }
628 return admin;
629 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700630 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800631 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700632 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800633 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
634 return admin;
635 }
636 }
637 throw new SecurityException("No active admin owned by uid "
638 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800639 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800640 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700641
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800642 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700643 sendAdminCommandLocked(admin, action, null);
644 }
645
646 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800647 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800648 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800649 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
650 intent.putExtra("expiration", admin.passwordExpirationDate);
651 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700652 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700653 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700654 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700655 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700656 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700657 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800658 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700659
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700660 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
661 final DevicePolicyData policy = getUserData(userHandle);
662 final int count = policy.mAdminList.size();
663 if (count > 0) {
664 for (int i = 0; i < count; i++) {
665 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800666 if (admin.info.usesPolicy(reqPolicy)) {
667 sendAdminCommandLocked(admin, action);
668 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800669 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800670 }
671 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700672
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700673 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
674 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800675 if (admin != null) {
676 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700677 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
678 new BroadcastReceiver() {
679 @Override
680 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700681 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700682 int userHandle = admin.getUserHandle().getIdentifier();
683 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700684 boolean doProxyCleanup = admin.info.usesPolicy(
685 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700686 policy.mAdminList.remove(admin);
687 policy.mAdminMap.remove(adminReceiver);
688 validatePasswordOwnerLocked(policy);
689 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700690 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700691 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700692 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700693 saveSettingsLocked(userHandle);
694 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700695 }
696 }
697 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800698 }
699 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700700
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700701 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
702 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800703 Intent resolveIntent = new Intent();
704 resolveIntent.setComponent(adminName);
705 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700706 resolveIntent, PackageManager.GET_META_DATA, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800707 if (infos == null || infos.size() <= 0) {
708 throw new IllegalArgumentException("Unknown admin: " + adminName);
709 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700710
Dianne Hackbornd6847842010-01-12 18:14:19 -0800711 try {
712 return new DeviceAdminInfo(mContext, infos.get(0));
713 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700714 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800715 return null;
716 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700717 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800718 return null;
719 }
720 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700721
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700722 private static JournaledFile makeJournaledFile(int userHandle) {
723 final String base = userHandle == 0
724 ? "/data/system/" + DEVICE_POLICIES_XML
725 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
726 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800727 return new JournaledFile(new File(base), new File(base + ".tmp"));
728 }
729
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700730 private void saveSettingsLocked(int userHandle) {
731 DevicePolicyData policy = getUserData(userHandle);
732 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800733 FileOutputStream stream = null;
734 try {
735 stream = new FileOutputStream(journal.chooseForWrite(), false);
736 XmlSerializer out = new FastXmlSerializer();
737 out.setOutput(stream, "utf-8");
738 out.startDocument(null, true);
739
740 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700741
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700742 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800743 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700744 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800745 if (ap != null) {
746 out.startTag(null, "admin");
747 out.attribute(null, "name", ap.info.getComponent().flattenToString());
748 ap.writeToXml(out);
749 out.endTag(null, "admin");
750 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800751 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700752
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700753 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800754 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700755 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800756 out.endTag(null, "password-owner");
757 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700758
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700759 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800760 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700761 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800762 out.endTag(null, "failed-password-attempts");
763 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700764
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700765 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
766 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
767 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
768 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700769 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700770 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
771 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
772 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
773 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
774 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700775 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700776 .toString(policy.mActivePasswordNumeric));
777 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
778 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700779 out.endTag(null, "active-password");
780 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700781
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700782 out.endTag(null, "policies");
783
Dianne Hackbornd6847842010-01-12 18:14:19 -0800784 out.endDocument();
785 stream.close();
786 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700787 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800788 } catch (IOException e) {
789 try {
790 if (stream != null) {
791 stream.close();
792 }
793 } catch (IOException ex) {
794 // Ignore
795 }
796 journal.rollback();
797 }
798 }
799
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700800 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700801 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
802 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700803 long ident = Binder.clearCallingIdentity();
804 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700805 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700806 } finally {
807 Binder.restoreCallingIdentity(ident);
808 }
Jim Miller284b62e2010-06-08 14:27:42 -0700809 }
810
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700811 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
812 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800813 FileInputStream stream = null;
814 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800815 try {
816 stream = new FileInputStream(file);
817 XmlPullParser parser = Xml.newPullParser();
818 parser.setInput(stream, null);
819
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800820 int type;
821 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
822 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800823 }
824 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800825 if (!"policies".equals(tag)) {
826 throw new XmlPullParserException(
827 "Settings do not start with policies tag: found " + tag);
828 }
829 type = parser.next();
830 int outerDepth = parser.getDepth();
831 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
832 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
833 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
834 continue;
835 }
836 tag = parser.getName();
837 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800838 String name = parser.getAttributeValue(null, "name");
839 try {
840 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700841 ComponentName.unflattenFromString(name), userHandle);
842 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
843 != userHandle)) {
844 Slog.w(TAG, "findAdmin returned an incorrect uid "
845 + dai.getActivityInfo().applicationInfo.uid + " for user "
846 + userHandle);
847 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800848 if (dai != null) {
849 ActiveAdmin ap = new ActiveAdmin(dai);
850 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700851 policy.mAdminMap.put(ap.info.getComponent(), ap);
852 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800853 }
854 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700855 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800856 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800857 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700858 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800859 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800860 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800861 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700862 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800863 parser.getAttributeValue(null, "value"));
864 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700865 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700866 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700867 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700868 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700869 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700870 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700871 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700872 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700873 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700874 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700875 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700876 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700877 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700878 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700879 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700880 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700881 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700882 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800883 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700884 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800885 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800886 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800887 }
888 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700889 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800890 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700891 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800892 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700893 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700894 } catch (FileNotFoundException e) {
895 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800896 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700897 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800898 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700899 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800900 }
901 try {
902 if (stream != null) {
903 stream.close();
904 }
905 } catch (IOException e) {
906 // Ignore
907 }
908
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700909 // Validate that what we stored for the password quality matches
910 // sufficiently what is currently set. Note that this is only
911 // a sanity check in case the two get out of sync; this should
912 // never normally happen.
913 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700914 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700915 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700916 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700917 + " does not match actual quality 0x"
918 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700919 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
920 policy.mActivePasswordLength = 0;
921 policy.mActivePasswordUpperCase = 0;
922 policy.mActivePasswordLowerCase = 0;
923 policy.mActivePasswordLetters = 0;
924 policy.mActivePasswordNumeric = 0;
925 policy.mActivePasswordSymbols = 0;
926 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700927 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700928
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700929 validatePasswordOwnerLocked(policy);
930 syncDeviceCapabilitiesLocked(policy);
931 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800932 }
933
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700934 static void validateQualityConstant(int quality) {
935 switch (quality) {
936 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500937 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700938 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
939 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
940 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
941 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700942 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700943 return;
944 }
945 throw new IllegalArgumentException("Invalid quality constant: 0x"
946 + Integer.toHexString(quality));
947 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700948
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700949 void validatePasswordOwnerLocked(DevicePolicyData policy) {
950 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800951 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700952 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
953 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800954 haveOwner = true;
955 break;
956 }
957 }
958 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700959 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800960 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700961 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800962 }
963 }
964 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700965
Ben Komalo2447edd2011-05-09 16:05:33 -0700966 /**
967 * Pushes down policy information to the system for any policies related to general device
968 * capabilities that need to be enforced by lower level services (e.g. Camera services).
969 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700970 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -0700971 // Ensure the status of the camera is synced down to the system. Interested native services
972 // should monitor this value and act accordingly.
973 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700974 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -0700975 if (cameraDisabled != systemState) {
976 long token = Binder.clearCallingIdentity();
977 try {
978 String value = cameraDisabled ? "1" : "0";
979 Slog.v(TAG, "Change in camera state ["
980 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
981 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
982 } finally {
983 Binder.restoreCallingIdentity(token);
984 }
985 }
986 }
987
Dianne Hackbornd6847842010-01-12 18:14:19 -0800988 public void systemReady() {
989 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700990 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800991 }
992 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700993
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700994 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -0800995 synchronized (this) {
996 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700997 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -0800998 if (N <= 0) {
999 return;
1000 }
1001 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001002 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001003 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1004 && admin.passwordExpirationTimeout > 0L
1005 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001006 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001007 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1008 }
1009 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001010 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001011 }
1012 }
1013
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001014 /**
1015 * @param adminReceiver The admin to add
1016 * @param refreshing true = update an active admin, no error
1017 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001018 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001019 mContext.enforceCallingOrSelfPermission(
1020 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001021 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001022
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001023 DevicePolicyData policy = getUserData(userHandle);
1024 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001025 if (info == null) {
1026 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1027 }
1028 synchronized (this) {
1029 long ident = Binder.clearCallingIdentity();
1030 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001031 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001032 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001033 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001034 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001035 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001036 int replaceIndex = -1;
1037 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001038 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001039 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001040 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001041 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1042 replaceIndex = i;
1043 break;
1044 }
1045 }
1046 }
1047 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001048 policy.mAdminList.add(newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001049 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001050 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001051 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001052 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001053 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001054 } finally {
1055 Binder.restoreCallingIdentity(ident);
1056 }
1057 }
1058 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001059
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001060 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
1061 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001062 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001063 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001064 }
1065 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001066
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001067 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
1068 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001069 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001070 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001071 if (administrator == null) {
1072 throw new SecurityException("No active admin " + adminReceiver);
1073 }
1074 return administrator.info.usesPolicy(policyId);
1075 }
1076 }
1077
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001078 public List<ComponentName> getActiveAdmins(int userHandle) {
1079 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001080 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001081 DevicePolicyData policy = getUserData(userHandle);
1082 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001083 if (N <= 0) {
1084 return null;
1085 }
1086 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1087 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001088 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001089 }
1090 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001091 }
1092 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001093
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001094 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
1095 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001096 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001097 DevicePolicyData policy = getUserData(userHandle);
1098 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001099 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001100 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001101 return true;
1102 }
1103 }
1104 return false;
1105 }
1106 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001107
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001108 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
1109 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001110 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001111 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001112 if (admin == null) {
1113 return;
1114 }
1115 if (admin.getUid() != Binder.getCallingUid()) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001116 mContext.enforceCallingOrSelfPermission(
1117 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1118 }
1119 long ident = Binder.clearCallingIdentity();
1120 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001121 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001122 } finally {
1123 Binder.restoreCallingIdentity(ident);
1124 }
1125 }
1126 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001127
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001128 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001129 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001130 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001131
Dianne Hackbornd6847842010-01-12 18:14:19 -08001132 synchronized (this) {
1133 if (who == null) {
1134 throw new NullPointerException("ComponentName is null");
1135 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001136 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1137 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001138 if (ap.passwordQuality != quality) {
1139 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001140 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001141 }
1142 }
1143 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001144
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001145 public int getPasswordQuality(ComponentName who, int userHandle) {
1146 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001147 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001148 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001149 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001150
Dianne Hackborn254cb442010-01-27 19:23:59 -08001151 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001152 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001153 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001154 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001155
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001156 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001157 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001158 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001159 if (mode < admin.passwordQuality) {
1160 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001161 }
1162 }
1163 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001164 }
1165 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001166
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001167 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
1168 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001169 synchronized (this) {
1170 if (who == null) {
1171 throw new NullPointerException("ComponentName is null");
1172 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001173 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1174 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001175 if (ap.minimumPasswordLength != length) {
1176 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001177 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001178 }
1179 }
1180 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001181
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001182 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
1183 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001184 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001185 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001186 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001187
Dianne Hackborn254cb442010-01-27 19:23:59 -08001188 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001189 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001190 return admin != null ? admin.minimumPasswordLength : length;
1191 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001192
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001193 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001194 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001195 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001196 if (length < admin.minimumPasswordLength) {
1197 length = admin.minimumPasswordLength;
1198 }
1199 }
1200 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001201 }
1202 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001203
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001204 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
1205 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001206 synchronized (this) {
1207 if (who == null) {
1208 throw new NullPointerException("ComponentName is null");
1209 }
1210 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1211 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1212 if (ap.passwordHistoryLength != length) {
1213 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001214 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001215 }
1216 }
1217 }
1218
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001219 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
1220 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001221 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001222 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001223 int length = 0;
1224
1225 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001226 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001227 return admin != null ? admin.passwordHistoryLength : length;
1228 }
1229
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001230 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001231 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001232 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001233 if (length < admin.passwordHistoryLength) {
1234 length = admin.passwordHistoryLength;
1235 }
1236 }
1237 return length;
1238 }
1239 }
1240
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001241 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
1242 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001243 synchronized (this) {
1244 if (who == null) {
1245 throw new NullPointerException("ComponentName is null");
1246 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001247 if (timeout < 0) {
1248 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001249 }
1250 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1251 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1252 // Calling this API automatically bumps the expiration date
1253 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1254 ap.passwordExpirationDate = expiration;
1255 ap.passwordExpirationTimeout = timeout;
1256 if (timeout > 0L) {
1257 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1258 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1259 .format(new Date(expiration)));
1260 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001261 saveSettingsLocked(userHandle);
1262 // in case this is the first one
1263 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001264 }
1265 }
1266
Andy Stadler043116a2010-11-29 17:43:32 -08001267 /**
1268 * Return a single admin's expiration cycle time, or the min of all cycle times.
1269 * Returns 0 if not configured.
1270 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001271 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
1272 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001273 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001274 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001275 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001276 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001277 }
1278
Andy Stadler043116a2010-11-29 17:43:32 -08001279 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001280 DevicePolicyData policy = getUserData(userHandle);
1281 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001282 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001283 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001284 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1285 && timeout > admin.passwordExpirationTimeout)) {
1286 timeout = admin.passwordExpirationTimeout;
1287 }
1288 }
1289 return timeout;
1290 }
1291 }
1292
Andy Stadler043116a2010-11-29 17:43:32 -08001293 /**
1294 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1295 * Returns 0 if not configured.
1296 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001297 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001298 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001299 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001300 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001301 }
1302
Andy Stadler043116a2010-11-29 17:43:32 -08001303 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001304 DevicePolicyData policy = getUserData(userHandle);
1305 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001306 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001307 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001308 if (timeout == 0L || (admin.passwordExpirationDate != 0
1309 && timeout > admin.passwordExpirationDate)) {
1310 timeout = admin.passwordExpirationDate;
1311 }
1312 }
1313 return timeout;
1314 }
1315
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001316 public long getPasswordExpiration(ComponentName who, int userHandle) {
1317 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001318 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001319 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001320 }
1321 }
1322
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001323 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
1324 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001325 synchronized (this) {
1326 if (who == null) {
1327 throw new NullPointerException("ComponentName is null");
1328 }
1329 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1330 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1331 if (ap.minimumPasswordUpperCase != length) {
1332 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001333 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001334 }
1335 }
1336 }
1337
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001338 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
1339 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001340 synchronized (this) {
1341 int length = 0;
1342
1343 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001344 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001345 return admin != null ? admin.minimumPasswordUpperCase : length;
1346 }
1347
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001348 DevicePolicyData policy = getUserData(userHandle);
1349 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001350 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001351 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001352 if (length < admin.minimumPasswordUpperCase) {
1353 length = admin.minimumPasswordUpperCase;
1354 }
1355 }
1356 return length;
1357 }
1358 }
1359
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001360 public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
1361 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001362 synchronized (this) {
1363 if (who == null) {
1364 throw new NullPointerException("ComponentName is null");
1365 }
1366 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1367 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1368 if (ap.minimumPasswordLowerCase != length) {
1369 ap.minimumPasswordLowerCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001370 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001371 }
1372 }
1373 }
1374
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001375 public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
1376 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001377 synchronized (this) {
1378 int length = 0;
1379
1380 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001381 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001382 return admin != null ? admin.minimumPasswordLowerCase : length;
1383 }
1384
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001385 DevicePolicyData policy = getUserData(userHandle);
1386 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001387 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001388 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001389 if (length < admin.minimumPasswordLowerCase) {
1390 length = admin.minimumPasswordLowerCase;
1391 }
1392 }
1393 return length;
1394 }
1395 }
1396
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001397 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
1398 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001399 synchronized (this) {
1400 if (who == null) {
1401 throw new NullPointerException("ComponentName is null");
1402 }
1403 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1404 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1405 if (ap.minimumPasswordLetters != length) {
1406 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001407 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001408 }
1409 }
1410 }
1411
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001412 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
1413 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001414 synchronized (this) {
1415 int length = 0;
1416
1417 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001418 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001419 return admin != null ? admin.minimumPasswordLetters : length;
1420 }
1421
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001422 DevicePolicyData policy = getUserData(userHandle);
1423 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001424 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001425 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001426 if (length < admin.minimumPasswordLetters) {
1427 length = admin.minimumPasswordLetters;
1428 }
1429 }
1430 return length;
1431 }
1432 }
1433
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001434 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
1435 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001436 synchronized (this) {
1437 if (who == null) {
1438 throw new NullPointerException("ComponentName is null");
1439 }
1440 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1441 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1442 if (ap.minimumPasswordNumeric != length) {
1443 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001444 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001445 }
1446 }
1447 }
1448
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001449 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
1450 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001451 synchronized (this) {
1452 int length = 0;
1453
1454 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001455 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001456 return admin != null ? admin.minimumPasswordNumeric : length;
1457 }
1458
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001459 DevicePolicyData policy = getUserData(userHandle);
1460 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001461 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001462 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001463 if (length < admin.minimumPasswordNumeric) {
1464 length = admin.minimumPasswordNumeric;
1465 }
1466 }
1467 return length;
1468 }
1469 }
1470
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001471 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
1472 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001473 synchronized (this) {
1474 if (who == null) {
1475 throw new NullPointerException("ComponentName is null");
1476 }
1477 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1478 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1479 if (ap.minimumPasswordSymbols != length) {
1480 ap.minimumPasswordSymbols = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001481 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001482 }
1483 }
1484 }
1485
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001486 public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
1487 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001488 synchronized (this) {
1489 int length = 0;
1490
1491 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001492 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001493 return admin != null ? admin.minimumPasswordSymbols : length;
1494 }
1495
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001496 DevicePolicyData policy = getUserData(userHandle);
1497 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001498 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001499 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001500 if (length < admin.minimumPasswordSymbols) {
1501 length = admin.minimumPasswordSymbols;
1502 }
1503 }
1504 return length;
1505 }
1506 }
1507
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001508 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
1509 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001510 synchronized (this) {
1511 if (who == null) {
1512 throw new NullPointerException("ComponentName is null");
1513 }
1514 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1515 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1516 if (ap.minimumPasswordNonLetter != length) {
1517 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001518 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001519 }
1520 }
1521 }
1522
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001523 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
1524 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001525 synchronized (this) {
1526 int length = 0;
1527
1528 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001529 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001530 return admin != null ? admin.minimumPasswordNonLetter : length;
1531 }
1532
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001533 DevicePolicyData policy = getUserData(userHandle);
1534 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001535 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001536 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001537 if (length < admin.minimumPasswordNonLetter) {
1538 length = admin.minimumPasswordNonLetter;
1539 }
1540 }
1541 return length;
1542 }
1543 }
1544
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001545 public boolean isActivePasswordSufficient(int userHandle) {
1546 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001547 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001548 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001549 // This API can only be called by an active device admin,
1550 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001551 getActiveAdminForCallerLocked(null,
1552 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001553 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1554 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001555 return false;
1556 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001557 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001558 return true;
1559 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001560 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1561 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1562 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1563 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1564 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1565 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001566 }
1567 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001568
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001569 public int getCurrentFailedPasswordAttempts(int userHandle) {
1570 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001571 synchronized (this) {
1572 // This API can only be called by an active device admin,
1573 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001574 getActiveAdminForCallerLocked(null,
1575 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001576 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001577 }
1578 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001579
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001580 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
1581 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001582 synchronized (this) {
1583 // This API can only be called by an active device admin,
1584 // so try to retrieve it to check that the caller is one.
1585 getActiveAdminForCallerLocked(who,
1586 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1587 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1588 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1589 if (ap.maximumFailedPasswordsForWipe != num) {
1590 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001591 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001592 }
1593 }
1594 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001595
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001596 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
1597 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001598 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001599 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001600 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001601
Dianne Hackborn254cb442010-01-27 19:23:59 -08001602 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001603 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001604 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1605 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001606
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001607 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001608 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001609 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001610 if (count == 0) {
1611 count = admin.maximumFailedPasswordsForWipe;
1612 } else if (admin.maximumFailedPasswordsForWipe != 0
1613 && count > admin.maximumFailedPasswordsForWipe) {
1614 count = admin.maximumFailedPasswordsForWipe;
1615 }
1616 }
1617 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001618 }
1619 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001620
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001621 public boolean resetPassword(String password, int flags, int userHandle) {
1622 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001623 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001624 synchronized (this) {
1625 // This API can only be called by an active device admin,
1626 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001627 getActiveAdminForCallerLocked(null,
1628 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001629 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001630 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001631 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001632 if (realQuality < quality
1633 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001634 Slog.w(TAG, "resetPassword: password quality 0x"
1635 + Integer.toHexString(quality)
1636 + " does not meet required quality 0x"
1637 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001638 return false;
1639 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001640 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001641 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001642 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001643 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001644 Slog.w(TAG, "resetPassword: password length " + password.length()
1645 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001646 return false;
1647 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001648 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1649 int letters = 0;
1650 int uppercase = 0;
1651 int lowercase = 0;
1652 int numbers = 0;
1653 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001654 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001655 for (int i = 0; i < password.length(); i++) {
1656 char c = password.charAt(i);
1657 if (c >= 'A' && c <= 'Z') {
1658 letters++;
1659 uppercase++;
1660 } else if (c >= 'a' && c <= 'z') {
1661 letters++;
1662 lowercase++;
1663 } else if (c >= '0' && c <= '9') {
1664 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001665 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001666 } else {
1667 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001668 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001669 }
1670 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001671 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001672 if(letters < neededLetters) {
1673 Slog.w(TAG, "resetPassword: number of letters " + letters
1674 + " does not meet required number of letters " + neededLetters);
1675 return false;
1676 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001677 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001678 if (numbers < neededNumbers) {
1679 Slog
1680 .w(TAG, "resetPassword: number of numerical digits " + numbers
1681 + " does not meet required number of numerical digits "
1682 + neededNumbers);
1683 return false;
1684 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001685 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001686 if (lowercase < neededLowerCase) {
1687 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1688 + " does not meet required number of lowercase letters "
1689 + neededLowerCase);
1690 return false;
1691 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001692 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001693 if (uppercase < neededUpperCase) {
1694 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1695 + " does not meet required number of uppercase letters "
1696 + neededUpperCase);
1697 return false;
1698 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001699 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001700 if (symbols < neededSymbols) {
1701 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1702 + " does not meet required number of special symbols " + neededSymbols);
1703 return false;
1704 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001705 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001706 if (nonletter < neededNonLetter) {
1707 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1708 + " does not meet required number of non-letter characters "
1709 + neededNonLetter);
1710 return false;
1711 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001712 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001713 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001714
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001715 int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001716 DevicePolicyData policy = getUserData(userHandle);
1717 if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001718 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001719 return false;
1720 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001721
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001722 // Don't do this with the lock held, because it is going to call
1723 // back in to the service.
1724 long ident = Binder.clearCallingIdentity();
1725 try {
1726 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001727 utils.saveLockPassword(password, quality, false, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001728 synchronized (this) {
1729 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1730 != 0 ? callingUid : -1;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001731 if (policy.mPasswordOwner != newOwner) {
1732 policy.mPasswordOwner = newOwner;
1733 saveSettingsLocked(userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001734 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001735 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001736 } finally {
1737 Binder.restoreCallingIdentity(ident);
1738 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001739
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001740 return true;
1741 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001742
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001743 public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
1744 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001745 synchronized (this) {
1746 if (who == null) {
1747 throw new NullPointerException("ComponentName is null");
1748 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001749 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001750 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001751 if (ap.maximumTimeToUnlock != timeMs) {
1752 ap.maximumTimeToUnlock = timeMs;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001753 saveSettingsLocked(userHandle);
1754 updateMaximumTimeToLockLocked(getUserData(userHandle));
Dianne Hackbornd6847842010-01-12 18:14:19 -08001755 }
1756 }
1757 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001758
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001759 void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
1760 long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
1761 if (policy.mLastMaximumTimeToLock == timeMs) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001762 return;
1763 }
1764
1765 long ident = Binder.clearCallingIdentity();
1766 try {
1767 if (timeMs <= 0) {
1768 timeMs = Integer.MAX_VALUE;
1769 } else {
1770 // Make sure KEEP_SCREEN_ON is disabled, since that
1771 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07001772 Settings.Global.putInt(mContext.getContentResolver(),
1773 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001774 }
1775
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001776 policy.mLastMaximumTimeToLock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001777
1778 try {
Jeff Brown96307042012-07-27 15:51:34 -07001779 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001780 } catch (RemoteException e) {
1781 Slog.w(TAG, "Failure talking with power manager", e);
1782 }
1783 } finally {
1784 Binder.restoreCallingIdentity(ident);
1785 }
1786 }
1787
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001788 public long getMaximumTimeToLock(ComponentName who, int userHandle) {
1789 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001790 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001791 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001792
Dianne Hackborn254cb442010-01-27 19:23:59 -08001793 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001794 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001795 return admin != null ? admin.maximumTimeToUnlock : time;
1796 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001797
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001798 DevicePolicyData policy = getUserData(userHandle);
1799 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001800 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001801 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001802 if (time == 0) {
1803 time = admin.maximumTimeToUnlock;
1804 } else if (admin.maximumTimeToUnlock != 0
1805 && time > admin.maximumTimeToUnlock) {
1806 time = admin.maximumTimeToUnlock;
1807 }
1808 }
1809 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001810 }
1811 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001812
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001813 public void lockNow() {
1814 synchronized (this) {
1815 // This API can only be called by an active device admin,
1816 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001817 getActiveAdminForCallerLocked(null,
1818 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001819 lockNowUnchecked();
1820 }
1821 }
1822
1823 private void lockNowUnchecked() {
1824 long ident = Binder.clearCallingIdentity();
1825 try {
1826 // Power off the display
1827 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1828 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
1829 // Ensure the device is locked
1830 getWindowManager().lockNow();
1831 } catch (RemoteException e) {
1832 } finally {
1833 Binder.restoreCallingIdentity(ident);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001834 }
1835 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001836
Ben Komaloed48c8b2011-10-17 17:30:21 -07001837 private boolean isExtStorageEncrypted() {
1838 String state = SystemProperties.get("vold.decrypt");
1839 return !"".equals(state);
1840 }
1841
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001842 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001843 // If the SD card is encrypted and non-removable, we have to force a wipe.
1844 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1845 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1846
1847 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1848 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001849 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001850 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001851 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1852 mWakeLock.acquire(10000);
1853 mContext.startService(intent);
1854 } else {
1855 try {
1856 RecoverySystem.rebootWipeUserData(mContext);
1857 } catch (IOException e) {
1858 Slog.w(TAG, "Failed requesting data wipe", e);
1859 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001860 }
1861 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001862
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001863 public void wipeData(int flags, final int userHandle) {
1864 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001865 synchronized (this) {
1866 // This API can only be called by an active device admin,
1867 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001868 getActiveAdminForCallerLocked(null,
1869 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001870 long ident = Binder.clearCallingIdentity();
1871 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001872 if (userHandle == UserHandle.USER_OWNER) {
1873 wipeDataLocked(flags);
1874 } else {
1875 lockNowUnchecked();
1876 mHandler.post(new Runnable() {
1877 public void run() {
1878 try {
1879 ActivityManagerNative.getDefault().switchUser(0);
1880 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
1881 .removeUser(userHandle);
1882 } catch (RemoteException re) {
1883 // Shouldn't happen
1884 }
1885 }
1886 });
1887 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001888 } finally {
1889 Binder.restoreCallingIdentity(ident);
1890 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001891 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001892 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001893
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001894 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
1895 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001896 mContext.enforceCallingOrSelfPermission(
1897 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001898
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001899 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001900 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001901 if (admin == null) {
1902 try {
1903 result.sendResult(null);
1904 } catch (RemoteException e) {
1905 }
1906 return;
1907 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001908 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001909 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001910 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001911 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001912 @Override
1913 public void onReceive(Context context, Intent intent) {
1914 try {
1915 result.sendResult(getResultExtras(false));
1916 } catch (RemoteException e) {
1917 }
1918 }
1919 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001920 }
1921 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001922
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001923 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001924 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
1925 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001926 mContext.enforceCallingOrSelfPermission(
1927 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001928 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001929
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001930 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001931
Dianne Hackbornd6847842010-01-12 18:14:19 -08001932 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001933 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
1934 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
1935 || p.mActivePasswordUpperCase != uppercase
1936 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
1937 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001938 long ident = Binder.clearCallingIdentity();
1939 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001940 p.mActivePasswordQuality = quality;
1941 p.mActivePasswordLength = length;
1942 p.mActivePasswordLetters = letters;
1943 p.mActivePasswordLowerCase = lowercase;
1944 p.mActivePasswordUpperCase = uppercase;
1945 p.mActivePasswordNumeric = numbers;
1946 p.mActivePasswordSymbols = symbols;
1947 p.mActivePasswordNonLetter = nonletter;
1948 p.mFailedPasswordAttempts = 0;
1949 saveSettingsLocked(userHandle);
1950 updatePasswordExpirationsLocked(userHandle);
1951 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001952 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001953 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001954 } finally {
1955 Binder.restoreCallingIdentity(ident);
1956 }
1957 }
1958 }
1959 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001960
Andy Stadler043116a2010-11-29 17:43:32 -08001961 /**
1962 * Called any time the device password is updated. Resets all password expiration clocks.
1963 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001964 private void updatePasswordExpirationsLocked(int userHandle) {
1965 DevicePolicyData policy = getUserData(userHandle);
1966 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001967 if (N > 0) {
1968 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001969 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001970 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08001971 long timeout = admin.passwordExpirationTimeout;
1972 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1973 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08001974 }
1975 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001976 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001977 }
1978 }
1979
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001980 public void reportFailedPasswordAttempt(int userHandle) {
1981 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001982 mContext.enforceCallingOrSelfPermission(
1983 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001984
Dianne Hackbornd6847842010-01-12 18:14:19 -08001985 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001986 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001987 long ident = Binder.clearCallingIdentity();
1988 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001989 policy.mFailedPasswordAttempts++;
1990 saveSettingsLocked(userHandle);
1991 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
1992 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001993 wipeDataLocked(0);
1994 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001995 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001996 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001997 } finally {
1998 Binder.restoreCallingIdentity(ident);
1999 }
2000 }
2001 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002002
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002003 public void reportSuccessfulPasswordAttempt(int userHandle) {
2004 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002005 mContext.enforceCallingOrSelfPermission(
2006 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002007
Dianne Hackbornd6847842010-01-12 18:14:19 -08002008 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002009 DevicePolicyData policy = getUserData(userHandle);
2010 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002011 long ident = Binder.clearCallingIdentity();
2012 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002013 policy.mFailedPasswordAttempts = 0;
2014 policy.mPasswordOwner = -1;
2015 saveSettingsLocked(userHandle);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002016 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002017 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002018 } finally {
2019 Binder.restoreCallingIdentity(ident);
2020 }
2021 }
2022 }
2023 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002024
Oscar Montemayor69238c62010-08-03 10:51:06 -07002025 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002026 String exclusionList, int userHandle) {
2027 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002028 synchronized(this) {
2029 if (who == null) {
2030 throw new NullPointerException("ComponentName is null");
2031 }
2032
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002033 // Only check if owner has set global proxy. We don't allow other users to set it.
2034 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002035 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2036 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2037
2038 // Scan through active admins and find if anyone has already
2039 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002040 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002041 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002042 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002043 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2044 // Another admin already sets the global proxy
2045 // Return it to the caller.
2046 return component;
2047 }
2048 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002049
2050 // If the user is not the owner, don't set the global proxy. Fail silently.
2051 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2052 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2053 + userHandle + " is not permitted.");
2054 return null;
2055 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002056 if (proxySpec == null) {
2057 admin.specifiesGlobalProxy = false;
2058 admin.globalProxySpec = null;
2059 admin.globalProxyExclusionList = null;
2060 } else {
2061
2062 admin.specifiesGlobalProxy = true;
2063 admin.globalProxySpec = proxySpec;
2064 admin.globalProxyExclusionList = exclusionList;
2065 }
2066
2067 // Reset the global proxy accordingly
2068 // Do this using system permissions, as apps cannot write to secure settings
2069 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002070 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002071 Binder.restoreCallingIdentity(origId);
2072 return null;
2073 }
2074 }
2075
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002076 public ComponentName getGlobalProxyAdmin(int userHandle) {
2077 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002078 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002079 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002080 // Scan through active admins and find if anyone has already
2081 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002082 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002083 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002084 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002085 if (ap.specifiesGlobalProxy) {
2086 // Device admin sets the global proxy
2087 // Return it to the caller.
2088 return ap.info.getComponent();
2089 }
2090 }
2091 }
2092 // No device admin sets the global proxy.
2093 return null;
2094 }
2095
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002096 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2097 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002098 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002099 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002100 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002101 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002102 return;
2103 }
2104 }
2105 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002106 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002107 }
2108
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002109 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002110 if (exclusionList == null) {
2111 exclusionList = "";
2112 }
2113 if (proxySpec == null) {
2114 proxySpec = "";
2115 }
2116 // Remove white spaces
2117 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002118 String data[] = proxySpec.split(":");
2119 int proxyPort = 8080;
2120 if (data.length > 1) {
2121 try {
2122 proxyPort = Integer.parseInt(data[1]);
2123 } catch (NumberFormatException e) {}
2124 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002125 exclusionList = exclusionList.trim();
2126 ContentResolver res = mContext.getContentResolver();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002127 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
2128 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2129 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
2130 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002131 }
2132
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002133 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002134 * Set the storage encryption request for a single admin. Returns the new total request
2135 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002136 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002137 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
2138 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002139 synchronized (this) {
2140 // Check for permissions
2141 if (who == null) {
2142 throw new NullPointerException("ComponentName is null");
2143 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002144 // Only owner can set storage encryption
2145 if (userHandle != UserHandle.USER_OWNER
2146 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2147 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2148 + UserHandle.getCallingUserId() + " is not permitted.");
2149 return 0;
2150 }
2151
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002152 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2153 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2154
Andy Stadler22dbfda2011-01-17 12:47:31 -08002155 // Quick exit: If the filesystem does not support encryption, we can exit early.
2156 if (!isEncryptionSupported()) {
2157 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2158 }
2159
2160 // (1) Record the value for the admin so it's sticky
2161 if (ap.encryptionRequested != encrypt) {
2162 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002163 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002164 }
2165
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002166 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002167 // (2) Compute "max" for all admins
2168 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002169 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002170 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002171 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002172 }
2173
2174 // Notify OS of new request
2175 setEncryptionRequested(newRequested);
2176
2177 // Return the new global request status
2178 return newRequested
2179 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2180 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002181 }
2182 }
2183
2184 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002185 * Get the current storage encryption request status for a given admin, or aggregate of all
2186 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002187 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002188 public boolean getStorageEncryption(ComponentName who, int userHandle) {
2189 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002190 synchronized (this) {
2191 // Check for permissions if a particular caller is specified
2192 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002193 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002194 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002195 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002196 }
2197
Andy Stadler22dbfda2011-01-17 12:47:31 -08002198 // If no particular caller is specified, return the aggregate set of requests.
2199 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002200 DevicePolicyData policy = getUserData(userHandle);
2201 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002202 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002203 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002204 return true;
2205 }
2206 }
2207 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002208 }
2209 }
2210
Andy Stadler22dbfda2011-01-17 12:47:31 -08002211 /**
2212 * Get the current encryption status of the device.
2213 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002214 public int getStorageEncryptionStatus(int userHandle) {
2215 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002216 return getEncryptionStatus();
2217 }
2218
2219 /**
2220 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2221 */
2222 private boolean isEncryptionSupported() {
2223 // Note, this can be implemented as
2224 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2225 // But is provided as a separate internal method if there's a faster way to do a
2226 // simple check for supported-or-not.
2227 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2228 }
2229
2230 /**
2231 * Hook to low-levels: Reporting the current status of encryption.
2232 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2233 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2234 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2235 */
2236 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002237 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2238 if ("encrypted".equalsIgnoreCase(status)) {
2239 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2240 } else if ("unencrypted".equalsIgnoreCase(status)) {
2241 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2242 } else {
2243 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2244 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002245 }
2246
2247 /**
2248 * Hook to low-levels: If needed, record the new admin setting for encryption.
2249 */
2250 private void setEncryptionRequested(boolean encrypt) {
2251 }
2252
Ben Komalo2447edd2011-05-09 16:05:33 -07002253 /**
2254 * The system property used to share the state of the camera. The native camera service
2255 * is expected to read this property and act accordingly.
2256 */
2257 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2258
2259 /**
2260 * Disables all device cameras according to the specified admin.
2261 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002262 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
2263 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002264 synchronized (this) {
2265 if (who == null) {
2266 throw new NullPointerException("ComponentName is null");
2267 }
2268 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2269 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2270 if (ap.disableCamera != disabled) {
2271 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002272 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002273 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002274 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002275 }
2276 }
2277
2278 /**
2279 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2280 * active admins.
2281 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002282 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Ben Komalo2447edd2011-05-09 16:05:33 -07002283 synchronized (this) {
2284 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002285 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002286 return (admin != null) ? admin.disableCamera : false;
2287 }
2288
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002289 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002290 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002291 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002292 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002293 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002294 if (admin.disableCamera) {
2295 return true;
2296 }
2297 }
2298 return false;
2299 }
2300 }
2301
Jim Millerb8ec4702012-08-31 17:19:10 -07002302 /**
2303 * Selectively disable keyguard widgets.
2304 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002305 public void setKeyguardWidgetsDisabled(ComponentName who, int which, int userHandle) {
2306 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002307 synchronized (this) {
2308 if (who == null) {
2309 throw new NullPointerException("ComponentName is null");
2310 }
2311 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2312 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS);
2313 if ((ap.disableKeyguardWidgets & which) != which) {
2314 ap.disableKeyguardWidgets |= which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002315 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002316 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002317 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002318 }
2319 }
2320
2321 /**
2322 * Gets the disabled state for widgets in keyguard for the given admin,
2323 * or the aggregate of all active admins if who is null.
2324 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002325 public int getKeyguardWidgetsDisabled(ComponentName who, int userHandle) {
2326 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002327 synchronized (this) {
2328 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002329 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002330 return (admin != null) ? admin.disableKeyguardWidgets : 0;
2331 }
2332
2333 // Determine whether or not keyguard widgets are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002334 DevicePolicyData policy = getUserData(userHandle);
2335 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002336 int which = 0;
2337 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002338 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millerb8ec4702012-08-31 17:19:10 -07002339 which |= admin.disableKeyguardWidgets;
2340 }
2341 return which;
2342 }
2343 }
2344
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002345 private void enforceCrossUserPermission(int userHandle) {
2346 if (userHandle < 0) {
2347 throw new IllegalArgumentException("Invalid userId " + userHandle);
2348 }
2349 final int callingUid = Binder.getCallingUid();
2350 if (userHandle == UserHandle.getUserId(callingUid)) return;
2351 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2352 mContext.enforceCallingOrSelfPermission(
2353 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2354 + " INTERACT_ACROSS_USERS_FULL permission");
2355 }
2356 }
2357
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002358 @Override
2359 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2360 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2361 != PackageManager.PERMISSION_GRANTED) {
2362
2363 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2364 + Binder.getCallingPid()
2365 + ", uid=" + Binder.getCallingUid());
2366 return;
2367 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002368
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002369 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002370
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002371 synchronized (this) {
2372 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002373
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002374 int userCount = mUserData.size();
2375 for (int u = 0; u < userCount; u++) {
2376 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2377 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2378 final int N = policy.mAdminList.size();
2379 for (int i=0; i<N; i++) {
2380 ActiveAdmin ap = policy.mAdminList.get(i);
2381 if (ap != null) {
2382 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2383 pw.println(":");
2384 ap.dump(" ", pw);
2385 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002386 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002387
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002388 pw.println(" ");
2389 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2390 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002391 }
2392 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002393}