blob: d3e7c24cfa86c8cb27174bf3780f05ccc8b6ae8f [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 Yamasani71e6c692013-03-24 17:39:28 -070044import android.content.pm.ApplicationInfo;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070045import android.content.pm.IPackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070046import android.content.pm.PackageInfo;
Dianne Hackbornd6847842010-01-12 18:14:19 -080047import android.content.pm.PackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070048import android.content.pm.Signature;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080049import android.content.pm.PackageManager.NameNotFoundException;
Andy Stadler1f35d482010-11-19 15:39:41 -080050import android.content.pm.ResolveInfo;
Amith Yamasani71e6c692013-03-24 17:39:28 -070051import android.net.Uri;
Dianne Hackbornd6847842010-01-12 18:14:19 -080052import android.os.Binder;
Adam Cohenf7522022012-10-03 20:03:18 -070053import android.os.Bundle;
Ben Komaloed48c8b2011-10-17 17:30:21 -070054import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080055import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080056import android.os.IBinder;
57import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070058import android.os.PowerManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070059import android.os.Process;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080060import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080061import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080062import android.os.RemoteException;
63import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080064import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080065import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070066import android.os.UserHandle;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070067import android.os.UserManager;
Oscar Montemayor69238c62010-08-03 10:51:06 -070068import android.provider.Settings;
Amith Yamasani71e6c692013-03-24 17:39:28 -070069import android.util.AtomicFile;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080070import android.util.PrintWriterPrinter;
71import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080072import android.util.Slog;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070073import android.util.SparseArray;
Dianne Hackbornd6847842010-01-12 18:14:19 -080074import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080075import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080076import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080077
78import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080079import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080080import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070081import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080082import java.io.FileOutputStream;
83import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080084import java.io.PrintWriter;
Jim Millera4e28d12010-11-08 16:15:47 -080085import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080086import java.util.ArrayList;
Jim Millera4e28d12010-11-08 16:15:47 -080087import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -080088import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -080089import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -070090import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -080091
92/**
93 * Implementation of the device policy APIs.
94 */
95public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Amith Yamasani599dd7c2012-09-14 23:20:08 -070096
Jim Miller6b857682011-02-16 16:27:41 -080097 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -080098
Amith Yamasani71e6c692013-03-24 17:39:28 -070099 private static final String DEVICE_POLICIES_XML = "device_policies.xml";
100
Jim Miller6b857682011-02-16 16:27:41 -0800101 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700102
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700103 private static final long MS_PER_DAY = 86400 * 1000;
104
105 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
Jim Millera4e28d12010-11-08 16:15:47 -0800106
107 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
108 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
109
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700110 private static final boolean DBG = false;
Jim Millera4e28d12010-11-08 16:15:47 -0800111
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800112 final Context mContext;
Dianne Hackborn42499172010-10-15 18:45:07 -0700113 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800114
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800115 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800116 IWindowManager mIWindowManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700117
Amith Yamasani71e6c692013-03-24 17:39:28 -0700118 private DeviceOwner mDeviceOwner;
119
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700120 public static class DevicePolicyData {
121 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
122 int mActivePasswordLength = 0;
123 int mActivePasswordUpperCase = 0;
124 int mActivePasswordLowerCase = 0;
125 int mActivePasswordLetters = 0;
126 int mActivePasswordNumeric = 0;
127 int mActivePasswordSymbols = 0;
128 int mActivePasswordNonLetter = 0;
129 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700130
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700131 int mUserHandle;;
132 int mPasswordOwner = -1;
133 long mLastMaximumTimeToLock = -1;
134
135 final HashMap<ComponentName, ActiveAdmin> mAdminMap
136 = new HashMap<ComponentName, ActiveAdmin>();
137 final ArrayList<ActiveAdmin> mAdminList
138 = new ArrayList<ActiveAdmin>();
139
140 public DevicePolicyData(int userHandle) {
141 mUserHandle = userHandle;
142 }
143 }
144
145 final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
146
Jim Millera4e28d12010-11-08 16:15:47 -0800147 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700148
Jim Millera4e28d12010-11-08 16:15:47 -0800149 BroadcastReceiver mReceiver = new BroadcastReceiver() {
150 @Override
151 public void onReceive(Context context, Intent intent) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700152 final String action = intent.getAction();
153 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
154 getSendingUserId());
Jim Millera4e28d12010-11-08 16:15:47 -0800155 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
156 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800157 if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
158 + action + " for user " + userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800159 mHandler.post(new Runnable() {
160 public void run() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700161 handlePasswordExpirationNotification(getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -0800162 }
163 });
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700164 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
165 removeUserData(userHandle);
166 } else if (Intent.ACTION_USER_STARTED.equals(action)
167 || Intent.ACTION_PACKAGE_CHANGED.equals(action)
168 || Intent.ACTION_PACKAGE_REMOVED.equals(action)
169 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
170
171 if (Intent.ACTION_USER_STARTED.equals(action)) {
172 // Reset the policy data
173 synchronized (DevicePolicyManagerService.this) {
174 mUserData.remove(userHandle);
175 }
176 }
177
178 handlePackagesChanged(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800179 }
180 }
181 };
182
Dianne Hackbornd6847842010-01-12 18:14:19 -0800183 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800184 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700185
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800186 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700187
188 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
189 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
190
191 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
192 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
193
194 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
195 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
196
197 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
198 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
199
200 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700201 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700202
203 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
204 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
205
206 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
207 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
208
209 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
210 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
211
212 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
213 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
214
215 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
216 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
217
218 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
219 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
220
221 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
222 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
223
Jim Miller48b9b0d2012-09-19 23:16:50 -0700224 static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
225 int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
Jim Millerb8ec4702012-08-31 17:19:10 -0700226
Andy Stadler22dbfda2011-01-17 12:47:31 -0800227 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700228 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700229
Oscar Montemayor69238c62010-08-03 10:51:06 -0700230 // TODO: review implementation decisions with frameworks team
231 boolean specifiesGlobalProxy = false;
232 String globalProxySpec = null;
233 String globalProxyExclusionList = null;
234
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800235 ActiveAdmin(DeviceAdminInfo _info) {
236 info = _info;
237 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700238
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800239 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700240
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700241 public UserHandle getUserHandle() {
242 return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
243 }
244
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800245 void writeToXml(XmlSerializer out)
246 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800247 out.startTag(null, "policies");
248 info.writePoliciesToXml(out);
249 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800250 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
251 out.startTag(null, "password-quality");
252 out.attribute(null, "value", Integer.toString(passwordQuality));
253 out.endTag(null, "password-quality");
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700254 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800255 out.startTag(null, "min-password-length");
256 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700257 out.endTag(null, "min-password-length");
258 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700259 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700260 out.startTag(null, "password-history-length");
261 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
262 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800263 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700264 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700265 out.startTag(null, "min-password-uppercase");
266 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
267 out.endTag(null, "min-password-uppercase");
268 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700269 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700270 out.startTag(null, "min-password-lowercase");
271 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
272 out.endTag(null, "min-password-lowercase");
273 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700274 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700275 out.startTag(null, "min-password-letters");
276 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
277 out.endTag(null, "min-password-letters");
278 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700279 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700280 out.startTag(null, "min-password-numeric");
281 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
282 out.endTag(null, "min-password-numeric");
283 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700284 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700285 out.startTag(null, "min-password-symbols");
286 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
287 out.endTag(null, "min-password-symbols");
288 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700289 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700290 out.startTag(null, "min-password-nonletter");
291 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
292 out.endTag(null, "min-password-nonletter");
293 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800294 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700295 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800296 out.startTag(null, "max-time-to-unlock");
297 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
298 out.endTag(null, "max-time-to-unlock");
299 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700300 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800301 out.startTag(null, "max-failed-password-wipe");
302 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
303 out.endTag(null, "max-failed-password-wipe");
304 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700305 if (specifiesGlobalProxy) {
306 out.startTag(null, "specifies-global-proxy");
307 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
308 out.endTag(null, "specifies_global_proxy");
309 if (globalProxySpec != null) {
310 out.startTag(null, "global-proxy-spec");
311 out.attribute(null, "value", globalProxySpec);
312 out.endTag(null, "global-proxy-spec");
313 }
314 if (globalProxyExclusionList != null) {
315 out.startTag(null, "global-proxy-exclusion-list");
316 out.attribute(null, "value", globalProxyExclusionList);
317 out.endTag(null, "global-proxy-exclusion-list");
318 }
319 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700320 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800321 out.startTag(null, "password-expiration-timeout");
322 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
323 out.endTag(null, "password-expiration-timeout");
324 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700325 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800326 out.startTag(null, "password-expiration-date");
327 out.attribute(null, "value", Long.toString(passwordExpirationDate));
328 out.endTag(null, "password-expiration-date");
329 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800330 if (encryptionRequested) {
331 out.startTag(null, "encryption-requested");
332 out.attribute(null, "value", Boolean.toString(encryptionRequested));
333 out.endTag(null, "encryption-requested");
334 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700335 if (disableCamera) {
336 out.startTag(null, "disable-camera");
337 out.attribute(null, "value", Boolean.toString(disableCamera));
338 out.endTag(null, "disable-camera");
339 }
Jim Miller48b9b0d2012-09-19 23:16:50 -0700340 if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
341 out.startTag(null, "disable-keyguard-features");
342 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
343 out.endTag(null, "disable-keyguard-features");
Jim Millerb8ec4702012-08-31 17:19:10 -0700344 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800345 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700346
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800347 void readFromXml(XmlPullParser parser)
348 throws XmlPullParserException, IOException {
349 int outerDepth = parser.getDepth();
350 int type;
351 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
352 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
353 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
354 continue;
355 }
356 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800357 if ("policies".equals(tag)) {
358 info.readPoliciesFromXml(parser);
359 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800360 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800361 parser.getAttributeValue(null, "value"));
362 } else if ("min-password-length".equals(tag)) {
363 minimumPasswordLength = Integer.parseInt(
364 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700365 } else if ("password-history-length".equals(tag)) {
366 passwordHistoryLength = Integer.parseInt(
367 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700368 } else if ("min-password-uppercase".equals(tag)) {
369 minimumPasswordUpperCase = Integer.parseInt(
370 parser.getAttributeValue(null, "value"));
371 } else if ("min-password-lowercase".equals(tag)) {
372 minimumPasswordLowerCase = Integer.parseInt(
373 parser.getAttributeValue(null, "value"));
374 } else if ("min-password-letters".equals(tag)) {
375 minimumPasswordLetters = Integer.parseInt(
376 parser.getAttributeValue(null, "value"));
377 } else if ("min-password-numeric".equals(tag)) {
378 minimumPasswordNumeric = Integer.parseInt(
379 parser.getAttributeValue(null, "value"));
380 } else if ("min-password-symbols".equals(tag)) {
381 minimumPasswordSymbols = Integer.parseInt(
382 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700383 } else if ("min-password-nonletter".equals(tag)) {
384 minimumPasswordNonLetter = Integer.parseInt(
385 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800386 } else if ("max-time-to-unlock".equals(tag)) {
387 maximumTimeToUnlock = Long.parseLong(
388 parser.getAttributeValue(null, "value"));
389 } else if ("max-failed-password-wipe".equals(tag)) {
390 maximumFailedPasswordsForWipe = Integer.parseInt(
391 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700392 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800393 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700394 parser.getAttributeValue(null, "value"));
395 } else if ("global-proxy-spec".equals(tag)) {
396 globalProxySpec =
397 parser.getAttributeValue(null, "value");
398 } else if ("global-proxy-exclusion-list".equals(tag)) {
399 globalProxyExclusionList =
400 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800401 } else if ("password-expiration-timeout".equals(tag)) {
402 passwordExpirationTimeout = Long.parseLong(
403 parser.getAttributeValue(null, "value"));
404 } else if ("password-expiration-date".equals(tag)) {
405 passwordExpirationDate = Long.parseLong(
406 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800407 } else if ("encryption-requested".equals(tag)) {
408 encryptionRequested = Boolean.parseBoolean(
409 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700410 } else if ("disable-camera".equals(tag)) {
411 disableCamera = Boolean.parseBoolean(
412 parser.getAttributeValue(null, "value"));
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700413 } else if ("disable-keyguard-features".equals(tag)) {
414 disabledKeyguardFeatures = Integer.parseInt(
415 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800416 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700417 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800418 }
419 XmlUtils.skipCurrentTag(parser);
420 }
421 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700422
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800423 void dump(String prefix, PrintWriter pw) {
424 pw.print(prefix); pw.print("uid="); pw.println(getUid());
425 pw.print(prefix); pw.println("policies:");
426 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
427 if (pols != null) {
428 for (int i=0; i<pols.size(); i++) {
429 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
430 }
431 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700432 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700433 pw.println(Integer.toHexString(passwordQuality));
434 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800435 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700436 pw.print(prefix); pw.print("passwordHistoryLength=");
437 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700438 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
439 pw.println(minimumPasswordUpperCase);
440 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
441 pw.println(minimumPasswordLowerCase);
442 pw.print(prefix); pw.print("minimumPasswordLetters=");
443 pw.println(minimumPasswordLetters);
444 pw.print(prefix); pw.print("minimumPasswordNumeric=");
445 pw.println(minimumPasswordNumeric);
446 pw.print(prefix); pw.print("minimumPasswordSymbols=");
447 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700448 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
449 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800450 pw.print(prefix); pw.print("maximumTimeToUnlock=");
451 pw.println(maximumTimeToUnlock);
452 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
453 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700454 pw.print(prefix); pw.print("specifiesGlobalProxy=");
455 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800456 pw.print(prefix); pw.print("passwordExpirationTimeout=");
457 pw.println(passwordExpirationTimeout);
458 pw.print(prefix); pw.print("passwordExpirationDate=");
459 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700460 if (globalProxySpec != null) {
461 pw.print(prefix); pw.print("globalProxySpec=");
462 pw.println(globalProxySpec);
463 }
464 if (globalProxyExclusionList != null) {
465 pw.print(prefix); pw.print("globalProxyEclusionList=");
466 pw.println(globalProxyExclusionList);
467 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800468 pw.print(prefix); pw.print("encryptionRequested=");
469 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700470 pw.print(prefix); pw.print("disableCamera=");
471 pw.println(disableCamera);
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700472 pw.print(prefix); pw.print("disabledKeyguardFeatures=");
473 pw.println(disabledKeyguardFeatures);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800474 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800475 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700476
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700477 private void handlePackagesChanged(int userHandle) {
478 boolean removed = false;
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800479 if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700480 DevicePolicyData policy = getUserData(userHandle);
481 IPackageManager pm = AppGlobals.getPackageManager();
482 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
483 ActiveAdmin aa = policy.mAdminList.get(i);
484 try {
485 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
486 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
487 removed = true;
488 policy.mAdminList.remove(i);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800489 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700490 } catch (RemoteException re) {
491 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800492 }
493 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700494 if (removed) {
495 validatePasswordOwnerLocked(policy);
496 syncDeviceCapabilitiesLocked(policy);
497 saveSettingsLocked(policy.mUserHandle);
498 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800499 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700500
Dianne Hackbornd6847842010-01-12 18:14:19 -0800501 /**
502 * Instantiates the service.
503 */
504 public DevicePolicyManagerService(Context context) {
505 mContext = context;
Dianne Hackborn42499172010-10-15 18:45:07 -0700506 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
507 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800508 IntentFilter filter = new IntentFilter();
509 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
510 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700511 filter.addAction(Intent.ACTION_USER_REMOVED);
512 filter.addAction(Intent.ACTION_USER_STARTED);
513 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
514 filter = new IntentFilter();
515 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
516 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
517 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Amith Yamasani71e6c692013-03-24 17:39:28 -0700518 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700519 filter.addDataScheme("package");
520 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
521 }
522
523 /**
524 * Creates and loads the policy data from xml.
525 * @param userHandle the user for whom to load the policy data
526 * @return
527 */
528 DevicePolicyData getUserData(int userHandle) {
529 synchronized (this) {
530 DevicePolicyData policy = mUserData.get(userHandle);
531 if (policy == null) {
532 policy = new DevicePolicyData(userHandle);
533 mUserData.append(userHandle, policy);
534 loadSettingsLocked(policy, userHandle);
535 }
536 return policy;
537 }
538 }
539
540 void removeUserData(int userHandle) {
541 synchronized (this) {
542 if (userHandle == UserHandle.USER_OWNER) {
543 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
544 return;
545 }
546 DevicePolicyData policy = mUserData.get(userHandle);
547 if (policy != null) {
548 mUserData.remove(userHandle);
549 }
550 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
551 DEVICE_POLICIES_XML);
552 policyFile.delete();
553 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
554 }
Jim Millera4e28d12010-11-08 16:15:47 -0800555 }
556
Amith Yamasani71e6c692013-03-24 17:39:28 -0700557 void loadDeviceOwner() {
558 synchronized (this) {
559 if (DeviceOwner.isRegistered()) {
560 mDeviceOwner = new DeviceOwner();
561 }
562 }
563 }
564
Andy Stadler043116a2010-11-29 17:43:32 -0800565 /**
566 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
567 * reminders. Clears alarm if no expirations are configured.
568 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700569 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
570 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800571 final long now = System.currentTimeMillis();
572 final long timeToExpire = expiration - now;
573 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800574 if (expiration == 0) {
575 // No expirations are currently configured: Cancel alarm.
576 alarmTime = 0;
577 } else if (timeToExpire <= 0) {
578 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800579 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800580 } else {
581 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
582 // the expiration time.
583 long alarmInterval = timeToExpire % MS_PER_DAY;
584 if (alarmInterval == 0) {
585 alarmInterval = MS_PER_DAY;
586 }
587 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800588 }
589
Andy Stadler1f35d482010-11-19 15:39:41 -0800590 long token = Binder.clearCallingIdentity();
591 try {
592 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700593 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800594 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700595 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
596 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800597 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800598 if (alarmTime != 0) {
599 am.set(AlarmManager.RTC, alarmTime, pi);
600 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800601 } finally {
602 Binder.restoreCallingIdentity(token);
603 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800604 }
605
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800606 private IPowerManager getIPowerManager() {
607 if (mIPowerManager == null) {
608 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
609 mIPowerManager = IPowerManager.Stub.asInterface(b);
610 }
611 return mIPowerManager;
612 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700613
Jim Miller93c518e2012-01-17 15:55:31 -0800614 private IWindowManager getWindowManager() {
615 if (mIWindowManager == null) {
616 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
617 mIWindowManager = IWindowManager.Stub.asInterface(b);
618 }
619 return mIWindowManager;
620 }
621
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700622 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
623 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800624 if (admin != null
625 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
626 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
627 return admin;
628 }
629 return null;
630 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700631
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800632 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
633 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800634 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700635 final int userHandle = UserHandle.getUserId(callingUid);
636 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800637 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700638 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800639 if (admin == null) {
640 throw new SecurityException("No active admin " + who);
641 }
642 if (admin.getUid() != callingUid) {
643 throw new SecurityException("Admin " + who + " is not owned by uid "
644 + Binder.getCallingUid());
645 }
646 if (!admin.info.usesPolicy(reqPolicy)) {
647 throw new SecurityException("Admin " + admin.info.getComponent()
648 + " did not specify uses-policy for: "
649 + admin.info.getTagForPolicy(reqPolicy));
650 }
651 return admin;
652 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700653 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800654 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700655 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800656 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
657 return admin;
658 }
659 }
660 throw new SecurityException("No active admin owned by uid "
661 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800662 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800663 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700664
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800665 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700666 sendAdminCommandLocked(admin, action, null);
667 }
668
669 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800670 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800671 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800672 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
673 intent.putExtra("expiration", admin.passwordExpirationDate);
674 }
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700675 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700676 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700677 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700678 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700679 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700680 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800681 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700682
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700683 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
684 final DevicePolicyData policy = getUserData(userHandle);
685 final int count = policy.mAdminList.size();
686 if (count > 0) {
687 for (int i = 0; i < count; i++) {
688 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800689 if (admin.info.usesPolicy(reqPolicy)) {
690 sendAdminCommandLocked(admin, action);
691 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800692 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800693 }
694 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700695
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700696 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
697 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800698 if (admin != null) {
699 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700700 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
701 new BroadcastReceiver() {
702 @Override
703 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700704 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700705 int userHandle = admin.getUserHandle().getIdentifier();
706 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700707 boolean doProxyCleanup = admin.info.usesPolicy(
708 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700709 policy.mAdminList.remove(admin);
710 policy.mAdminMap.remove(adminReceiver);
711 validatePasswordOwnerLocked(policy);
712 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700713 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700714 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700715 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700716 saveSettingsLocked(userHandle);
717 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb2011-05-25 10:48:28 -0700718 }
719 }
720 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800721 }
722 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700723
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700724 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
725 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800726 Intent resolveIntent = new Intent();
727 resolveIntent.setComponent(adminName);
728 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani71e6c692013-03-24 17:39:28 -0700729 resolveIntent,
730 PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
731 userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800732 if (infos == null || infos.size() <= 0) {
733 throw new IllegalArgumentException("Unknown admin: " + adminName);
734 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700735
Dianne Hackbornd6847842010-01-12 18:14:19 -0800736 try {
737 return new DeviceAdminInfo(mContext, infos.get(0));
738 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700739 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800740 return null;
741 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700742 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800743 return null;
744 }
745 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700746
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700747 private static JournaledFile makeJournaledFile(int userHandle) {
748 final String base = userHandle == 0
749 ? "/data/system/" + DEVICE_POLICIES_XML
750 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
751 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800752 return new JournaledFile(new File(base), new File(base + ".tmp"));
753 }
754
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700755 private void saveSettingsLocked(int userHandle) {
756 DevicePolicyData policy = getUserData(userHandle);
757 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800758 FileOutputStream stream = null;
759 try {
760 stream = new FileOutputStream(journal.chooseForWrite(), false);
761 XmlSerializer out = new FastXmlSerializer();
762 out.setOutput(stream, "utf-8");
763 out.startDocument(null, true);
764
765 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700766
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700767 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800768 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700769 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800770 if (ap != null) {
771 out.startTag(null, "admin");
772 out.attribute(null, "name", ap.info.getComponent().flattenToString());
773 ap.writeToXml(out);
774 out.endTag(null, "admin");
775 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800776 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700777
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700778 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800779 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700780 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800781 out.endTag(null, "password-owner");
782 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700783
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700784 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800785 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700786 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800787 out.endTag(null, "failed-password-attempts");
788 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700789
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700790 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
791 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
792 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
793 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700794 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700795 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
796 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
797 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
798 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
799 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700800 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700801 .toString(policy.mActivePasswordNumeric));
802 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
803 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700804 out.endTag(null, "active-password");
805 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700806
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700807 out.endTag(null, "policies");
808
Dianne Hackbornd6847842010-01-12 18:14:19 -0800809 out.endDocument();
810 stream.close();
811 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700812 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800813 } catch (IOException e) {
814 try {
815 if (stream != null) {
816 stream.close();
817 }
818 } catch (IOException ex) {
819 // Ignore
820 }
821 journal.rollback();
822 }
823 }
824
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700825 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700826 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
827 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700828 long ident = Binder.clearCallingIdentity();
829 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700830 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700831 } finally {
832 Binder.restoreCallingIdentity(ident);
833 }
Jim Miller284b62e2010-06-08 14:27:42 -0700834 }
835
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700836 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
837 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800838 FileInputStream stream = null;
839 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800840 try {
841 stream = new FileInputStream(file);
842 XmlPullParser parser = Xml.newPullParser();
843 parser.setInput(stream, null);
844
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800845 int type;
846 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
847 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800848 }
849 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800850 if (!"policies".equals(tag)) {
851 throw new XmlPullParserException(
852 "Settings do not start with policies tag: found " + tag);
853 }
854 type = parser.next();
855 int outerDepth = parser.getDepth();
856 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
857 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
858 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
859 continue;
860 }
861 tag = parser.getName();
862 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800863 String name = parser.getAttributeValue(null, "name");
864 try {
865 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700866 ComponentName.unflattenFromString(name), userHandle);
867 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
868 != userHandle)) {
869 Slog.w(TAG, "findAdmin returned an incorrect uid "
870 + dai.getActivityInfo().applicationInfo.uid + " for user "
871 + userHandle);
872 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800873 if (dai != null) {
874 ActiveAdmin ap = new ActiveAdmin(dai);
875 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700876 policy.mAdminMap.put(ap.info.getComponent(), ap);
877 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800878 }
879 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700880 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800881 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800882 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700883 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800884 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800885 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800886 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700887 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800888 parser.getAttributeValue(null, "value"));
889 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700890 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700891 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700892 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700893 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700894 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700895 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700896 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700897 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700898 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700899 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700900 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700901 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700902 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700903 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700904 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700905 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700906 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700907 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800908 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700909 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800910 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800911 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800912 }
913 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700914 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800915 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700916 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800917 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700918 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700919 } catch (FileNotFoundException e) {
920 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800921 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700922 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800923 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700924 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800925 }
926 try {
927 if (stream != null) {
928 stream.close();
929 }
930 } catch (IOException e) {
931 // Ignore
932 }
933
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700934 // Validate that what we stored for the password quality matches
935 // sufficiently what is currently set. Note that this is only
936 // a sanity check in case the two get out of sync; this should
937 // never normally happen.
938 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700939 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700940 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700941 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700942 + " does not match actual quality 0x"
943 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700944 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
945 policy.mActivePasswordLength = 0;
946 policy.mActivePasswordUpperCase = 0;
947 policy.mActivePasswordLowerCase = 0;
948 policy.mActivePasswordLetters = 0;
949 policy.mActivePasswordNumeric = 0;
950 policy.mActivePasswordSymbols = 0;
951 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700952 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700953
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700954 validatePasswordOwnerLocked(policy);
955 syncDeviceCapabilitiesLocked(policy);
956 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800957 }
958
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700959 static void validateQualityConstant(int quality) {
960 switch (quality) {
961 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500962 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700963 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
964 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
965 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
966 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700967 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700968 return;
969 }
970 throw new IllegalArgumentException("Invalid quality constant: 0x"
971 + Integer.toHexString(quality));
972 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700973
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700974 void validatePasswordOwnerLocked(DevicePolicyData policy) {
975 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800976 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700977 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
978 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800979 haveOwner = true;
980 break;
981 }
982 }
983 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700984 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800985 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700986 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800987 }
988 }
989 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700990
Ben Komalo2447edd2011-05-09 16:05:33 -0700991 /**
992 * Pushes down policy information to the system for any policies related to general device
993 * capabilities that need to be enforced by lower level services (e.g. Camera services).
994 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700995 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -0700996 // Ensure the status of the camera is synced down to the system. Interested native services
997 // should monitor this value and act accordingly.
998 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700999 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07001000 if (cameraDisabled != systemState) {
1001 long token = Binder.clearCallingIdentity();
1002 try {
1003 String value = cameraDisabled ? "1" : "0";
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001004 if (DBG) Slog.v(TAG, "Change in camera state ["
Ben Komalo2447edd2011-05-09 16:05:33 -07001005 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
1006 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
1007 } finally {
1008 Binder.restoreCallingIdentity(token);
1009 }
1010 }
1011 }
1012
Dianne Hackbornd6847842010-01-12 18:14:19 -08001013 public void systemReady() {
1014 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001015 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001016 loadDeviceOwner();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001017 }
1018 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001019
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001020 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -08001021 synchronized (this) {
1022 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001023 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001024 if (N <= 0) {
1025 return;
1026 }
1027 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001028 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001029 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1030 && admin.passwordExpirationTimeout > 0L
1031 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001032 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001033 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1034 }
1035 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001036 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001037 }
1038 }
1039
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001040 /**
1041 * @param adminReceiver The admin to add
1042 * @param refreshing true = update an active admin, no error
1043 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001044 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001045 mContext.enforceCallingOrSelfPermission(
1046 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001047 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001048
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001049 DevicePolicyData policy = getUserData(userHandle);
1050 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001051 if (info == null) {
1052 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1053 }
1054 synchronized (this) {
1055 long ident = Binder.clearCallingIdentity();
1056 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001057 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001058 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001059 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001060 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001061 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001062 int replaceIndex = -1;
1063 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001064 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001065 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001066 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001067 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1068 replaceIndex = i;
1069 break;
1070 }
1071 }
1072 }
1073 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001074 policy.mAdminList.add(newAdmin);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001075 enableIfNecessary(info.getPackageName(), userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001076 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001077 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001078 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001079 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001080 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001081 } finally {
1082 Binder.restoreCallingIdentity(ident);
1083 }
1084 }
1085 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001086
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001087 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
1088 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001089 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001090 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001091 }
1092 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001093
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001094 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
1095 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001096 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001097 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001098 if (administrator == null) {
1099 throw new SecurityException("No active admin " + adminReceiver);
1100 }
1101 return administrator.info.usesPolicy(policyId);
1102 }
1103 }
1104
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001105 public List<ComponentName> getActiveAdmins(int userHandle) {
1106 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001107 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001108 DevicePolicyData policy = getUserData(userHandle);
1109 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001110 if (N <= 0) {
1111 return null;
1112 }
1113 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1114 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001115 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001116 }
1117 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001118 }
1119 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001120
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001121 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
1122 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001123 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001124 DevicePolicyData policy = getUserData(userHandle);
1125 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001126 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001127 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001128 return true;
1129 }
1130 }
1131 return false;
1132 }
1133 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001134
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001135 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
1136 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001137 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001138 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001139 if (admin == null) {
1140 return;
1141 }
1142 if (admin.getUid() != Binder.getCallingUid()) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07001143 // If trying to remove device owner, refuse when the caller is not the owner.
1144 if (mDeviceOwner != null
1145 && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
1146 return;
1147 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001148 mContext.enforceCallingOrSelfPermission(
1149 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1150 }
1151 long ident = Binder.clearCallingIdentity();
1152 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001153 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001154 } finally {
1155 Binder.restoreCallingIdentity(ident);
1156 }
1157 }
1158 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001159
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001160 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001161 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001162 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001163
Dianne Hackbornd6847842010-01-12 18:14:19 -08001164 synchronized (this) {
1165 if (who == null) {
1166 throw new NullPointerException("ComponentName is null");
1167 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001168 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1169 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001170 if (ap.passwordQuality != quality) {
1171 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001172 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001173 }
1174 }
1175 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001176
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001177 public int getPasswordQuality(ComponentName who, int userHandle) {
1178 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001179 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001180 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001181 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001182
Dianne Hackborn254cb442010-01-27 19:23:59 -08001183 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001184 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001185 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001186 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001187
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001188 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001189 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001190 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001191 if (mode < admin.passwordQuality) {
1192 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001193 }
1194 }
1195 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001196 }
1197 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001198
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001199 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
1200 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001201 synchronized (this) {
1202 if (who == null) {
1203 throw new NullPointerException("ComponentName is null");
1204 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001205 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1206 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001207 if (ap.minimumPasswordLength != length) {
1208 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001209 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001210 }
1211 }
1212 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001213
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001214 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
1215 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001216 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001217 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001218 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001219
Dianne Hackborn254cb442010-01-27 19:23:59 -08001220 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001221 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001222 return admin != null ? admin.minimumPasswordLength : length;
1223 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001224
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001225 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001226 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001227 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001228 if (length < admin.minimumPasswordLength) {
1229 length = admin.minimumPasswordLength;
1230 }
1231 }
1232 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001233 }
1234 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001235
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001236 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
1237 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001238 synchronized (this) {
1239 if (who == null) {
1240 throw new NullPointerException("ComponentName is null");
1241 }
1242 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1243 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1244 if (ap.passwordHistoryLength != length) {
1245 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001246 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001247 }
1248 }
1249 }
1250
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001251 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
1252 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001253 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001254 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001255 int length = 0;
1256
1257 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001258 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001259 return admin != null ? admin.passwordHistoryLength : length;
1260 }
1261
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001262 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001263 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001264 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001265 if (length < admin.passwordHistoryLength) {
1266 length = admin.passwordHistoryLength;
1267 }
1268 }
1269 return length;
1270 }
1271 }
1272
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001273 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
1274 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001275 synchronized (this) {
1276 if (who == null) {
1277 throw new NullPointerException("ComponentName is null");
1278 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001279 if (timeout < 0) {
1280 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001281 }
1282 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1283 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1284 // Calling this API automatically bumps the expiration date
1285 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1286 ap.passwordExpirationDate = expiration;
1287 ap.passwordExpirationTimeout = timeout;
1288 if (timeout > 0L) {
1289 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1290 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1291 .format(new Date(expiration)));
1292 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001293 saveSettingsLocked(userHandle);
1294 // in case this is the first one
1295 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001296 }
1297 }
1298
Andy Stadler043116a2010-11-29 17:43:32 -08001299 /**
1300 * Return a single admin's expiration cycle time, or the min of all cycle times.
1301 * Returns 0 if not configured.
1302 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001303 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
1304 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001305 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001306 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001307 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001308 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001309 }
1310
Andy Stadler043116a2010-11-29 17:43:32 -08001311 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001312 DevicePolicyData policy = getUserData(userHandle);
1313 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001314 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001315 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001316 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1317 && timeout > admin.passwordExpirationTimeout)) {
1318 timeout = admin.passwordExpirationTimeout;
1319 }
1320 }
1321 return timeout;
1322 }
1323 }
1324
Andy Stadler043116a2010-11-29 17:43:32 -08001325 /**
1326 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1327 * Returns 0 if not configured.
1328 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001329 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001330 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001331 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001332 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001333 }
1334
Andy Stadler043116a2010-11-29 17:43:32 -08001335 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001336 DevicePolicyData policy = getUserData(userHandle);
1337 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001338 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001339 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001340 if (timeout == 0L || (admin.passwordExpirationDate != 0
1341 && timeout > admin.passwordExpirationDate)) {
1342 timeout = admin.passwordExpirationDate;
1343 }
1344 }
1345 return timeout;
1346 }
1347
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001348 public long getPasswordExpiration(ComponentName who, int userHandle) {
1349 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001350 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001351 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001352 }
1353 }
1354
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001355 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
1356 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001357 synchronized (this) {
1358 if (who == null) {
1359 throw new NullPointerException("ComponentName is null");
1360 }
1361 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1362 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1363 if (ap.minimumPasswordUpperCase != length) {
1364 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001365 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001366 }
1367 }
1368 }
1369
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001370 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
1371 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001372 synchronized (this) {
1373 int length = 0;
1374
1375 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001376 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001377 return admin != null ? admin.minimumPasswordUpperCase : length;
1378 }
1379
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001380 DevicePolicyData policy = getUserData(userHandle);
1381 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001382 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001383 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001384 if (length < admin.minimumPasswordUpperCase) {
1385 length = admin.minimumPasswordUpperCase;
1386 }
1387 }
1388 return length;
1389 }
1390 }
1391
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001392 public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
1393 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001394 synchronized (this) {
1395 if (who == null) {
1396 throw new NullPointerException("ComponentName is null");
1397 }
1398 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1399 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1400 if (ap.minimumPasswordLowerCase != length) {
1401 ap.minimumPasswordLowerCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001402 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001403 }
1404 }
1405 }
1406
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001407 public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
1408 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001409 synchronized (this) {
1410 int length = 0;
1411
1412 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001413 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001414 return admin != null ? admin.minimumPasswordLowerCase : length;
1415 }
1416
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001417 DevicePolicyData policy = getUserData(userHandle);
1418 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001419 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001420 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001421 if (length < admin.minimumPasswordLowerCase) {
1422 length = admin.minimumPasswordLowerCase;
1423 }
1424 }
1425 return length;
1426 }
1427 }
1428
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001429 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
1430 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001431 synchronized (this) {
1432 if (who == null) {
1433 throw new NullPointerException("ComponentName is null");
1434 }
1435 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1436 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1437 if (ap.minimumPasswordLetters != length) {
1438 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001439 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001440 }
1441 }
1442 }
1443
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001444 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
1445 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001446 synchronized (this) {
1447 int length = 0;
1448
1449 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001450 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001451 return admin != null ? admin.minimumPasswordLetters : length;
1452 }
1453
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001454 DevicePolicyData policy = getUserData(userHandle);
1455 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001456 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001457 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001458 if (length < admin.minimumPasswordLetters) {
1459 length = admin.minimumPasswordLetters;
1460 }
1461 }
1462 return length;
1463 }
1464 }
1465
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001466 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
1467 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001468 synchronized (this) {
1469 if (who == null) {
1470 throw new NullPointerException("ComponentName is null");
1471 }
1472 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1473 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1474 if (ap.minimumPasswordNumeric != length) {
1475 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001476 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001477 }
1478 }
1479 }
1480
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001481 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
1482 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001483 synchronized (this) {
1484 int length = 0;
1485
1486 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001487 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001488 return admin != null ? admin.minimumPasswordNumeric : length;
1489 }
1490
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001491 DevicePolicyData policy = getUserData(userHandle);
1492 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001493 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001494 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001495 if (length < admin.minimumPasswordNumeric) {
1496 length = admin.minimumPasswordNumeric;
1497 }
1498 }
1499 return length;
1500 }
1501 }
1502
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001503 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
1504 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001505 synchronized (this) {
1506 if (who == null) {
1507 throw new NullPointerException("ComponentName is null");
1508 }
1509 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1510 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1511 if (ap.minimumPasswordSymbols != length) {
1512 ap.minimumPasswordSymbols = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001513 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001514 }
1515 }
1516 }
1517
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001518 public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
1519 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001520 synchronized (this) {
1521 int length = 0;
1522
1523 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001524 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001525 return admin != null ? admin.minimumPasswordSymbols : length;
1526 }
1527
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001528 DevicePolicyData policy = getUserData(userHandle);
1529 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001530 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001531 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001532 if (length < admin.minimumPasswordSymbols) {
1533 length = admin.minimumPasswordSymbols;
1534 }
1535 }
1536 return length;
1537 }
1538 }
1539
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001540 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
1541 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001542 synchronized (this) {
1543 if (who == null) {
1544 throw new NullPointerException("ComponentName is null");
1545 }
1546 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1547 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1548 if (ap.minimumPasswordNonLetter != length) {
1549 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001550 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001551 }
1552 }
1553 }
1554
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001555 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
1556 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001557 synchronized (this) {
1558 int length = 0;
1559
1560 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001561 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001562 return admin != null ? admin.minimumPasswordNonLetter : length;
1563 }
1564
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001565 DevicePolicyData policy = getUserData(userHandle);
1566 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001567 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001568 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001569 if (length < admin.minimumPasswordNonLetter) {
1570 length = admin.minimumPasswordNonLetter;
1571 }
1572 }
1573 return length;
1574 }
1575 }
1576
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001577 public boolean isActivePasswordSufficient(int userHandle) {
1578 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001579 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001580 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001581 // This API can only be called by an active device admin,
1582 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001583 getActiveAdminForCallerLocked(null,
1584 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001585 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1586 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001587 return false;
1588 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001589 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001590 return true;
1591 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001592 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1593 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1594 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1595 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1596 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1597 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001598 }
1599 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001600
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001601 public int getCurrentFailedPasswordAttempts(int userHandle) {
1602 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001603 synchronized (this) {
1604 // This API can only be called by an active device admin,
1605 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001606 getActiveAdminForCallerLocked(null,
1607 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001608 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001609 }
1610 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001611
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001612 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
1613 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001614 synchronized (this) {
1615 // This API can only be called by an active device admin,
1616 // so try to retrieve it to check that the caller is one.
1617 getActiveAdminForCallerLocked(who,
1618 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1619 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1620 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1621 if (ap.maximumFailedPasswordsForWipe != num) {
1622 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001623 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001624 }
1625 }
1626 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001627
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001628 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
1629 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001630 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001631 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001632 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001633
Dianne Hackborn254cb442010-01-27 19:23:59 -08001634 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001635 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001636 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1637 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001638
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001639 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001640 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001641 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001642 if (count == 0) {
1643 count = admin.maximumFailedPasswordsForWipe;
1644 } else if (admin.maximumFailedPasswordsForWipe != 0
1645 && count > admin.maximumFailedPasswordsForWipe) {
1646 count = admin.maximumFailedPasswordsForWipe;
1647 }
1648 }
1649 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001650 }
1651 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001652
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001653 public boolean resetPassword(String password, int flags, int userHandle) {
1654 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001655 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001656 synchronized (this) {
1657 // This API can only be called by an active device admin,
1658 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001659 getActiveAdminForCallerLocked(null,
1660 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001661 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001662 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001663 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001664 if (realQuality < quality
1665 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001666 Slog.w(TAG, "resetPassword: password quality 0x"
1667 + Integer.toHexString(quality)
1668 + " does not meet required quality 0x"
1669 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001670 return false;
1671 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001672 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001673 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001674 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001675 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001676 Slog.w(TAG, "resetPassword: password length " + password.length()
1677 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001678 return false;
1679 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001680 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1681 int letters = 0;
1682 int uppercase = 0;
1683 int lowercase = 0;
1684 int numbers = 0;
1685 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001686 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001687 for (int i = 0; i < password.length(); i++) {
1688 char c = password.charAt(i);
1689 if (c >= 'A' && c <= 'Z') {
1690 letters++;
1691 uppercase++;
1692 } else if (c >= 'a' && c <= 'z') {
1693 letters++;
1694 lowercase++;
1695 } else if (c >= '0' && c <= '9') {
1696 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001697 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001698 } else {
1699 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001700 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001701 }
1702 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001703 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001704 if(letters < neededLetters) {
1705 Slog.w(TAG, "resetPassword: number of letters " + letters
1706 + " does not meet required number of letters " + neededLetters);
1707 return false;
1708 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001709 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001710 if (numbers < neededNumbers) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001711 Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
1712 + " does not meet required number of numerical digits "
1713 + neededNumbers);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001714 return false;
1715 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001716 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001717 if (lowercase < neededLowerCase) {
1718 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1719 + " does not meet required number of lowercase letters "
1720 + neededLowerCase);
1721 return false;
1722 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001723 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001724 if (uppercase < neededUpperCase) {
1725 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1726 + " does not meet required number of uppercase letters "
1727 + neededUpperCase);
1728 return false;
1729 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001730 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001731 if (symbols < neededSymbols) {
1732 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1733 + " does not meet required number of special symbols " + neededSymbols);
1734 return false;
1735 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001736 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001737 if (nonletter < neededNonLetter) {
1738 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1739 + " does not meet required number of non-letter characters "
1740 + neededNonLetter);
1741 return false;
1742 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001743 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001744 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001745
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001746 int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001747 DevicePolicyData policy = getUserData(userHandle);
1748 if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001749 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001750 return false;
1751 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001752
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001753 // Don't do this with the lock held, because it is going to call
1754 // back in to the service.
1755 long ident = Binder.clearCallingIdentity();
1756 try {
1757 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001758 utils.saveLockPassword(password, quality, false, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001759 synchronized (this) {
1760 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1761 != 0 ? callingUid : -1;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001762 if (policy.mPasswordOwner != newOwner) {
1763 policy.mPasswordOwner = newOwner;
1764 saveSettingsLocked(userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001765 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001766 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001767 } finally {
1768 Binder.restoreCallingIdentity(ident);
1769 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001770
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001771 return true;
1772 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001773
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001774 public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
1775 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001776 synchronized (this) {
1777 if (who == null) {
1778 throw new NullPointerException("ComponentName is null");
1779 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001780 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001781 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001782 if (ap.maximumTimeToUnlock != timeMs) {
1783 ap.maximumTimeToUnlock = timeMs;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001784 saveSettingsLocked(userHandle);
1785 updateMaximumTimeToLockLocked(getUserData(userHandle));
Dianne Hackbornd6847842010-01-12 18:14:19 -08001786 }
1787 }
1788 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001789
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001790 void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
1791 long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
1792 if (policy.mLastMaximumTimeToLock == timeMs) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001793 return;
1794 }
1795
1796 long ident = Binder.clearCallingIdentity();
1797 try {
1798 if (timeMs <= 0) {
1799 timeMs = Integer.MAX_VALUE;
1800 } else {
1801 // Make sure KEEP_SCREEN_ON is disabled, since that
1802 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07001803 Settings.Global.putInt(mContext.getContentResolver(),
1804 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001805 }
1806
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001807 policy.mLastMaximumTimeToLock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001808
1809 try {
Jeff Brown96307042012-07-27 15:51:34 -07001810 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001811 } catch (RemoteException e) {
1812 Slog.w(TAG, "Failure talking with power manager", e);
1813 }
1814 } finally {
1815 Binder.restoreCallingIdentity(ident);
1816 }
1817 }
1818
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001819 public long getMaximumTimeToLock(ComponentName who, int userHandle) {
1820 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001821 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001822 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001823
Dianne Hackborn254cb442010-01-27 19:23:59 -08001824 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001825 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001826 return admin != null ? admin.maximumTimeToUnlock : time;
1827 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001828
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001829 DevicePolicyData policy = getUserData(userHandle);
1830 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001831 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001832 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001833 if (time == 0) {
1834 time = admin.maximumTimeToUnlock;
1835 } else if (admin.maximumTimeToUnlock != 0
1836 && time > admin.maximumTimeToUnlock) {
1837 time = admin.maximumTimeToUnlock;
1838 }
1839 }
1840 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001841 }
1842 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001843
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001844 public void lockNow() {
1845 synchronized (this) {
1846 // This API can only be called by an active device admin,
1847 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001848 getActiveAdminForCallerLocked(null,
1849 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001850 lockNowUnchecked();
1851 }
1852 }
1853
1854 private void lockNowUnchecked() {
1855 long ident = Binder.clearCallingIdentity();
1856 try {
1857 // Power off the display
1858 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1859 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
1860 // Ensure the device is locked
Adam Cohenf7522022012-10-03 20:03:18 -07001861 getWindowManager().lockNow(null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001862 } catch (RemoteException e) {
1863 } finally {
1864 Binder.restoreCallingIdentity(ident);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001865 }
1866 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001867
Ben Komaloed48c8b2011-10-17 17:30:21 -07001868 private boolean isExtStorageEncrypted() {
1869 String state = SystemProperties.get("vold.decrypt");
1870 return !"".equals(state);
1871 }
1872
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001873 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001874 // If the SD card is encrypted and non-removable, we have to force a wipe.
1875 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1876 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1877
1878 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1879 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001880 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001881 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001882 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1883 mWakeLock.acquire(10000);
1884 mContext.startService(intent);
1885 } else {
1886 try {
1887 RecoverySystem.rebootWipeUserData(mContext);
1888 } catch (IOException e) {
1889 Slog.w(TAG, "Failed requesting data wipe", e);
1890 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001891 }
1892 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001893
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001894 public void wipeData(int flags, final int userHandle) {
1895 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001896 synchronized (this) {
1897 // This API can only be called by an active device admin,
1898 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001899 getActiveAdminForCallerLocked(null,
1900 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001901 long ident = Binder.clearCallingIdentity();
1902 try {
Amith Yamasani32f07422012-11-16 15:09:13 -08001903 wipeDeviceOrUserLocked(flags, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001904 } finally {
1905 Binder.restoreCallingIdentity(ident);
1906 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001907 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001908 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001909
Amith Yamasani32f07422012-11-16 15:09:13 -08001910 private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
1911 if (userHandle == UserHandle.USER_OWNER) {
1912 wipeDataLocked(flags);
1913 } else {
1914 lockNowUnchecked();
1915 mHandler.post(new Runnable() {
1916 public void run() {
1917 try {
Amith Yamasanie4cf7342012-12-17 11:12:09 -08001918 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
Amith Yamasani32f07422012-11-16 15:09:13 -08001919 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
1920 .removeUser(userHandle);
1921 } catch (RemoteException re) {
1922 // Shouldn't happen
1923 }
1924 }
1925 });
1926 }
1927 }
1928
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001929 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
1930 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001931 mContext.enforceCallingOrSelfPermission(
1932 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001933
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001934 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001935 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001936 if (admin == null) {
1937 try {
1938 result.sendResult(null);
1939 } catch (RemoteException e) {
1940 }
1941 return;
1942 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001943 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001944 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001945 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001946 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001947 @Override
1948 public void onReceive(Context context, Intent intent) {
1949 try {
1950 result.sendResult(getResultExtras(false));
1951 } catch (RemoteException e) {
1952 }
1953 }
1954 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001955 }
1956 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001957
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001958 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001959 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
1960 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001961 mContext.enforceCallingOrSelfPermission(
1962 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001963 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001964
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001965 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001966
Dianne Hackbornd6847842010-01-12 18:14:19 -08001967 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001968 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
1969 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
1970 || p.mActivePasswordUpperCase != uppercase
1971 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
1972 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001973 long ident = Binder.clearCallingIdentity();
1974 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001975 p.mActivePasswordQuality = quality;
1976 p.mActivePasswordLength = length;
1977 p.mActivePasswordLetters = letters;
1978 p.mActivePasswordLowerCase = lowercase;
1979 p.mActivePasswordUpperCase = uppercase;
1980 p.mActivePasswordNumeric = numbers;
1981 p.mActivePasswordSymbols = symbols;
1982 p.mActivePasswordNonLetter = nonletter;
1983 p.mFailedPasswordAttempts = 0;
1984 saveSettingsLocked(userHandle);
1985 updatePasswordExpirationsLocked(userHandle);
1986 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08001987 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001988 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001989 } finally {
1990 Binder.restoreCallingIdentity(ident);
1991 }
1992 }
1993 }
1994 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001995
Andy Stadler043116a2010-11-29 17:43:32 -08001996 /**
1997 * Called any time the device password is updated. Resets all password expiration clocks.
1998 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001999 private void updatePasswordExpirationsLocked(int userHandle) {
2000 DevicePolicyData policy = getUserData(userHandle);
2001 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08002002 if (N > 0) {
2003 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002004 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08002005 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08002006 long timeout = admin.passwordExpirationTimeout;
2007 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
2008 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08002009 }
2010 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002011 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08002012 }
2013 }
2014
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002015 public void reportFailedPasswordAttempt(int userHandle) {
2016 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002017 mContext.enforceCallingOrSelfPermission(
2018 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002019
Dianne Hackbornd6847842010-01-12 18:14:19 -08002020 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002021 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002022 long ident = Binder.clearCallingIdentity();
2023 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002024 policy.mFailedPasswordAttempts++;
2025 saveSettingsLocked(userHandle);
2026 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
2027 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
Amith Yamasani32f07422012-11-16 15:09:13 -08002028 wipeDeviceOrUserLocked(0, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002029 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002030 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002031 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002032 } finally {
2033 Binder.restoreCallingIdentity(ident);
2034 }
2035 }
2036 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002037
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002038 public void reportSuccessfulPasswordAttempt(int userHandle) {
2039 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002040 mContext.enforceCallingOrSelfPermission(
2041 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002042
Dianne Hackbornd6847842010-01-12 18:14:19 -08002043 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002044 DevicePolicyData policy = getUserData(userHandle);
2045 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002046 long ident = Binder.clearCallingIdentity();
2047 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002048 policy.mFailedPasswordAttempts = 0;
2049 policy.mPasswordOwner = -1;
2050 saveSettingsLocked(userHandle);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002051 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002052 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002053 } finally {
2054 Binder.restoreCallingIdentity(ident);
2055 }
2056 }
2057 }
2058 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002059
Oscar Montemayor69238c62010-08-03 10:51:06 -07002060 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002061 String exclusionList, int userHandle) {
2062 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002063 synchronized(this) {
2064 if (who == null) {
2065 throw new NullPointerException("ComponentName is null");
2066 }
2067
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002068 // Only check if owner has set global proxy. We don't allow other users to set it.
2069 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002070 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2071 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2072
2073 // Scan through active admins and find if anyone has already
2074 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002075 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002076 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002077 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002078 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2079 // Another admin already sets the global proxy
2080 // Return it to the caller.
2081 return component;
2082 }
2083 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002084
2085 // If the user is not the owner, don't set the global proxy. Fail silently.
2086 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2087 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2088 + userHandle + " is not permitted.");
2089 return null;
2090 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002091 if (proxySpec == null) {
2092 admin.specifiesGlobalProxy = false;
2093 admin.globalProxySpec = null;
2094 admin.globalProxyExclusionList = null;
2095 } else {
2096
2097 admin.specifiesGlobalProxy = true;
2098 admin.globalProxySpec = proxySpec;
2099 admin.globalProxyExclusionList = exclusionList;
2100 }
2101
2102 // Reset the global proxy accordingly
2103 // Do this using system permissions, as apps cannot write to secure settings
2104 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002105 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002106 Binder.restoreCallingIdentity(origId);
2107 return null;
2108 }
2109 }
2110
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002111 public ComponentName getGlobalProxyAdmin(int userHandle) {
2112 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002113 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002114 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002115 // Scan through active admins and find if anyone has already
2116 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002117 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002118 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002119 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002120 if (ap.specifiesGlobalProxy) {
2121 // Device admin sets the global proxy
2122 // Return it to the caller.
2123 return ap.info.getComponent();
2124 }
2125 }
2126 }
2127 // No device admin sets the global proxy.
2128 return null;
2129 }
2130
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002131 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2132 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002133 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002134 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002135 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002136 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002137 return;
2138 }
2139 }
2140 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002141 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002142 }
2143
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002144 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002145 if (exclusionList == null) {
2146 exclusionList = "";
2147 }
2148 if (proxySpec == null) {
2149 proxySpec = "";
2150 }
2151 // Remove white spaces
2152 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002153 String data[] = proxySpec.split(":");
2154 int proxyPort = 8080;
2155 if (data.length > 1) {
2156 try {
2157 proxyPort = Integer.parseInt(data[1]);
2158 } catch (NumberFormatException e) {}
2159 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002160 exclusionList = exclusionList.trim();
2161 ContentResolver res = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -07002162 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
2163 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2164 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwalt434203a2010-10-11 16:00:27 -07002165 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002166 }
2167
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002168 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002169 * Set the storage encryption request for a single admin. Returns the new total request
2170 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002171 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002172 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
2173 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002174 synchronized (this) {
2175 // Check for permissions
2176 if (who == null) {
2177 throw new NullPointerException("ComponentName is null");
2178 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002179 // Only owner can set storage encryption
2180 if (userHandle != UserHandle.USER_OWNER
2181 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2182 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2183 + UserHandle.getCallingUserId() + " is not permitted.");
2184 return 0;
2185 }
2186
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002187 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2188 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2189
Andy Stadler22dbfda2011-01-17 12:47:31 -08002190 // Quick exit: If the filesystem does not support encryption, we can exit early.
2191 if (!isEncryptionSupported()) {
2192 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2193 }
2194
2195 // (1) Record the value for the admin so it's sticky
2196 if (ap.encryptionRequested != encrypt) {
2197 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002198 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002199 }
2200
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002201 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002202 // (2) Compute "max" for all admins
2203 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002204 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002205 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002206 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002207 }
2208
2209 // Notify OS of new request
2210 setEncryptionRequested(newRequested);
2211
2212 // Return the new global request status
2213 return newRequested
2214 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2215 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002216 }
2217 }
2218
2219 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002220 * Get the current storage encryption request status for a given admin, or aggregate of all
2221 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002222 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002223 public boolean getStorageEncryption(ComponentName who, int userHandle) {
2224 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002225 synchronized (this) {
2226 // Check for permissions if a particular caller is specified
2227 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002228 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002229 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002230 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002231 }
2232
Andy Stadler22dbfda2011-01-17 12:47:31 -08002233 // If no particular caller is specified, return the aggregate set of requests.
2234 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002235 DevicePolicyData policy = getUserData(userHandle);
2236 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002237 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002238 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002239 return true;
2240 }
2241 }
2242 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002243 }
2244 }
2245
Andy Stadler22dbfda2011-01-17 12:47:31 -08002246 /**
2247 * Get the current encryption status of the device.
2248 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002249 public int getStorageEncryptionStatus(int userHandle) {
2250 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002251 return getEncryptionStatus();
2252 }
2253
2254 /**
2255 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2256 */
2257 private boolean isEncryptionSupported() {
2258 // Note, this can be implemented as
2259 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2260 // But is provided as a separate internal method if there's a faster way to do a
2261 // simple check for supported-or-not.
2262 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2263 }
2264
2265 /**
2266 * Hook to low-levels: Reporting the current status of encryption.
2267 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2268 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2269 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2270 */
2271 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002272 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2273 if ("encrypted".equalsIgnoreCase(status)) {
2274 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2275 } else if ("unencrypted".equalsIgnoreCase(status)) {
2276 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2277 } else {
2278 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2279 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002280 }
2281
2282 /**
2283 * Hook to low-levels: If needed, record the new admin setting for encryption.
2284 */
2285 private void setEncryptionRequested(boolean encrypt) {
2286 }
2287
Ben Komalo2447edd2011-05-09 16:05:33 -07002288 /**
2289 * The system property used to share the state of the camera. The native camera service
2290 * is expected to read this property and act accordingly.
2291 */
2292 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2293
2294 /**
2295 * Disables all device cameras according to the specified admin.
2296 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002297 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
2298 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002299 synchronized (this) {
2300 if (who == null) {
2301 throw new NullPointerException("ComponentName is null");
2302 }
2303 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2304 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2305 if (ap.disableCamera != disabled) {
2306 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002307 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002308 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002309 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002310 }
2311 }
2312
2313 /**
2314 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2315 * active admins.
2316 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002317 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Ben Komalo2447edd2011-05-09 16:05:33 -07002318 synchronized (this) {
2319 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002320 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002321 return (admin != null) ? admin.disableCamera : false;
2322 }
2323
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002324 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002325 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002326 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002327 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002328 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002329 if (admin.disableCamera) {
2330 return true;
2331 }
2332 }
2333 return false;
2334 }
2335 }
2336
Jim Millerb8ec4702012-08-31 17:19:10 -07002337 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002338 * Selectively disable keyguard features.
Jim Millerb8ec4702012-08-31 17:19:10 -07002339 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002340 public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002341 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002342 synchronized (this) {
2343 if (who == null) {
2344 throw new NullPointerException("ComponentName is null");
2345 }
2346 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Jim Miller48b9b0d2012-09-19 23:16:50 -07002347 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
2348 if (ap.disabledKeyguardFeatures != which) {
2349 ap.disabledKeyguardFeatures = which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002350 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002351 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002352 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002353 }
2354 }
2355
2356 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002357 * Gets the disabled state for features in keyguard for the given admin,
Jim Millerb8ec4702012-08-31 17:19:10 -07002358 * or the aggregate of all active admins if who is null.
2359 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002360 public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002361 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002362 synchronized (this) {
2363 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002364 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002365 return (admin != null) ? admin.disabledKeyguardFeatures : 0;
Jim Millerb8ec4702012-08-31 17:19:10 -07002366 }
2367
Jim Miller48b9b0d2012-09-19 23:16:50 -07002368 // Determine which keyguard features are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002369 DevicePolicyData policy = getUserData(userHandle);
2370 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002371 int which = 0;
2372 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002373 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002374 which |= admin.disabledKeyguardFeatures;
Jim Millerb8ec4702012-08-31 17:19:10 -07002375 }
2376 return which;
2377 }
2378 }
2379
Amith Yamasani71e6c692013-03-24 17:39:28 -07002380 @Override
2381 public boolean setDeviceOwner(String packageName) {
2382 if (packageName == null
2383 || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
2384 throw new IllegalArgumentException("Invalid package name " + packageName
2385 + " for device owner");
2386 }
2387 synchronized (this) {
2388 if (mDeviceOwner == null && !isDeviceProvisioned()) {
2389 mDeviceOwner = new DeviceOwner(packageName);
2390 mDeviceOwner.writeOwnerFile();
2391 return true;
2392 } else {
2393 throw new IllegalStateException("Trying to set device owner to " + packageName
2394 + ", owner=" + mDeviceOwner.getPackageName()
2395 + ", device_provisioned=" + isDeviceProvisioned());
2396 }
2397 }
2398 }
2399
2400 @Override
2401 public boolean isDeviceOwner(String packageName) {
2402 synchronized (this) {
2403 return mDeviceOwner != null
2404 && mDeviceOwner.getPackageName().equals(packageName);
2405 }
2406 }
2407
2408 @Override
2409 public String getDeviceOwner() {
2410 synchronized (this) {
2411 if (mDeviceOwner != null) {
2412 return mDeviceOwner.getPackageName();
2413 }
2414 }
2415 return null;
2416 }
2417
2418 private boolean isDeviceProvisioned() {
2419 return Settings.Global.getInt(mContext.getContentResolver(),
2420 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
2421 }
2422
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002423 private void enforceCrossUserPermission(int userHandle) {
2424 if (userHandle < 0) {
2425 throw new IllegalArgumentException("Invalid userId " + userHandle);
2426 }
2427 final int callingUid = Binder.getCallingUid();
2428 if (userHandle == UserHandle.getUserId(callingUid)) return;
2429 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2430 mContext.enforceCallingOrSelfPermission(
2431 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2432 + " INTERACT_ACROSS_USERS_FULL permission");
2433 }
2434 }
2435
Amith Yamasani71e6c692013-03-24 17:39:28 -07002436 private void enableIfNecessary(String packageName, int userId) {
2437 try {
2438 IPackageManager ipm = AppGlobals.getPackageManager();
2439 ApplicationInfo ai = ipm.getApplicationInfo(packageName,
2440 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2441 userId);
2442 if (ai.enabledSetting
2443 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
2444 ipm.setApplicationEnabledSetting(packageName,
2445 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
2446 PackageManager.DONT_KILL_APP, userId);
2447 }
2448 } catch (RemoteException e) {
2449 }
2450 }
2451
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002452 @Override
2453 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2454 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2455 != PackageManager.PERMISSION_GRANTED) {
2456
2457 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2458 + Binder.getCallingPid()
2459 + ", uid=" + Binder.getCallingUid());
2460 return;
2461 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002462
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002463 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002464
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002465 synchronized (this) {
2466 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002467
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002468 int userCount = mUserData.size();
2469 for (int u = 0; u < userCount; u++) {
2470 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2471 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2472 final int N = policy.mAdminList.size();
2473 for (int i=0; i<N; i++) {
2474 ActiveAdmin ap = policy.mAdminList.get(i);
2475 if (ap != null) {
2476 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2477 pw.println(":");
2478 ap.dump(" ", pw);
2479 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002480 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002481
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002482 pw.println(" ");
2483 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2484 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002485 }
2486 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002487
2488 static class DeviceOwner {
2489 private static final String DEVICE_OWNER_XML = "device_owner.xml";
2490 private static final String TAG_DEVICE_OWNER = "device-owner";
2491 private static final String ATTR_PACKAGE = "package";
2492 private String mPackageName;
2493
2494 DeviceOwner() {
2495 readOwnerFile();
2496 }
2497
2498 DeviceOwner(String packageName) {
2499 this.mPackageName = packageName;
2500 }
2501
2502 static boolean isRegistered() {
2503 return new File(Environment.getSystemSecureDirectory(),
2504 DEVICE_OWNER_XML).exists();
2505 }
2506
2507 String getPackageName() {
2508 return mPackageName;
2509 }
2510
2511 static boolean isInstalled(String packageName, PackageManager pm) {
2512 try {
2513 PackageInfo pi;
2514 if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
2515 if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
2516 return true;
2517 }
2518 }
2519 } catch (NameNotFoundException nnfe) {
2520 Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
2521 }
2522 return false;
2523 }
2524
2525 void readOwnerFile() {
2526 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2527 DEVICE_OWNER_XML));
2528 try {
2529 FileInputStream input = file.openRead();
2530 XmlPullParser parser = Xml.newPullParser();
2531 parser.setInput(input, null);
2532 int type;
2533 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2534 && type != XmlPullParser.START_TAG) {
2535 }
2536 String tag = parser.getName();
2537 if (!TAG_DEVICE_OWNER.equals(tag)) {
2538 throw new XmlPullParserException(
2539 "Device Owner file does not start with device-owner tag: found " + tag);
2540 }
2541 mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
2542 input.close();
2543 } catch (XmlPullParserException xppe) {
2544 Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
2545 } catch (IOException ioe) {
2546 Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
2547 }
2548 }
2549
2550 void writeOwnerFile() {
2551 synchronized (this) {
2552 writeOwnerFileLocked();
2553 }
2554 }
2555
2556 private void writeOwnerFileLocked() {
2557 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2558 DEVICE_OWNER_XML));
2559 try {
2560 FileOutputStream output = file.startWrite();
2561 XmlSerializer out = new FastXmlSerializer();
2562 out.setOutput(output, "utf-8");
2563 out.startDocument(null, true);
2564 out.startTag(null, TAG_DEVICE_OWNER);
2565 out.attribute(null, ATTR_PACKAGE, mPackageName);
2566 out.endTag(null, TAG_DEVICE_OWNER);
2567 out.endDocument();
2568 out.flush();
2569 file.finishWrite(output);
2570 } catch (IOException ioe) {
2571 Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
2572 }
2573 }
2574 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002575}