blob: 2bca7596ca317b5fba3aa2ded255a967ae3b06ee [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
Maggie Benthallda51e682013-08-08 22:35:44 -040019import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
20
Maggie Benthall0469f412013-09-05 15:30:26 -040021import com.android.internal.R;
Dianne Hackborn42499172010-10-15 18:45:07 -070022import com.android.internal.os.storage.ExternalStorageFormatter;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080023import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070024import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080025import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080026import com.android.internal.widget.LockPatternUtils;
Maggie Benthallda51e682013-08-08 22:35:44 -040027import com.android.org.conscrypt.TrustedCertificateStore;
Dianne Hackbornd6847842010-01-12 18:14:19 -080028
29import org.xmlpull.v1.XmlPullParser;
30import org.xmlpull.v1.XmlPullParserException;
31import org.xmlpull.v1.XmlSerializer;
32
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080033import android.app.Activity;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070034import android.app.ActivityManagerNative;
Jim Millera4e28d12010-11-08 16:15:47 -080035import android.app.AlarmManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070036import android.app.AppGlobals;
Maggie Benthall0469f412013-09-05 15:30:26 -040037import android.app.INotificationManager;
38import android.app.Notification;
39import android.app.NotificationManager;
Jim Millera4e28d12010-11-08 16:15:47 -080040import android.app.PendingIntent;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080041import android.app.admin.DeviceAdminInfo;
42import android.app.admin.DeviceAdminReceiver;
43import android.app.admin.DevicePolicyManager;
44import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080045import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080046import android.content.ComponentName;
Oscar Montemayor69238c62010-08-03 10:51:06 -070047import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080048import android.content.Context;
49import android.content.Intent;
Jim Millera4e28d12010-11-08 16:15:47 -080050import android.content.IntentFilter;
Amith Yamasani71e6c692013-03-24 17:39:28 -070051import android.content.pm.ApplicationInfo;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070052import android.content.pm.IPackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070053import android.content.pm.PackageInfo;
Dianne Hackbornd6847842010-01-12 18:14:19 -080054import android.content.pm.PackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070055import android.content.pm.Signature;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080056import android.content.pm.PackageManager.NameNotFoundException;
Andy Stadler1f35d482010-11-19 15:39:41 -080057import android.content.pm.ResolveInfo;
Maggie Benthall0469f412013-09-05 15:30:26 -040058import android.content.pm.UserInfo;
Amith Yamasani71e6c692013-03-24 17:39:28 -070059import android.net.Uri;
Maggie Benthallda51e682013-08-08 22:35:44 -040060import android.os.AsyncTask;
Dianne Hackbornd6847842010-01-12 18:14:19 -080061import android.os.Binder;
Adam Cohenf7522022012-10-03 20:03:18 -070062import android.os.Bundle;
Ben Komaloed48c8b2011-10-17 17:30:21 -070063import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080064import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080065import android.os.IBinder;
66import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070067import android.os.PowerManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070068import android.os.Process;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080069import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080070import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080071import android.os.RemoteException;
72import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080073import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080074import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070075import android.os.UserHandle;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070076import android.os.UserManager;
Oscar Montemayor69238c62010-08-03 10:51:06 -070077import android.provider.Settings;
Maggie Benthallda51e682013-08-08 22:35:44 -040078import android.security.Credentials;
79import android.security.IKeyChainService;
80import android.security.KeyChain;
81import android.security.KeyChain.KeyChainConnection;
Amith Yamasani71e6c692013-03-24 17:39:28 -070082import android.util.AtomicFile;
Maggie Benthallda51e682013-08-08 22:35:44 -040083import android.util.Log;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080084import android.util.PrintWriterPrinter;
85import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080086import android.util.Slog;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070087import android.util.SparseArray;
Dianne Hackbornd6847842010-01-12 18:14:19 -080088import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080089import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080090import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080091
Maggie Benthallda51e682013-08-08 22:35:44 -040092import java.io.ByteArrayInputStream;
Dianne Hackbornd6847842010-01-12 18:14:19 -080093import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080094import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080095import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070096import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080097import java.io.FileOutputStream;
98import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080099import java.io.PrintWriter;
Maggie Benthallda51e682013-08-08 22:35:44 -0400100import java.security.KeyStore.TrustedCertificateEntry;
101import java.security.cert.CertificateException;
102import java.security.cert.CertificateFactory;
103import java.security.cert.X509Certificate;
Jim Millera4e28d12010-11-08 16:15:47 -0800104import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800105import java.util.ArrayList;
Maggie Benthallda51e682013-08-08 22:35:44 -0400106import java.util.Arrays;
107import java.util.Collection;
Jim Millera4e28d12010-11-08 16:15:47 -0800108import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800109import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800110import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -0700111import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800112
113/**
114 * Implementation of the device policy APIs.
115 */
116public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700117
Jim Miller6b857682011-02-16 16:27:41 -0800118 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -0800119
Amith Yamasani71e6c692013-03-24 17:39:28 -0700120 private static final String DEVICE_POLICIES_XML = "device_policies.xml";
121
Jim Miller6b857682011-02-16 16:27:41 -0800122 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700123
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700124 private static final long MS_PER_DAY = 86400 * 1000;
125
126 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
Jim Millera4e28d12010-11-08 16:15:47 -0800127
128 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
129 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
130
Maggie Benthall0469f412013-09-05 15:30:26 -0400131 private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
132
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700133 private static final boolean DBG = false;
Jim Millera4e28d12010-11-08 16:15:47 -0800134
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800135 final Context mContext;
Dianne Hackborn42499172010-10-15 18:45:07 -0700136 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800137
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800138 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800139 IWindowManager mIWindowManager;
Maggie Benthall0469f412013-09-05 15:30:26 -0400140 NotificationManager mNotificationManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700141
Amith Yamasani71e6c692013-03-24 17:39:28 -0700142 private DeviceOwner mDeviceOwner;
143
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700144 public static class DevicePolicyData {
145 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
146 int mActivePasswordLength = 0;
147 int mActivePasswordUpperCase = 0;
148 int mActivePasswordLowerCase = 0;
149 int mActivePasswordLetters = 0;
150 int mActivePasswordNumeric = 0;
151 int mActivePasswordSymbols = 0;
152 int mActivePasswordNonLetter = 0;
153 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700154
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700155 int mUserHandle;;
156 int mPasswordOwner = -1;
157 long mLastMaximumTimeToLock = -1;
158
159 final HashMap<ComponentName, ActiveAdmin> mAdminMap
160 = new HashMap<ComponentName, ActiveAdmin>();
161 final ArrayList<ActiveAdmin> mAdminList
162 = new ArrayList<ActiveAdmin>();
163
164 public DevicePolicyData(int userHandle) {
165 mUserHandle = userHandle;
166 }
167 }
168
169 final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
170
Jim Millera4e28d12010-11-08 16:15:47 -0800171 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700172
Jim Millera4e28d12010-11-08 16:15:47 -0800173 BroadcastReceiver mReceiver = new BroadcastReceiver() {
174 @Override
175 public void onReceive(Context context, Intent intent) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700176 final String action = intent.getAction();
177 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
178 getSendingUserId());
Jim Millera4e28d12010-11-08 16:15:47 -0800179 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
180 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800181 if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
182 + action + " for user " + userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800183 mHandler.post(new Runnable() {
184 public void run() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700185 handlePasswordExpirationNotification(getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -0800186 }
187 });
Maggie Benthall0469f412013-09-05 15:30:26 -0400188 }
189 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
190 || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
191 manageMonitoringCertificateNotification(intent);
192 }
193 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700194 removeUserData(userHandle);
195 } else if (Intent.ACTION_USER_STARTED.equals(action)
196 || Intent.ACTION_PACKAGE_CHANGED.equals(action)
197 || Intent.ACTION_PACKAGE_REMOVED.equals(action)
198 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
199
200 if (Intent.ACTION_USER_STARTED.equals(action)) {
201 // Reset the policy data
202 synchronized (DevicePolicyManagerService.this) {
203 mUserData.remove(userHandle);
204 }
205 }
206
207 handlePackagesChanged(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800208 }
209 }
210 };
211
Dianne Hackbornd6847842010-01-12 18:14:19 -0800212 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800213 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700214
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800215 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700216
217 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
218 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
219
220 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
221 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
222
223 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
224 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
225
226 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
227 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
228
229 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700230 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700231
232 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
233 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
234
235 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
236 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
237
238 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
239 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
240
241 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
242 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
243
244 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
245 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
246
247 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
248 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
249
250 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
251 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
252
Jim Miller48b9b0d2012-09-19 23:16:50 -0700253 static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
254 int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
Jim Millerb8ec4702012-08-31 17:19:10 -0700255
Andy Stadler22dbfda2011-01-17 12:47:31 -0800256 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700257 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700258
Oscar Montemayor69238c62010-08-03 10:51:06 -0700259 // TODO: review implementation decisions with frameworks team
260 boolean specifiesGlobalProxy = false;
261 String globalProxySpec = null;
262 String globalProxyExclusionList = null;
263
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800264 ActiveAdmin(DeviceAdminInfo _info) {
265 info = _info;
266 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700267
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800268 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700269
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700270 public UserHandle getUserHandle() {
271 return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
272 }
273
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800274 void writeToXml(XmlSerializer out)
275 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800276 out.startTag(null, "policies");
277 info.writePoliciesToXml(out);
278 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800279 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
280 out.startTag(null, "password-quality");
281 out.attribute(null, "value", Integer.toString(passwordQuality));
282 out.endTag(null, "password-quality");
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700283 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800284 out.startTag(null, "min-password-length");
285 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700286 out.endTag(null, "min-password-length");
287 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700288 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700289 out.startTag(null, "password-history-length");
290 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
291 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800292 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700293 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700294 out.startTag(null, "min-password-uppercase");
295 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
296 out.endTag(null, "min-password-uppercase");
297 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700298 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700299 out.startTag(null, "min-password-lowercase");
300 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
301 out.endTag(null, "min-password-lowercase");
302 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700303 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700304 out.startTag(null, "min-password-letters");
305 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
306 out.endTag(null, "min-password-letters");
307 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700308 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700309 out.startTag(null, "min-password-numeric");
310 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
311 out.endTag(null, "min-password-numeric");
312 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700313 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700314 out.startTag(null, "min-password-symbols");
315 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
316 out.endTag(null, "min-password-symbols");
317 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700318 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700319 out.startTag(null, "min-password-nonletter");
320 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
321 out.endTag(null, "min-password-nonletter");
322 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800323 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700324 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800325 out.startTag(null, "max-time-to-unlock");
326 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
327 out.endTag(null, "max-time-to-unlock");
328 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700329 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800330 out.startTag(null, "max-failed-password-wipe");
331 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
332 out.endTag(null, "max-failed-password-wipe");
333 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700334 if (specifiesGlobalProxy) {
335 out.startTag(null, "specifies-global-proxy");
336 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
337 out.endTag(null, "specifies_global_proxy");
338 if (globalProxySpec != null) {
339 out.startTag(null, "global-proxy-spec");
340 out.attribute(null, "value", globalProxySpec);
341 out.endTag(null, "global-proxy-spec");
342 }
343 if (globalProxyExclusionList != null) {
344 out.startTag(null, "global-proxy-exclusion-list");
345 out.attribute(null, "value", globalProxyExclusionList);
346 out.endTag(null, "global-proxy-exclusion-list");
347 }
348 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700349 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800350 out.startTag(null, "password-expiration-timeout");
351 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
352 out.endTag(null, "password-expiration-timeout");
353 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700354 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800355 out.startTag(null, "password-expiration-date");
356 out.attribute(null, "value", Long.toString(passwordExpirationDate));
357 out.endTag(null, "password-expiration-date");
358 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800359 if (encryptionRequested) {
360 out.startTag(null, "encryption-requested");
361 out.attribute(null, "value", Boolean.toString(encryptionRequested));
362 out.endTag(null, "encryption-requested");
363 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700364 if (disableCamera) {
365 out.startTag(null, "disable-camera");
366 out.attribute(null, "value", Boolean.toString(disableCamera));
367 out.endTag(null, "disable-camera");
368 }
Jim Miller48b9b0d2012-09-19 23:16:50 -0700369 if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
370 out.startTag(null, "disable-keyguard-features");
371 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
372 out.endTag(null, "disable-keyguard-features");
Jim Millerb8ec4702012-08-31 17:19:10 -0700373 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800374 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700375
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800376 void readFromXml(XmlPullParser parser)
377 throws XmlPullParserException, IOException {
378 int outerDepth = parser.getDepth();
379 int type;
380 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
381 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
382 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
383 continue;
384 }
385 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800386 if ("policies".equals(tag)) {
387 info.readPoliciesFromXml(parser);
388 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800389 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800390 parser.getAttributeValue(null, "value"));
391 } else if ("min-password-length".equals(tag)) {
392 minimumPasswordLength = Integer.parseInt(
393 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700394 } else if ("password-history-length".equals(tag)) {
395 passwordHistoryLength = Integer.parseInt(
396 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700397 } else if ("min-password-uppercase".equals(tag)) {
398 minimumPasswordUpperCase = Integer.parseInt(
399 parser.getAttributeValue(null, "value"));
400 } else if ("min-password-lowercase".equals(tag)) {
401 minimumPasswordLowerCase = Integer.parseInt(
402 parser.getAttributeValue(null, "value"));
403 } else if ("min-password-letters".equals(tag)) {
404 minimumPasswordLetters = Integer.parseInt(
405 parser.getAttributeValue(null, "value"));
406 } else if ("min-password-numeric".equals(tag)) {
407 minimumPasswordNumeric = Integer.parseInt(
408 parser.getAttributeValue(null, "value"));
409 } else if ("min-password-symbols".equals(tag)) {
410 minimumPasswordSymbols = Integer.parseInt(
411 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700412 } else if ("min-password-nonletter".equals(tag)) {
413 minimumPasswordNonLetter = Integer.parseInt(
414 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800415 } else if ("max-time-to-unlock".equals(tag)) {
416 maximumTimeToUnlock = Long.parseLong(
417 parser.getAttributeValue(null, "value"));
418 } else if ("max-failed-password-wipe".equals(tag)) {
419 maximumFailedPasswordsForWipe = Integer.parseInt(
420 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700421 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800422 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700423 parser.getAttributeValue(null, "value"));
424 } else if ("global-proxy-spec".equals(tag)) {
425 globalProxySpec =
426 parser.getAttributeValue(null, "value");
427 } else if ("global-proxy-exclusion-list".equals(tag)) {
428 globalProxyExclusionList =
429 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800430 } else if ("password-expiration-timeout".equals(tag)) {
431 passwordExpirationTimeout = Long.parseLong(
432 parser.getAttributeValue(null, "value"));
433 } else if ("password-expiration-date".equals(tag)) {
434 passwordExpirationDate = Long.parseLong(
435 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800436 } else if ("encryption-requested".equals(tag)) {
437 encryptionRequested = Boolean.parseBoolean(
438 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700439 } else if ("disable-camera".equals(tag)) {
440 disableCamera = Boolean.parseBoolean(
441 parser.getAttributeValue(null, "value"));
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700442 } else if ("disable-keyguard-features".equals(tag)) {
443 disabledKeyguardFeatures = Integer.parseInt(
444 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800445 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700446 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800447 }
448 XmlUtils.skipCurrentTag(parser);
449 }
450 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700451
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800452 void dump(String prefix, PrintWriter pw) {
453 pw.print(prefix); pw.print("uid="); pw.println(getUid());
454 pw.print(prefix); pw.println("policies:");
455 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
456 if (pols != null) {
457 for (int i=0; i<pols.size(); i++) {
458 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
459 }
460 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700461 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700462 pw.println(Integer.toHexString(passwordQuality));
463 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800464 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700465 pw.print(prefix); pw.print("passwordHistoryLength=");
466 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700467 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
468 pw.println(minimumPasswordUpperCase);
469 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
470 pw.println(minimumPasswordLowerCase);
471 pw.print(prefix); pw.print("minimumPasswordLetters=");
472 pw.println(minimumPasswordLetters);
473 pw.print(prefix); pw.print("minimumPasswordNumeric=");
474 pw.println(minimumPasswordNumeric);
475 pw.print(prefix); pw.print("minimumPasswordSymbols=");
476 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700477 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
478 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800479 pw.print(prefix); pw.print("maximumTimeToUnlock=");
480 pw.println(maximumTimeToUnlock);
481 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
482 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700483 pw.print(prefix); pw.print("specifiesGlobalProxy=");
484 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800485 pw.print(prefix); pw.print("passwordExpirationTimeout=");
486 pw.println(passwordExpirationTimeout);
487 pw.print(prefix); pw.print("passwordExpirationDate=");
488 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700489 if (globalProxySpec != null) {
490 pw.print(prefix); pw.print("globalProxySpec=");
491 pw.println(globalProxySpec);
492 }
493 if (globalProxyExclusionList != null) {
494 pw.print(prefix); pw.print("globalProxyEclusionList=");
495 pw.println(globalProxyExclusionList);
496 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800497 pw.print(prefix); pw.print("encryptionRequested=");
498 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700499 pw.print(prefix); pw.print("disableCamera=");
500 pw.println(disableCamera);
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700501 pw.print(prefix); pw.print("disabledKeyguardFeatures=");
502 pw.println(disabledKeyguardFeatures);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800503 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800504 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700505
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700506 private void handlePackagesChanged(int userHandle) {
507 boolean removed = false;
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800508 if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700509 DevicePolicyData policy = getUserData(userHandle);
510 IPackageManager pm = AppGlobals.getPackageManager();
511 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
512 ActiveAdmin aa = policy.mAdminList.get(i);
513 try {
514 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
515 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
516 removed = true;
517 policy.mAdminList.remove(i);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800518 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700519 } catch (RemoteException re) {
520 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800521 }
522 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700523 if (removed) {
524 validatePasswordOwnerLocked(policy);
525 syncDeviceCapabilitiesLocked(policy);
526 saveSettingsLocked(policy.mUserHandle);
527 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800528 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700529
Dianne Hackbornd6847842010-01-12 18:14:19 -0800530 /**
531 * Instantiates the service.
532 */
533 public DevicePolicyManagerService(Context context) {
534 mContext = context;
Dianne Hackborn42499172010-10-15 18:45:07 -0700535 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
536 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800537 IntentFilter filter = new IntentFilter();
538 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
539 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700540 filter.addAction(Intent.ACTION_USER_REMOVED);
541 filter.addAction(Intent.ACTION_USER_STARTED);
Maggie Benthall0469f412013-09-05 15:30:26 -0400542 filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700543 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
544 filter = new IntentFilter();
545 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
546 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
547 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Amith Yamasani71e6c692013-03-24 17:39:28 -0700548 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700549 filter.addDataScheme("package");
550 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
551 }
552
553 /**
554 * Creates and loads the policy data from xml.
555 * @param userHandle the user for whom to load the policy data
556 * @return
557 */
558 DevicePolicyData getUserData(int userHandle) {
559 synchronized (this) {
560 DevicePolicyData policy = mUserData.get(userHandle);
561 if (policy == null) {
562 policy = new DevicePolicyData(userHandle);
563 mUserData.append(userHandle, policy);
564 loadSettingsLocked(policy, userHandle);
565 }
566 return policy;
567 }
568 }
569
570 void removeUserData(int userHandle) {
571 synchronized (this) {
572 if (userHandle == UserHandle.USER_OWNER) {
573 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
574 return;
575 }
576 DevicePolicyData policy = mUserData.get(userHandle);
577 if (policy != null) {
578 mUserData.remove(userHandle);
579 }
580 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
581 DEVICE_POLICIES_XML);
582 policyFile.delete();
583 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
584 }
Jim Millera4e28d12010-11-08 16:15:47 -0800585 }
586
Amith Yamasani71e6c692013-03-24 17:39:28 -0700587 void loadDeviceOwner() {
588 synchronized (this) {
589 if (DeviceOwner.isRegistered()) {
590 mDeviceOwner = new DeviceOwner();
591 }
592 }
593 }
594
Andy Stadler043116a2010-11-29 17:43:32 -0800595 /**
596 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
597 * reminders. Clears alarm if no expirations are configured.
598 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700599 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
600 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800601 final long now = System.currentTimeMillis();
602 final long timeToExpire = expiration - now;
603 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800604 if (expiration == 0) {
605 // No expirations are currently configured: Cancel alarm.
606 alarmTime = 0;
607 } else if (timeToExpire <= 0) {
608 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800609 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800610 } else {
611 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
612 // the expiration time.
613 long alarmInterval = timeToExpire % MS_PER_DAY;
614 if (alarmInterval == 0) {
615 alarmInterval = MS_PER_DAY;
616 }
617 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800618 }
619
Andy Stadler1f35d482010-11-19 15:39:41 -0800620 long token = Binder.clearCallingIdentity();
621 try {
622 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700623 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800624 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700625 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
626 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800627 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800628 if (alarmTime != 0) {
629 am.set(AlarmManager.RTC, alarmTime, pi);
630 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800631 } finally {
632 Binder.restoreCallingIdentity(token);
633 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800634 }
635
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800636 private IPowerManager getIPowerManager() {
637 if (mIPowerManager == null) {
638 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
639 mIPowerManager = IPowerManager.Stub.asInterface(b);
640 }
641 return mIPowerManager;
642 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700643
Jim Miller93c518e2012-01-17 15:55:31 -0800644 private IWindowManager getWindowManager() {
645 if (mIWindowManager == null) {
646 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
647 mIWindowManager = IWindowManager.Stub.asInterface(b);
648 }
649 return mIWindowManager;
650 }
651
Maggie Benthall0469f412013-09-05 15:30:26 -0400652 private NotificationManager getNotificationManager() {
653 if (mNotificationManager == null) {
654 mNotificationManager =
655 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
656 }
657 return mNotificationManager;
658 }
659
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700660 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
661 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800662 if (admin != null
663 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
664 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
665 return admin;
666 }
667 return null;
668 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700669
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800670 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
671 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800672 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700673 final int userHandle = UserHandle.getUserId(callingUid);
674 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800675 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700676 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800677 if (admin == null) {
678 throw new SecurityException("No active admin " + who);
679 }
680 if (admin.getUid() != callingUid) {
681 throw new SecurityException("Admin " + who + " is not owned by uid "
682 + Binder.getCallingUid());
683 }
684 if (!admin.info.usesPolicy(reqPolicy)) {
685 throw new SecurityException("Admin " + admin.info.getComponent()
686 + " did not specify uses-policy for: "
687 + admin.info.getTagForPolicy(reqPolicy));
688 }
689 return admin;
690 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700691 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800692 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700693 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800694 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
695 return admin;
696 }
697 }
698 throw new SecurityException("No active admin owned by uid "
699 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800700 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800701 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700702
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800703 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700704 sendAdminCommandLocked(admin, action, null);
705 }
706
707 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800708 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800709 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800710 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
711 intent.putExtra("expiration", admin.passwordExpirationDate);
712 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700713 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700714 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700715 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700716 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700717 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700718 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800719 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700720
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700721 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
722 final DevicePolicyData policy = getUserData(userHandle);
723 final int count = policy.mAdminList.size();
724 if (count > 0) {
725 for (int i = 0; i < count; i++) {
726 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800727 if (admin.info.usesPolicy(reqPolicy)) {
728 sendAdminCommandLocked(admin, action);
729 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800730 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800731 }
732 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700733
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700734 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
735 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800736 if (admin != null) {
737 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700738 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
739 new BroadcastReceiver() {
740 @Override
741 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700742 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700743 int userHandle = admin.getUserHandle().getIdentifier();
744 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700745 boolean doProxyCleanup = admin.info.usesPolicy(
746 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700747 policy.mAdminList.remove(admin);
748 policy.mAdminMap.remove(adminReceiver);
749 validatePasswordOwnerLocked(policy);
750 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700751 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700752 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700753 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700754 saveSettingsLocked(userHandle);
755 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700756 }
757 }
758 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800759 }
760 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700761
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700762 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
763 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800764 Intent resolveIntent = new Intent();
765 resolveIntent.setComponent(adminName);
766 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani71e6c692013-03-24 17:39:28 -0700767 resolveIntent,
768 PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
769 userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800770 if (infos == null || infos.size() <= 0) {
771 throw new IllegalArgumentException("Unknown admin: " + adminName);
772 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700773
Dianne Hackbornd6847842010-01-12 18:14:19 -0800774 try {
775 return new DeviceAdminInfo(mContext, infos.get(0));
776 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700777 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800778 return null;
779 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700780 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800781 return null;
782 }
783 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700784
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700785 private static JournaledFile makeJournaledFile(int userHandle) {
786 final String base = userHandle == 0
787 ? "/data/system/" + DEVICE_POLICIES_XML
788 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
789 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800790 return new JournaledFile(new File(base), new File(base + ".tmp"));
791 }
792
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700793 private void saveSettingsLocked(int userHandle) {
794 DevicePolicyData policy = getUserData(userHandle);
795 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800796 FileOutputStream stream = null;
797 try {
798 stream = new FileOutputStream(journal.chooseForWrite(), false);
799 XmlSerializer out = new FastXmlSerializer();
800 out.setOutput(stream, "utf-8");
801 out.startDocument(null, true);
802
803 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700804
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700805 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800806 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700807 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800808 if (ap != null) {
809 out.startTag(null, "admin");
810 out.attribute(null, "name", ap.info.getComponent().flattenToString());
811 ap.writeToXml(out);
812 out.endTag(null, "admin");
813 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800814 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700815
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700816 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800817 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700818 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800819 out.endTag(null, "password-owner");
820 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700821
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700822 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800823 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700824 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800825 out.endTag(null, "failed-password-attempts");
826 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700827
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700828 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
829 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
830 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
831 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700832 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700833 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
834 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
835 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
836 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
837 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700838 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700839 .toString(policy.mActivePasswordNumeric));
840 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
841 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700842 out.endTag(null, "active-password");
843 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700844
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700845 out.endTag(null, "policies");
846
Dianne Hackbornd6847842010-01-12 18:14:19 -0800847 out.endDocument();
848 stream.close();
849 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700850 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800851 } catch (IOException e) {
852 try {
853 if (stream != null) {
854 stream.close();
855 }
856 } catch (IOException ex) {
857 // Ignore
858 }
859 journal.rollback();
860 }
861 }
862
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700863 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700864 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
865 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700866 long ident = Binder.clearCallingIdentity();
867 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700868 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700869 } finally {
870 Binder.restoreCallingIdentity(ident);
871 }
Jim Miller284b62e2010-06-08 14:27:42 -0700872 }
873
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700874 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
875 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800876 FileInputStream stream = null;
877 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800878 try {
879 stream = new FileInputStream(file);
880 XmlPullParser parser = Xml.newPullParser();
881 parser.setInput(stream, null);
882
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800883 int type;
884 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
885 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800886 }
887 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800888 if (!"policies".equals(tag)) {
889 throw new XmlPullParserException(
890 "Settings do not start with policies tag: found " + tag);
891 }
892 type = parser.next();
893 int outerDepth = parser.getDepth();
894 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
895 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
896 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
897 continue;
898 }
899 tag = parser.getName();
900 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800901 String name = parser.getAttributeValue(null, "name");
902 try {
903 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700904 ComponentName.unflattenFromString(name), userHandle);
905 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
906 != userHandle)) {
907 Slog.w(TAG, "findAdmin returned an incorrect uid "
908 + dai.getActivityInfo().applicationInfo.uid + " for user "
909 + userHandle);
910 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800911 if (dai != null) {
912 ActiveAdmin ap = new ActiveAdmin(dai);
913 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700914 policy.mAdminMap.put(ap.info.getComponent(), ap);
915 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800916 }
917 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700918 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800919 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800920 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700921 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800922 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800923 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800924 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700925 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800926 parser.getAttributeValue(null, "value"));
927 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700928 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700929 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700930 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700931 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700932 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700933 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700934 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700935 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700936 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700937 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700938 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700939 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700940 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700941 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700942 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700943 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700944 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700945 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800946 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700947 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800948 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800949 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800950 }
951 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700952 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800953 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700954 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800955 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700956 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700957 } catch (FileNotFoundException e) {
958 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800959 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700960 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800961 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700962 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800963 }
964 try {
965 if (stream != null) {
966 stream.close();
967 }
968 } catch (IOException e) {
969 // Ignore
970 }
971
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700972 // Validate that what we stored for the password quality matches
973 // sufficiently what is currently set. Note that this is only
974 // a sanity check in case the two get out of sync; this should
975 // never normally happen.
976 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700977 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700978 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700979 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700980 + " does not match actual quality 0x"
981 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700982 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
983 policy.mActivePasswordLength = 0;
984 policy.mActivePasswordUpperCase = 0;
985 policy.mActivePasswordLowerCase = 0;
986 policy.mActivePasswordLetters = 0;
987 policy.mActivePasswordNumeric = 0;
988 policy.mActivePasswordSymbols = 0;
989 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700990 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700991
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700992 validatePasswordOwnerLocked(policy);
993 syncDeviceCapabilitiesLocked(policy);
994 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800995 }
996
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700997 static void validateQualityConstant(int quality) {
998 switch (quality) {
999 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -05001000 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001001 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
1002 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
1003 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
1004 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001005 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001006 return;
1007 }
1008 throw new IllegalArgumentException("Invalid quality constant: 0x"
1009 + Integer.toHexString(quality));
1010 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001011
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001012 void validatePasswordOwnerLocked(DevicePolicyData policy) {
1013 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001014 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001015 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
1016 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001017 haveOwner = true;
1018 break;
1019 }
1020 }
1021 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001022 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001023 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001024 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001025 }
1026 }
1027 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001028
Ben Komalo2447edd2011-05-09 16:05:33 -07001029 /**
1030 * Pushes down policy information to the system for any policies related to general device
1031 * capabilities that need to be enforced by lower level services (e.g. Camera services).
1032 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001033 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -07001034 // Ensure the status of the camera is synced down to the system. Interested native services
1035 // should monitor this value and act accordingly.
1036 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001037 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07001038 if (cameraDisabled != systemState) {
1039 long token = Binder.clearCallingIdentity();
1040 try {
1041 String value = cameraDisabled ? "1" : "0";
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001042 if (DBG) Slog.v(TAG, "Change in camera state ["
Ben Komalo2447edd2011-05-09 16:05:33 -07001043 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
1044 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
1045 } finally {
1046 Binder.restoreCallingIdentity(token);
1047 }
1048 }
1049 }
1050
Dianne Hackbornd6847842010-01-12 18:14:19 -08001051 public void systemReady() {
1052 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001053 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001054 loadDeviceOwner();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001055 }
1056 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001057
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001058 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -08001059 synchronized (this) {
1060 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001061 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001062 if (N <= 0) {
1063 return;
1064 }
1065 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001066 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001067 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1068 && admin.passwordExpirationTimeout > 0L
1069 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001070 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001071 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1072 }
1073 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001074 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001075 }
1076 }
1077
Maggie Benthall0469f412013-09-05 15:30:26 -04001078 private void manageMonitoringCertificateNotification(Intent intent) {
1079 final NotificationManager notificationManager = getNotificationManager();
1080
1081 final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
1082 if (! hasCert) {
1083 if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
1084 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1085 for (UserInfo user : um.getUsers()) {
1086 notificationManager.cancelAsUser(
1087 null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
1088 }
1089 }
1090 return;
1091 }
1092 final boolean isManaged = getDeviceOwner() != null;
1093 int smallIconId;
1094 String contentText;
1095 if (isManaged) {
1096 contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
1097 getDeviceOwnerName());
1098 smallIconId = R.drawable.stat_sys_certificate_info;
1099 } else {
1100 contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
1101 smallIconId = android.R.drawable.stat_sys_warning;
1102 }
1103
1104 Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
1105 dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1106 dialogIntent.setPackage("com.android.settings");
1107 // Notification will be sent individually to all users. The activity should start as
1108 // whichever user is current when it starts.
1109 PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
1110 PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
1111
1112 Notification noti = new Notification.Builder(mContext)
1113 .setSmallIcon(smallIconId)
1114 .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
1115 .setContentText(contentText)
1116 .setContentIntent(notifyIntent)
1117 .setPriority(Notification.PRIORITY_HIGH)
1118 .setShowWhen(false)
1119 .build();
1120
1121 // If this is a boot intent, this will fire for each user. But if this is a storage changed
1122 // intent, it will fire once, so we need to notify all users.
1123 if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
1124 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1125 for (UserInfo user : um.getUsers()) {
1126 notificationManager.notifyAsUser(
1127 null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
1128 }
1129 } else {
1130 notificationManager.notifyAsUser(
1131 null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
1132 }
1133 }
1134
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001135 /**
1136 * @param adminReceiver The admin to add
1137 * @param refreshing true = update an active admin, no error
1138 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001139 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001140 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001141 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001142 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001143
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001144 DevicePolicyData policy = getUserData(userHandle);
1145 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001146 if (info == null) {
1147 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1148 }
1149 synchronized (this) {
1150 long ident = Binder.clearCallingIdentity();
1151 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001152 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001153 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001154 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001155 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001156 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001157 int replaceIndex = -1;
1158 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001159 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001160 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001161 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001162 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1163 replaceIndex = i;
1164 break;
1165 }
1166 }
1167 }
1168 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001169 policy.mAdminList.add(newAdmin);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001170 enableIfNecessary(info.getPackageName(), userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001171 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001172 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001173 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001174 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001175 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001176 } finally {
1177 Binder.restoreCallingIdentity(ident);
1178 }
1179 }
1180 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001181
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001182 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
1183 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001184 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001185 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001186 }
1187 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001188
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001189 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
1190 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001191 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001192 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001193 if (administrator == null) {
1194 throw new SecurityException("No active admin " + adminReceiver);
1195 }
1196 return administrator.info.usesPolicy(policyId);
1197 }
1198 }
1199
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001200 public List<ComponentName> getActiveAdmins(int userHandle) {
1201 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001202 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001203 DevicePolicyData policy = getUserData(userHandle);
1204 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001205 if (N <= 0) {
1206 return null;
1207 }
1208 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1209 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001210 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001211 }
1212 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001213 }
1214 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001215
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001216 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
1217 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001218 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001219 DevicePolicyData policy = getUserData(userHandle);
1220 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001221 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001222 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001223 return true;
1224 }
1225 }
1226 return false;
1227 }
1228 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001229
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001230 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
1231 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001232 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001233 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001234 if (admin == null) {
1235 return;
1236 }
1237 if (admin.getUid() != Binder.getCallingUid()) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07001238 // If trying to remove device owner, refuse when the caller is not the owner.
1239 if (mDeviceOwner != null
1240 && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
1241 return;
1242 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001243 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001244 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001245 }
1246 long ident = Binder.clearCallingIdentity();
1247 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001248 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001249 } finally {
1250 Binder.restoreCallingIdentity(ident);
1251 }
1252 }
1253 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001254
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001255 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001256 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001257 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001258
Dianne Hackbornd6847842010-01-12 18:14:19 -08001259 synchronized (this) {
1260 if (who == null) {
1261 throw new NullPointerException("ComponentName is null");
1262 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001263 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1264 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001265 if (ap.passwordQuality != quality) {
1266 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001267 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001268 }
1269 }
1270 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001271
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001272 public int getPasswordQuality(ComponentName who, int userHandle) {
1273 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001274 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001275 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001276 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001277
Dianne Hackborn254cb442010-01-27 19:23:59 -08001278 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001279 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001280 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001281 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001282
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001283 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001284 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001285 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001286 if (mode < admin.passwordQuality) {
1287 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001288 }
1289 }
1290 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001291 }
1292 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001293
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001294 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
1295 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001296 synchronized (this) {
1297 if (who == null) {
1298 throw new NullPointerException("ComponentName is null");
1299 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001300 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1301 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001302 if (ap.minimumPasswordLength != length) {
1303 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001304 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001305 }
1306 }
1307 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001308
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001309 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
1310 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001311 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001312 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001313 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001314
Dianne Hackborn254cb442010-01-27 19:23:59 -08001315 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001316 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001317 return admin != null ? admin.minimumPasswordLength : length;
1318 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001319
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001320 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001321 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001322 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001323 if (length < admin.minimumPasswordLength) {
1324 length = admin.minimumPasswordLength;
1325 }
1326 }
1327 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001328 }
1329 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001330
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001331 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
1332 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001333 synchronized (this) {
1334 if (who == null) {
1335 throw new NullPointerException("ComponentName is null");
1336 }
1337 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1338 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1339 if (ap.passwordHistoryLength != length) {
1340 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001341 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001342 }
1343 }
1344 }
1345
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001346 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
1347 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001348 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001349 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001350 int length = 0;
1351
1352 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001353 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001354 return admin != null ? admin.passwordHistoryLength : length;
1355 }
1356
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001357 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001358 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001359 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001360 if (length < admin.passwordHistoryLength) {
1361 length = admin.passwordHistoryLength;
1362 }
1363 }
1364 return length;
1365 }
1366 }
1367
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001368 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
1369 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001370 synchronized (this) {
1371 if (who == null) {
1372 throw new NullPointerException("ComponentName is null");
1373 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001374 if (timeout < 0) {
1375 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001376 }
1377 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1378 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1379 // Calling this API automatically bumps the expiration date
1380 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1381 ap.passwordExpirationDate = expiration;
1382 ap.passwordExpirationTimeout = timeout;
1383 if (timeout > 0L) {
1384 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1385 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1386 .format(new Date(expiration)));
1387 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001388 saveSettingsLocked(userHandle);
1389 // in case this is the first one
1390 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001391 }
1392 }
1393
Andy Stadler043116a2010-11-29 17:43:32 -08001394 /**
1395 * Return a single admin's expiration cycle time, or the min of all cycle times.
1396 * Returns 0 if not configured.
1397 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001398 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
1399 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001400 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001401 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001402 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001403 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001404 }
1405
Andy Stadler043116a2010-11-29 17:43:32 -08001406 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001407 DevicePolicyData policy = getUserData(userHandle);
1408 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001409 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001410 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001411 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1412 && timeout > admin.passwordExpirationTimeout)) {
1413 timeout = admin.passwordExpirationTimeout;
1414 }
1415 }
1416 return timeout;
1417 }
1418 }
1419
Andy Stadler043116a2010-11-29 17:43:32 -08001420 /**
1421 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1422 * Returns 0 if not configured.
1423 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001424 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001425 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001426 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001427 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001428 }
1429
Andy Stadler043116a2010-11-29 17:43:32 -08001430 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001431 DevicePolicyData policy = getUserData(userHandle);
1432 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001433 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001434 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001435 if (timeout == 0L || (admin.passwordExpirationDate != 0
1436 && timeout > admin.passwordExpirationDate)) {
1437 timeout = admin.passwordExpirationDate;
1438 }
1439 }
1440 return timeout;
1441 }
1442
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001443 public long getPasswordExpiration(ComponentName who, int userHandle) {
1444 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001445 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001446 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001447 }
1448 }
1449
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001450 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
1451 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001452 synchronized (this) {
1453 if (who == null) {
1454 throw new NullPointerException("ComponentName is null");
1455 }
1456 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1457 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1458 if (ap.minimumPasswordUpperCase != length) {
1459 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001460 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001461 }
1462 }
1463 }
1464
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001465 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
1466 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001467 synchronized (this) {
1468 int length = 0;
1469
1470 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001471 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001472 return admin != null ? admin.minimumPasswordUpperCase : length;
1473 }
1474
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001475 DevicePolicyData policy = getUserData(userHandle);
1476 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001477 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001478 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001479 if (length < admin.minimumPasswordUpperCase) {
1480 length = admin.minimumPasswordUpperCase;
1481 }
1482 }
1483 return length;
1484 }
1485 }
1486
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001487 public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
1488 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001489 synchronized (this) {
1490 if (who == null) {
1491 throw new NullPointerException("ComponentName is null");
1492 }
1493 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1494 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1495 if (ap.minimumPasswordLowerCase != length) {
1496 ap.minimumPasswordLowerCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001497 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001498 }
1499 }
1500 }
1501
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001502 public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
1503 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001504 synchronized (this) {
1505 int length = 0;
1506
1507 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001508 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001509 return admin != null ? admin.minimumPasswordLowerCase : length;
1510 }
1511
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001512 DevicePolicyData policy = getUserData(userHandle);
1513 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001514 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001515 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001516 if (length < admin.minimumPasswordLowerCase) {
1517 length = admin.minimumPasswordLowerCase;
1518 }
1519 }
1520 return length;
1521 }
1522 }
1523
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001524 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
1525 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001526 synchronized (this) {
1527 if (who == null) {
1528 throw new NullPointerException("ComponentName is null");
1529 }
1530 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1531 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1532 if (ap.minimumPasswordLetters != length) {
1533 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001534 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001535 }
1536 }
1537 }
1538
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001539 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
1540 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001541 synchronized (this) {
1542 int length = 0;
1543
1544 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001545 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001546 return admin != null ? admin.minimumPasswordLetters : length;
1547 }
1548
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001549 DevicePolicyData policy = getUserData(userHandle);
1550 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001551 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001552 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001553 if (length < admin.minimumPasswordLetters) {
1554 length = admin.minimumPasswordLetters;
1555 }
1556 }
1557 return length;
1558 }
1559 }
1560
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001561 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
1562 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001563 synchronized (this) {
1564 if (who == null) {
1565 throw new NullPointerException("ComponentName is null");
1566 }
1567 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1568 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1569 if (ap.minimumPasswordNumeric != length) {
1570 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001571 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001572 }
1573 }
1574 }
1575
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001576 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
1577 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001578 synchronized (this) {
1579 int length = 0;
1580
1581 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001582 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001583 return admin != null ? admin.minimumPasswordNumeric : length;
1584 }
1585
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001586 DevicePolicyData policy = getUserData(userHandle);
1587 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001588 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001589 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001590 if (length < admin.minimumPasswordNumeric) {
1591 length = admin.minimumPasswordNumeric;
1592 }
1593 }
1594 return length;
1595 }
1596 }
1597
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001598 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
1599 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001600 synchronized (this) {
1601 if (who == null) {
1602 throw new NullPointerException("ComponentName is null");
1603 }
1604 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1605 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1606 if (ap.minimumPasswordSymbols != length) {
1607 ap.minimumPasswordSymbols = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001608 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001609 }
1610 }
1611 }
1612
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001613 public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
1614 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001615 synchronized (this) {
1616 int length = 0;
1617
1618 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001619 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001620 return admin != null ? admin.minimumPasswordSymbols : length;
1621 }
1622
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001623 DevicePolicyData policy = getUserData(userHandle);
1624 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001625 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001626 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001627 if (length < admin.minimumPasswordSymbols) {
1628 length = admin.minimumPasswordSymbols;
1629 }
1630 }
1631 return length;
1632 }
1633 }
1634
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001635 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
1636 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001637 synchronized (this) {
1638 if (who == null) {
1639 throw new NullPointerException("ComponentName is null");
1640 }
1641 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1642 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1643 if (ap.minimumPasswordNonLetter != length) {
1644 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001645 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001646 }
1647 }
1648 }
1649
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001650 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
1651 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001652 synchronized (this) {
1653 int length = 0;
1654
1655 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001656 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001657 return admin != null ? admin.minimumPasswordNonLetter : length;
1658 }
1659
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001660 DevicePolicyData policy = getUserData(userHandle);
1661 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001662 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001663 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001664 if (length < admin.minimumPasswordNonLetter) {
1665 length = admin.minimumPasswordNonLetter;
1666 }
1667 }
1668 return length;
1669 }
1670 }
1671
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001672 public boolean isActivePasswordSufficient(int userHandle) {
1673 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001674 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001675 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001676 // This API can only be called by an active device admin,
1677 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001678 getActiveAdminForCallerLocked(null,
1679 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001680 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1681 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001682 return false;
1683 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001684 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001685 return true;
1686 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001687 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1688 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1689 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1690 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1691 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1692 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001693 }
1694 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001695
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001696 public int getCurrentFailedPasswordAttempts(int userHandle) {
1697 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001698 synchronized (this) {
1699 // This API can only be called by an active device admin,
1700 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001701 getActiveAdminForCallerLocked(null,
1702 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001703 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001704 }
1705 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001706
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001707 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
1708 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001709 synchronized (this) {
1710 // This API can only be called by an active device admin,
1711 // so try to retrieve it to check that the caller is one.
1712 getActiveAdminForCallerLocked(who,
1713 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1714 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1715 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1716 if (ap.maximumFailedPasswordsForWipe != num) {
1717 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001718 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001719 }
1720 }
1721 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001722
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001723 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
1724 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001725 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001726 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001727 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001728
Dianne Hackborn254cb442010-01-27 19:23:59 -08001729 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001730 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001731 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1732 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001733
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001734 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001735 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001736 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001737 if (count == 0) {
1738 count = admin.maximumFailedPasswordsForWipe;
1739 } else if (admin.maximumFailedPasswordsForWipe != 0
1740 && count > admin.maximumFailedPasswordsForWipe) {
1741 count = admin.maximumFailedPasswordsForWipe;
1742 }
1743 }
1744 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001745 }
1746 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001747
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001748 public boolean resetPassword(String password, int flags, int userHandle) {
1749 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001750 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001751 synchronized (this) {
1752 // This API can only be called by an active device admin,
1753 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001754 getActiveAdminForCallerLocked(null,
1755 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001756 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001757 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001758 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001759 if (realQuality < quality
1760 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001761 Slog.w(TAG, "resetPassword: password quality 0x"
joonyoung.choad83c192013-04-18 13:51:08 +09001762 + Integer.toHexString(realQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001763 + " does not meet required quality 0x"
1764 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001765 return false;
1766 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001767 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001768 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001769 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001770 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001771 Slog.w(TAG, "resetPassword: password length " + password.length()
1772 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001773 return false;
1774 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001775 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1776 int letters = 0;
1777 int uppercase = 0;
1778 int lowercase = 0;
1779 int numbers = 0;
1780 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001781 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001782 for (int i = 0; i < password.length(); i++) {
1783 char c = password.charAt(i);
1784 if (c >= 'A' && c <= 'Z') {
1785 letters++;
1786 uppercase++;
1787 } else if (c >= 'a' && c <= 'z') {
1788 letters++;
1789 lowercase++;
1790 } else if (c >= '0' && c <= '9') {
1791 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001792 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001793 } else {
1794 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001795 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001796 }
1797 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001798 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001799 if(letters < neededLetters) {
1800 Slog.w(TAG, "resetPassword: number of letters " + letters
1801 + " does not meet required number of letters " + neededLetters);
1802 return false;
1803 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001804 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001805 if (numbers < neededNumbers) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001806 Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
1807 + " does not meet required number of numerical digits "
1808 + neededNumbers);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001809 return false;
1810 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001811 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001812 if (lowercase < neededLowerCase) {
1813 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1814 + " does not meet required number of lowercase letters "
1815 + neededLowerCase);
1816 return false;
1817 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001818 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001819 if (uppercase < neededUpperCase) {
1820 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1821 + " does not meet required number of uppercase letters "
1822 + neededUpperCase);
1823 return false;
1824 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001825 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001826 if (symbols < neededSymbols) {
1827 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1828 + " does not meet required number of special symbols " + neededSymbols);
1829 return false;
1830 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001831 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001832 if (nonletter < neededNonLetter) {
1833 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1834 + " does not meet required number of non-letter characters "
1835 + neededNonLetter);
1836 return false;
1837 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001838 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001839 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001840
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001841 int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001842 DevicePolicyData policy = getUserData(userHandle);
1843 if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001844 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001845 return false;
1846 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001847
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001848 // Don't do this with the lock held, because it is going to call
1849 // back in to the service.
1850 long ident = Binder.clearCallingIdentity();
1851 try {
1852 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001853 utils.saveLockPassword(password, quality, false, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001854 synchronized (this) {
1855 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1856 != 0 ? callingUid : -1;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001857 if (policy.mPasswordOwner != newOwner) {
1858 policy.mPasswordOwner = newOwner;
1859 saveSettingsLocked(userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001860 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001861 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001862 } finally {
1863 Binder.restoreCallingIdentity(ident);
1864 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001865
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001866 return true;
1867 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001868
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001869 public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
1870 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001871 synchronized (this) {
1872 if (who == null) {
1873 throw new NullPointerException("ComponentName is null");
1874 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001875 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001876 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001877 if (ap.maximumTimeToUnlock != timeMs) {
1878 ap.maximumTimeToUnlock = timeMs;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001879 saveSettingsLocked(userHandle);
1880 updateMaximumTimeToLockLocked(getUserData(userHandle));
Dianne Hackbornd6847842010-01-12 18:14:19 -08001881 }
1882 }
1883 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001884
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001885 void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
1886 long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
1887 if (policy.mLastMaximumTimeToLock == timeMs) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001888 return;
1889 }
1890
1891 long ident = Binder.clearCallingIdentity();
1892 try {
1893 if (timeMs <= 0) {
1894 timeMs = Integer.MAX_VALUE;
1895 } else {
1896 // Make sure KEEP_SCREEN_ON is disabled, since that
1897 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07001898 Settings.Global.putInt(mContext.getContentResolver(),
1899 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001900 }
1901
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001902 policy.mLastMaximumTimeToLock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001903
1904 try {
Jeff Brown96307042012-07-27 15:51:34 -07001905 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001906 } catch (RemoteException e) {
1907 Slog.w(TAG, "Failure talking with power manager", e);
1908 }
1909 } finally {
1910 Binder.restoreCallingIdentity(ident);
1911 }
1912 }
1913
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001914 public long getMaximumTimeToLock(ComponentName who, int userHandle) {
1915 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001916 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001917 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001918
Dianne Hackborn254cb442010-01-27 19:23:59 -08001919 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001920 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001921 return admin != null ? admin.maximumTimeToUnlock : time;
1922 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001923
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001924 DevicePolicyData policy = getUserData(userHandle);
1925 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001926 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001927 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001928 if (time == 0) {
1929 time = admin.maximumTimeToUnlock;
1930 } else if (admin.maximumTimeToUnlock != 0
1931 && time > admin.maximumTimeToUnlock) {
1932 time = admin.maximumTimeToUnlock;
1933 }
1934 }
1935 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001936 }
1937 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001938
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001939 public void lockNow() {
1940 synchronized (this) {
1941 // This API can only be called by an active device admin,
1942 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001943 getActiveAdminForCallerLocked(null,
1944 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001945 lockNowUnchecked();
1946 }
1947 }
1948
1949 private void lockNowUnchecked() {
1950 long ident = Binder.clearCallingIdentity();
1951 try {
1952 // Power off the display
1953 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1954 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
1955 // Ensure the device is locked
Adam Cohenf7522022012-10-03 20:03:18 -07001956 getWindowManager().lockNow(null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001957 } catch (RemoteException e) {
1958 } finally {
1959 Binder.restoreCallingIdentity(ident);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001960 }
1961 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001962
Ben Komaloed48c8b2011-10-17 17:30:21 -07001963 private boolean isExtStorageEncrypted() {
1964 String state = SystemProperties.get("vold.decrypt");
1965 return !"".equals(state);
1966 }
1967
Maggie Benthallda51e682013-08-08 22:35:44 -04001968 public boolean installCaCert(byte[] certBuffer) throws RemoteException {
1969 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
1970 KeyChainConnection keyChainConnection = null;
1971 byte[] pemCert;
1972 try {
1973 X509Certificate cert = parseCert(certBuffer);
1974 pemCert = Credentials.convertToPem(cert);
1975 } catch (CertificateException ce) {
1976 Log.e(TAG, "Problem converting cert", ce);
1977 return false;
1978 } catch (IOException ioe) {
1979 Log.e(TAG, "Problem reading cert", ioe);
1980 return false;
1981 }
1982 try {
1983 keyChainConnection = KeyChain.bind(mContext);
1984 try {
1985 keyChainConnection.getService().installCaCertificate(pemCert);
1986 return true;
1987 } finally {
1988 if (keyChainConnection != null) {
1989 keyChainConnection.close();
1990 keyChainConnection = null;
1991 }
1992 }
1993 } catch (InterruptedException e1) {
1994 Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
1995 Thread.currentThread().interrupt();
1996 }
1997 return false;
1998 }
1999
2000 private static X509Certificate parseCert(byte[] certBuffer)
2001 throws CertificateException, IOException {
2002 CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
2003 return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
2004 certBuffer));
2005 }
2006
2007 public void uninstallCaCert(final byte[] certBuffer) {
2008 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
2009 TrustedCertificateStore certStore = new TrustedCertificateStore();
2010 String alias = null;
2011 try {
2012 X509Certificate cert = parseCert(certBuffer);
2013 alias = certStore.getCertificateAlias(cert);
2014 } catch (CertificateException ce) {
2015 Log.e(TAG, "Problem creating X509Certificate", ce);
2016 return;
2017 } catch (IOException ioe) {
2018 Log.e(TAG, "Problem reading certificate", ioe);
2019 return;
2020 }
2021 try {
2022 KeyChainConnection keyChainConnection = KeyChain.bind(mContext);
2023 IKeyChainService service = keyChainConnection.getService();
2024 try {
2025 service.deleteCaCertificate(alias);
2026 } catch (RemoteException e) {
2027 Log.e(TAG, "from CaCertUninstaller: ", e);
2028 } finally {
2029 keyChainConnection.close();
2030 keyChainConnection = null;
2031 }
2032 } catch (InterruptedException ie) {
2033 Log.w(TAG, "CaCertUninstaller: ", ie);
2034 Thread.currentThread().interrupt();
2035 }
2036 }
2037
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002038 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07002039 // If the SD card is encrypted and non-removable, we have to force a wipe.
2040 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
2041 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
2042
2043 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
2044 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07002045 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09002046 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07002047 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
2048 mWakeLock.acquire(10000);
2049 mContext.startService(intent);
2050 } else {
2051 try {
2052 RecoverySystem.rebootWipeUserData(mContext);
2053 } catch (IOException e) {
2054 Slog.w(TAG, "Failed requesting data wipe", e);
2055 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002056 }
2057 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002058
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002059 public void wipeData(int flags, final int userHandle) {
2060 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002061 synchronized (this) {
2062 // This API can only be called by an active device admin,
2063 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08002064 getActiveAdminForCallerLocked(null,
2065 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002066 long ident = Binder.clearCallingIdentity();
2067 try {
Amith Yamasani32f07422012-11-16 15:09:13 -08002068 wipeDeviceOrUserLocked(flags, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002069 } finally {
2070 Binder.restoreCallingIdentity(ident);
2071 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002072 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002073 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002074
Amith Yamasani32f07422012-11-16 15:09:13 -08002075 private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
2076 if (userHandle == UserHandle.USER_OWNER) {
2077 wipeDataLocked(flags);
2078 } else {
2079 lockNowUnchecked();
2080 mHandler.post(new Runnable() {
2081 public void run() {
2082 try {
Amith Yamasanie4cf7342012-12-17 11:12:09 -08002083 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
Amith Yamasani32f07422012-11-16 15:09:13 -08002084 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
2085 .removeUser(userHandle);
2086 } catch (RemoteException re) {
2087 // Shouldn't happen
2088 }
2089 }
2090 });
2091 }
2092 }
2093
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002094 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
2095 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002096 mContext.enforceCallingOrSelfPermission(
2097 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002098
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002099 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002100 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002101 if (admin == null) {
2102 try {
2103 result.sendResult(null);
2104 } catch (RemoteException e) {
2105 }
2106 return;
2107 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002108 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002109 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002110 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002111 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002112 @Override
2113 public void onReceive(Context context, Intent intent) {
2114 try {
2115 result.sendResult(getResultExtras(false));
2116 } catch (RemoteException e) {
2117 }
2118 }
2119 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002120 }
2121 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002122
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002123 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002124 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
2125 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002126 mContext.enforceCallingOrSelfPermission(
2127 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002128 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002129
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002130 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002131
Dianne Hackbornd6847842010-01-12 18:14:19 -08002132 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002133 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
2134 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
2135 || p.mActivePasswordUpperCase != uppercase
2136 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
2137 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002138 long ident = Binder.clearCallingIdentity();
2139 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002140 p.mActivePasswordQuality = quality;
2141 p.mActivePasswordLength = length;
2142 p.mActivePasswordLetters = letters;
2143 p.mActivePasswordLowerCase = lowercase;
2144 p.mActivePasswordUpperCase = uppercase;
2145 p.mActivePasswordNumeric = numbers;
2146 p.mActivePasswordSymbols = symbols;
2147 p.mActivePasswordNonLetter = nonletter;
2148 p.mFailedPasswordAttempts = 0;
2149 saveSettingsLocked(userHandle);
2150 updatePasswordExpirationsLocked(userHandle);
2151 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002152 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002153 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002154 } finally {
2155 Binder.restoreCallingIdentity(ident);
2156 }
2157 }
2158 }
2159 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002160
Andy Stadler043116a2010-11-29 17:43:32 -08002161 /**
2162 * Called any time the device password is updated. Resets all password expiration clocks.
2163 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002164 private void updatePasswordExpirationsLocked(int userHandle) {
2165 DevicePolicyData policy = getUserData(userHandle);
2166 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08002167 if (N > 0) {
2168 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002169 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08002170 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08002171 long timeout = admin.passwordExpirationTimeout;
2172 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
2173 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08002174 }
2175 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002176 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08002177 }
2178 }
2179
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002180 public void reportFailedPasswordAttempt(int userHandle) {
2181 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002182 mContext.enforceCallingOrSelfPermission(
2183 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002184
Dianne Hackbornd6847842010-01-12 18:14:19 -08002185 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002186 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002187 long ident = Binder.clearCallingIdentity();
2188 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002189 policy.mFailedPasswordAttempts++;
2190 saveSettingsLocked(userHandle);
2191 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
2192 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
Amith Yamasani32f07422012-11-16 15:09:13 -08002193 wipeDeviceOrUserLocked(0, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002194 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002195 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002196 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002197 } finally {
2198 Binder.restoreCallingIdentity(ident);
2199 }
2200 }
2201 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002202
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002203 public void reportSuccessfulPasswordAttempt(int userHandle) {
2204 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002205 mContext.enforceCallingOrSelfPermission(
2206 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002207
Dianne Hackbornd6847842010-01-12 18:14:19 -08002208 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002209 DevicePolicyData policy = getUserData(userHandle);
2210 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002211 long ident = Binder.clearCallingIdentity();
2212 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002213 policy.mFailedPasswordAttempts = 0;
2214 policy.mPasswordOwner = -1;
2215 saveSettingsLocked(userHandle);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002216 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002217 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002218 } finally {
2219 Binder.restoreCallingIdentity(ident);
2220 }
2221 }
2222 }
2223 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002224
Oscar Montemayor69238c62010-08-03 10:51:06 -07002225 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002226 String exclusionList, int userHandle) {
2227 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002228 synchronized(this) {
2229 if (who == null) {
2230 throw new NullPointerException("ComponentName is null");
2231 }
2232
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002233 // Only check if owner has set global proxy. We don't allow other users to set it.
2234 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002235 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2236 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2237
2238 // Scan through active admins and find if anyone has already
2239 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002240 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002241 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002242 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002243 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2244 // Another admin already sets the global proxy
2245 // Return it to the caller.
2246 return component;
2247 }
2248 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002249
2250 // If the user is not the owner, don't set the global proxy. Fail silently.
2251 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2252 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2253 + userHandle + " is not permitted.");
2254 return null;
2255 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002256 if (proxySpec == null) {
2257 admin.specifiesGlobalProxy = false;
2258 admin.globalProxySpec = null;
2259 admin.globalProxyExclusionList = null;
2260 } else {
2261
2262 admin.specifiesGlobalProxy = true;
2263 admin.globalProxySpec = proxySpec;
2264 admin.globalProxyExclusionList = exclusionList;
2265 }
2266
2267 // Reset the global proxy accordingly
2268 // Do this using system permissions, as apps cannot write to secure settings
2269 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002270 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002271 Binder.restoreCallingIdentity(origId);
2272 return null;
2273 }
2274 }
2275
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002276 public ComponentName getGlobalProxyAdmin(int userHandle) {
2277 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002278 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002279 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002280 // Scan through active admins and find if anyone has already
2281 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002282 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002283 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002284 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002285 if (ap.specifiesGlobalProxy) {
2286 // Device admin sets the global proxy
2287 // Return it to the caller.
2288 return ap.info.getComponent();
2289 }
2290 }
2291 }
2292 // No device admin sets the global proxy.
2293 return null;
2294 }
2295
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002296 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2297 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002298 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002299 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002300 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002301 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002302 return;
2303 }
2304 }
2305 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002306 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002307 }
2308
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002309 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002310 if (exclusionList == null) {
2311 exclusionList = "";
2312 }
2313 if (proxySpec == null) {
2314 proxySpec = "";
2315 }
2316 // Remove white spaces
2317 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002318 String data[] = proxySpec.split(":");
2319 int proxyPort = 8080;
2320 if (data.length > 1) {
2321 try {
2322 proxyPort = Integer.parseInt(data[1]);
2323 } catch (NumberFormatException e) {}
2324 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002325 exclusionList = exclusionList.trim();
2326 ContentResolver res = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -07002327 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
2328 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2329 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwalt434203a2010-10-11 16:00:27 -07002330 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002331 }
2332
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002333 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002334 * Set the storage encryption request for a single admin. Returns the new total request
2335 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002336 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002337 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
2338 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002339 synchronized (this) {
2340 // Check for permissions
2341 if (who == null) {
2342 throw new NullPointerException("ComponentName is null");
2343 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002344 // Only owner can set storage encryption
2345 if (userHandle != UserHandle.USER_OWNER
2346 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2347 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2348 + UserHandle.getCallingUserId() + " is not permitted.");
2349 return 0;
2350 }
2351
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002352 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2353 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2354
Andy Stadler22dbfda2011-01-17 12:47:31 -08002355 // Quick exit: If the filesystem does not support encryption, we can exit early.
2356 if (!isEncryptionSupported()) {
2357 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2358 }
2359
2360 // (1) Record the value for the admin so it's sticky
2361 if (ap.encryptionRequested != encrypt) {
2362 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002363 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002364 }
2365
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002366 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002367 // (2) Compute "max" for all admins
2368 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002369 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002370 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002371 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002372 }
2373
2374 // Notify OS of new request
2375 setEncryptionRequested(newRequested);
2376
2377 // Return the new global request status
2378 return newRequested
2379 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2380 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002381 }
2382 }
2383
2384 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002385 * Get the current storage encryption request status for a given admin, or aggregate of all
2386 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002387 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002388 public boolean getStorageEncryption(ComponentName who, int userHandle) {
2389 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002390 synchronized (this) {
2391 // Check for permissions if a particular caller is specified
2392 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002393 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002394 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002395 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002396 }
2397
Andy Stadler22dbfda2011-01-17 12:47:31 -08002398 // If no particular caller is specified, return the aggregate set of requests.
2399 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002400 DevicePolicyData policy = getUserData(userHandle);
2401 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002402 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002403 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002404 return true;
2405 }
2406 }
2407 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002408 }
2409 }
2410
Andy Stadler22dbfda2011-01-17 12:47:31 -08002411 /**
2412 * Get the current encryption status of the device.
2413 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002414 public int getStorageEncryptionStatus(int userHandle) {
2415 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002416 return getEncryptionStatus();
2417 }
2418
2419 /**
2420 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2421 */
2422 private boolean isEncryptionSupported() {
2423 // Note, this can be implemented as
2424 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2425 // But is provided as a separate internal method if there's a faster way to do a
2426 // simple check for supported-or-not.
2427 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2428 }
2429
2430 /**
2431 * Hook to low-levels: Reporting the current status of encryption.
2432 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2433 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2434 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2435 */
2436 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002437 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2438 if ("encrypted".equalsIgnoreCase(status)) {
2439 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2440 } else if ("unencrypted".equalsIgnoreCase(status)) {
2441 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2442 } else {
2443 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2444 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002445 }
2446
2447 /**
2448 * Hook to low-levels: If needed, record the new admin setting for encryption.
2449 */
2450 private void setEncryptionRequested(boolean encrypt) {
2451 }
2452
Ben Komalo2447edd2011-05-09 16:05:33 -07002453 /**
2454 * The system property used to share the state of the camera. The native camera service
2455 * is expected to read this property and act accordingly.
2456 */
2457 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2458
2459 /**
2460 * Disables all device cameras according to the specified admin.
2461 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002462 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
2463 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002464 synchronized (this) {
2465 if (who == null) {
2466 throw new NullPointerException("ComponentName is null");
2467 }
2468 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2469 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2470 if (ap.disableCamera != disabled) {
2471 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002472 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002473 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002474 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002475 }
2476 }
2477
2478 /**
2479 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2480 * active admins.
2481 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002482 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Ben Komalo2447edd2011-05-09 16:05:33 -07002483 synchronized (this) {
2484 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002485 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002486 return (admin != null) ? admin.disableCamera : false;
2487 }
2488
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002489 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002490 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002491 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002492 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002493 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002494 if (admin.disableCamera) {
2495 return true;
2496 }
2497 }
2498 return false;
2499 }
2500 }
2501
Jim Millerb8ec4702012-08-31 17:19:10 -07002502 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002503 * Selectively disable keyguard features.
Jim Millerb8ec4702012-08-31 17:19:10 -07002504 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002505 public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002506 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002507 synchronized (this) {
2508 if (who == null) {
2509 throw new NullPointerException("ComponentName is null");
2510 }
2511 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Jim Miller48b9b0d2012-09-19 23:16:50 -07002512 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
2513 if (ap.disabledKeyguardFeatures != which) {
2514 ap.disabledKeyguardFeatures = which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002515 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002516 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002517 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002518 }
2519 }
2520
2521 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002522 * Gets the disabled state for features in keyguard for the given admin,
Jim Millerb8ec4702012-08-31 17:19:10 -07002523 * or the aggregate of all active admins if who is null.
2524 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002525 public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002526 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002527 synchronized (this) {
2528 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002529 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002530 return (admin != null) ? admin.disabledKeyguardFeatures : 0;
Jim Millerb8ec4702012-08-31 17:19:10 -07002531 }
2532
Jim Miller48b9b0d2012-09-19 23:16:50 -07002533 // Determine which keyguard features are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002534 DevicePolicyData policy = getUserData(userHandle);
2535 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002536 int which = 0;
2537 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002538 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002539 which |= admin.disabledKeyguardFeatures;
Jim Millerb8ec4702012-08-31 17:19:10 -07002540 }
2541 return which;
2542 }
2543 }
2544
Amith Yamasani71e6c692013-03-24 17:39:28 -07002545 @Override
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002546 public boolean setDeviceOwner(String packageName, String ownerName) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07002547 if (packageName == null
2548 || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
2549 throw new IllegalArgumentException("Invalid package name " + packageName
2550 + " for device owner");
2551 }
2552 synchronized (this) {
2553 if (mDeviceOwner == null && !isDeviceProvisioned()) {
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002554 mDeviceOwner = new DeviceOwner(packageName, ownerName);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002555 mDeviceOwner.writeOwnerFile();
2556 return true;
2557 } else {
2558 throw new IllegalStateException("Trying to set device owner to " + packageName
2559 + ", owner=" + mDeviceOwner.getPackageName()
2560 + ", device_provisioned=" + isDeviceProvisioned());
2561 }
2562 }
2563 }
2564
2565 @Override
2566 public boolean isDeviceOwner(String packageName) {
2567 synchronized (this) {
2568 return mDeviceOwner != null
2569 && mDeviceOwner.getPackageName().equals(packageName);
2570 }
2571 }
2572
2573 @Override
2574 public String getDeviceOwner() {
2575 synchronized (this) {
2576 if (mDeviceOwner != null) {
2577 return mDeviceOwner.getPackageName();
2578 }
2579 }
2580 return null;
2581 }
2582
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002583 @Override
2584 public String getDeviceOwnerName() {
2585 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
2586 synchronized (this) {
2587 if (mDeviceOwner != null) {
2588 return mDeviceOwner.getName();
2589 }
2590 }
2591 return null;
2592 }
2593
Amith Yamasani71e6c692013-03-24 17:39:28 -07002594 private boolean isDeviceProvisioned() {
2595 return Settings.Global.getInt(mContext.getContentResolver(),
2596 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
2597 }
2598
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002599 private void enforceCrossUserPermission(int userHandle) {
2600 if (userHandle < 0) {
2601 throw new IllegalArgumentException("Invalid userId " + userHandle);
2602 }
2603 final int callingUid = Binder.getCallingUid();
2604 if (userHandle == UserHandle.getUserId(callingUid)) return;
2605 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2606 mContext.enforceCallingOrSelfPermission(
2607 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2608 + " INTERACT_ACROSS_USERS_FULL permission");
2609 }
2610 }
2611
Amith Yamasani71e6c692013-03-24 17:39:28 -07002612 private void enableIfNecessary(String packageName, int userId) {
2613 try {
2614 IPackageManager ipm = AppGlobals.getPackageManager();
2615 ApplicationInfo ai = ipm.getApplicationInfo(packageName,
2616 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2617 userId);
2618 if (ai.enabledSetting
2619 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
2620 ipm.setApplicationEnabledSetting(packageName,
2621 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002622 PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
Amith Yamasani71e6c692013-03-24 17:39:28 -07002623 }
2624 } catch (RemoteException e) {
2625 }
2626 }
2627
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002628 @Override
2629 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2630 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2631 != PackageManager.PERMISSION_GRANTED) {
2632
2633 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2634 + Binder.getCallingPid()
2635 + ", uid=" + Binder.getCallingUid());
2636 return;
2637 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002638
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002639 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002640
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002641 synchronized (this) {
2642 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002643
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002644 int userCount = mUserData.size();
2645 for (int u = 0; u < userCount; u++) {
2646 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2647 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2648 final int N = policy.mAdminList.size();
2649 for (int i=0; i<N; i++) {
2650 ActiveAdmin ap = policy.mAdminList.get(i);
2651 if (ap != null) {
2652 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2653 pw.println(":");
2654 ap.dump(" ", pw);
2655 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002656 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002657
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002658 pw.println(" ");
2659 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2660 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002661 }
2662 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002663
2664 static class DeviceOwner {
2665 private static final String DEVICE_OWNER_XML = "device_owner.xml";
2666 private static final String TAG_DEVICE_OWNER = "device-owner";
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002667 private static final String ATTR_NAME = "name";
Amith Yamasani71e6c692013-03-24 17:39:28 -07002668 private static final String ATTR_PACKAGE = "package";
2669 private String mPackageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002670 private String mOwnerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002671
2672 DeviceOwner() {
2673 readOwnerFile();
2674 }
2675
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002676 DeviceOwner(String packageName, String ownerName) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07002677 this.mPackageName = packageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002678 this.mOwnerName = ownerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002679 }
2680
2681 static boolean isRegistered() {
2682 return new File(Environment.getSystemSecureDirectory(),
2683 DEVICE_OWNER_XML).exists();
2684 }
2685
2686 String getPackageName() {
2687 return mPackageName;
2688 }
2689
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002690 String getName() {
2691 return mOwnerName;
2692 }
2693
Amith Yamasani71e6c692013-03-24 17:39:28 -07002694 static boolean isInstalled(String packageName, PackageManager pm) {
2695 try {
2696 PackageInfo pi;
2697 if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
2698 if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
2699 return true;
2700 }
2701 }
2702 } catch (NameNotFoundException nnfe) {
2703 Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
2704 }
2705 return false;
2706 }
2707
2708 void readOwnerFile() {
2709 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2710 DEVICE_OWNER_XML));
2711 try {
2712 FileInputStream input = file.openRead();
2713 XmlPullParser parser = Xml.newPullParser();
2714 parser.setInput(input, null);
2715 int type;
2716 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2717 && type != XmlPullParser.START_TAG) {
2718 }
2719 String tag = parser.getName();
2720 if (!TAG_DEVICE_OWNER.equals(tag)) {
2721 throw new XmlPullParserException(
2722 "Device Owner file does not start with device-owner tag: found " + tag);
2723 }
2724 mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002725 mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002726 input.close();
2727 } catch (XmlPullParserException xppe) {
2728 Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
2729 } catch (IOException ioe) {
2730 Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
2731 }
2732 }
2733
2734 void writeOwnerFile() {
2735 synchronized (this) {
2736 writeOwnerFileLocked();
2737 }
2738 }
2739
2740 private void writeOwnerFileLocked() {
2741 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2742 DEVICE_OWNER_XML));
2743 try {
2744 FileOutputStream output = file.startWrite();
2745 XmlSerializer out = new FastXmlSerializer();
2746 out.setOutput(output, "utf-8");
2747 out.startDocument(null, true);
2748 out.startTag(null, TAG_DEVICE_OWNER);
2749 out.attribute(null, ATTR_PACKAGE, mPackageName);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002750 if (mOwnerName != null) {
2751 out.attribute(null, ATTR_NAME, mOwnerName);
2752 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002753 out.endTag(null, TAG_DEVICE_OWNER);
2754 out.endDocument();
2755 out.flush();
2756 file.finishWrite(output);
2757 } catch (IOException ioe) {
2758 Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
2759 }
2760 }
2761 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002762}