blob: 2bb99d68ed77e00384166e5af1a247e62a63582e [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;
Raj Mamadgi92d024912013-11-11 13:52:58 -080059import android.net.ProxyProperties;
Amith Yamasani71e6c692013-03-24 17:39:28 -070060import android.net.Uri;
Maggie Benthallda51e682013-08-08 22:35:44 -040061import android.os.AsyncTask;
Dianne Hackbornd6847842010-01-12 18:14:19 -080062import android.os.Binder;
Adam Cohenf7522022012-10-03 20:03:18 -070063import android.os.Bundle;
Ben Komaloed48c8b2011-10-17 17:30:21 -070064import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080065import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080066import android.os.IBinder;
67import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070068import android.os.PowerManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070069import android.os.Process;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080070import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080071import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080072import android.os.RemoteException;
73import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080074import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080075import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070076import android.os.UserHandle;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070077import android.os.UserManager;
Oscar Montemayor69238c62010-08-03 10:51:06 -070078import android.provider.Settings;
Maggie Benthallda51e682013-08-08 22:35:44 -040079import android.security.Credentials;
80import android.security.IKeyChainService;
81import android.security.KeyChain;
82import android.security.KeyChain.KeyChainConnection;
Amith Yamasani71e6c692013-03-24 17:39:28 -070083import android.util.AtomicFile;
Maggie Benthallda51e682013-08-08 22:35:44 -040084import android.util.Log;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080085import android.util.PrintWriterPrinter;
86import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080087import android.util.Slog;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070088import android.util.SparseArray;
Dianne Hackbornd6847842010-01-12 18:14:19 -080089import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080090import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080091import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080092
Maggie Benthallda51e682013-08-08 22:35:44 -040093import java.io.ByteArrayInputStream;
Dianne Hackbornd6847842010-01-12 18:14:19 -080094import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080095import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080096import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070097import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080098import java.io.FileOutputStream;
99import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800100import java.io.PrintWriter;
Maggie Benthallda51e682013-08-08 22:35:44 -0400101import java.security.KeyStore.TrustedCertificateEntry;
102import java.security.cert.CertificateException;
103import java.security.cert.CertificateFactory;
104import java.security.cert.X509Certificate;
Jim Millera4e28d12010-11-08 16:15:47 -0800105import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800106import java.util.ArrayList;
Maggie Benthallda51e682013-08-08 22:35:44 -0400107import java.util.Arrays;
108import java.util.Collection;
Amith Yamasani44a01b72013-09-16 10:44:57 -0700109import java.util.Collections;
Jim Millera4e28d12010-11-08 16:15:47 -0800110import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800111import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800112import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -0700113import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800114
115/**
116 * Implementation of the device policy APIs.
117 */
118public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700119
Jim Miller6b857682011-02-16 16:27:41 -0800120 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -0800121
Amith Yamasani71e6c692013-03-24 17:39:28 -0700122 private static final String DEVICE_POLICIES_XML = "device_policies.xml";
123
Jim Miller6b857682011-02-16 16:27:41 -0800124 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700125
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700126 private static final long MS_PER_DAY = 86400 * 1000;
127
128 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
Jim Millera4e28d12010-11-08 16:15:47 -0800129
130 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
131 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
132
Maggie Benthall0469f412013-09-05 15:30:26 -0400133 private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
134
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700135 private static final boolean DBG = false;
Jim Millera4e28d12010-11-08 16:15:47 -0800136
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800137 final Context mContext;
Dianne Hackborn42499172010-10-15 18:45:07 -0700138 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800139
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800140 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800141 IWindowManager mIWindowManager;
Maggie Benthall0469f412013-09-05 15:30:26 -0400142 NotificationManager mNotificationManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700143
Amith Yamasani71e6c692013-03-24 17:39:28 -0700144 private DeviceOwner mDeviceOwner;
145
Amith Yamasani44a01b72013-09-16 10:44:57 -0700146 /**
147 * Whether or not device admin feature is supported. If it isn't return defaults for all
148 * public methods.
149 */
150 private boolean mHasFeature;
151
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700152 public static class DevicePolicyData {
153 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
154 int mActivePasswordLength = 0;
155 int mActivePasswordUpperCase = 0;
156 int mActivePasswordLowerCase = 0;
157 int mActivePasswordLetters = 0;
158 int mActivePasswordNumeric = 0;
159 int mActivePasswordSymbols = 0;
160 int mActivePasswordNonLetter = 0;
161 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700162
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700163 int mUserHandle;;
164 int mPasswordOwner = -1;
165 long mLastMaximumTimeToLock = -1;
166
167 final HashMap<ComponentName, ActiveAdmin> mAdminMap
168 = new HashMap<ComponentName, ActiveAdmin>();
169 final ArrayList<ActiveAdmin> mAdminList
170 = new ArrayList<ActiveAdmin>();
171
172 public DevicePolicyData(int userHandle) {
173 mUserHandle = userHandle;
174 }
175 }
176
177 final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
178
Jim Millera4e28d12010-11-08 16:15:47 -0800179 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700180
Jim Millera4e28d12010-11-08 16:15:47 -0800181 BroadcastReceiver mReceiver = new BroadcastReceiver() {
182 @Override
183 public void onReceive(Context context, Intent intent) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700184 final String action = intent.getAction();
185 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
186 getSendingUserId());
Jim Millera4e28d12010-11-08 16:15:47 -0800187 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
188 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800189 if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
190 + action + " for user " + userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800191 mHandler.post(new Runnable() {
192 public void run() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700193 handlePasswordExpirationNotification(getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -0800194 }
195 });
Maggie Benthall0469f412013-09-05 15:30:26 -0400196 }
197 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
198 || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
199 manageMonitoringCertificateNotification(intent);
200 }
201 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700202 removeUserData(userHandle);
203 } else if (Intent.ACTION_USER_STARTED.equals(action)
204 || Intent.ACTION_PACKAGE_CHANGED.equals(action)
205 || Intent.ACTION_PACKAGE_REMOVED.equals(action)
206 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
207
208 if (Intent.ACTION_USER_STARTED.equals(action)) {
209 // Reset the policy data
210 synchronized (DevicePolicyManagerService.this) {
211 mUserData.remove(userHandle);
212 }
213 }
214
215 handlePackagesChanged(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800216 }
217 }
218 };
219
Dianne Hackbornd6847842010-01-12 18:14:19 -0800220 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800221 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700222
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800223 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700224
225 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
226 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
227
228 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
229 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
230
231 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
232 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
233
234 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
235 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
236
237 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700238 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700239
240 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
241 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
242
243 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
244 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
245
246 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
247 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
248
249 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
250 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
251
252 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
253 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
254
255 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
256 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
257
258 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
259 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
260
Jim Miller48b9b0d2012-09-19 23:16:50 -0700261 static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
262 int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
Jim Millerb8ec4702012-08-31 17:19:10 -0700263
Andy Stadler22dbfda2011-01-17 12:47:31 -0800264 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700265 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700266
Oscar Montemayor69238c62010-08-03 10:51:06 -0700267 // TODO: review implementation decisions with frameworks team
268 boolean specifiesGlobalProxy = false;
269 String globalProxySpec = null;
270 String globalProxyExclusionList = null;
271
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800272 ActiveAdmin(DeviceAdminInfo _info) {
273 info = _info;
274 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700275
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800276 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700277
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700278 public UserHandle getUserHandle() {
279 return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
280 }
281
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800282 void writeToXml(XmlSerializer out)
283 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800284 out.startTag(null, "policies");
285 info.writePoliciesToXml(out);
286 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800287 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
288 out.startTag(null, "password-quality");
289 out.attribute(null, "value", Integer.toString(passwordQuality));
290 out.endTag(null, "password-quality");
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700291 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800292 out.startTag(null, "min-password-length");
293 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700294 out.endTag(null, "min-password-length");
295 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700296 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700297 out.startTag(null, "password-history-length");
298 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
299 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800300 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700301 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700302 out.startTag(null, "min-password-uppercase");
303 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
304 out.endTag(null, "min-password-uppercase");
305 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700306 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700307 out.startTag(null, "min-password-lowercase");
308 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
309 out.endTag(null, "min-password-lowercase");
310 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700311 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700312 out.startTag(null, "min-password-letters");
313 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
314 out.endTag(null, "min-password-letters");
315 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700316 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700317 out.startTag(null, "min-password-numeric");
318 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
319 out.endTag(null, "min-password-numeric");
320 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700321 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700322 out.startTag(null, "min-password-symbols");
323 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
324 out.endTag(null, "min-password-symbols");
325 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700326 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700327 out.startTag(null, "min-password-nonletter");
328 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
329 out.endTag(null, "min-password-nonletter");
330 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800331 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700332 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800333 out.startTag(null, "max-time-to-unlock");
334 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
335 out.endTag(null, "max-time-to-unlock");
336 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700337 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800338 out.startTag(null, "max-failed-password-wipe");
339 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
340 out.endTag(null, "max-failed-password-wipe");
341 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700342 if (specifiesGlobalProxy) {
343 out.startTag(null, "specifies-global-proxy");
344 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
345 out.endTag(null, "specifies_global_proxy");
346 if (globalProxySpec != null) {
347 out.startTag(null, "global-proxy-spec");
348 out.attribute(null, "value", globalProxySpec);
349 out.endTag(null, "global-proxy-spec");
350 }
351 if (globalProxyExclusionList != null) {
352 out.startTag(null, "global-proxy-exclusion-list");
353 out.attribute(null, "value", globalProxyExclusionList);
354 out.endTag(null, "global-proxy-exclusion-list");
355 }
356 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700357 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800358 out.startTag(null, "password-expiration-timeout");
359 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
360 out.endTag(null, "password-expiration-timeout");
361 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700362 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800363 out.startTag(null, "password-expiration-date");
364 out.attribute(null, "value", Long.toString(passwordExpirationDate));
365 out.endTag(null, "password-expiration-date");
366 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800367 if (encryptionRequested) {
368 out.startTag(null, "encryption-requested");
369 out.attribute(null, "value", Boolean.toString(encryptionRequested));
370 out.endTag(null, "encryption-requested");
371 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700372 if (disableCamera) {
373 out.startTag(null, "disable-camera");
374 out.attribute(null, "value", Boolean.toString(disableCamera));
375 out.endTag(null, "disable-camera");
376 }
Jim Miller48b9b0d2012-09-19 23:16:50 -0700377 if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
378 out.startTag(null, "disable-keyguard-features");
379 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
380 out.endTag(null, "disable-keyguard-features");
Jim Millerb8ec4702012-08-31 17:19:10 -0700381 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800382 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700383
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800384 void readFromXml(XmlPullParser parser)
385 throws XmlPullParserException, IOException {
386 int outerDepth = parser.getDepth();
387 int type;
388 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
389 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
390 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
391 continue;
392 }
393 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800394 if ("policies".equals(tag)) {
395 info.readPoliciesFromXml(parser);
396 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800397 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800398 parser.getAttributeValue(null, "value"));
399 } else if ("min-password-length".equals(tag)) {
400 minimumPasswordLength = Integer.parseInt(
401 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700402 } else if ("password-history-length".equals(tag)) {
403 passwordHistoryLength = Integer.parseInt(
404 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700405 } else if ("min-password-uppercase".equals(tag)) {
406 minimumPasswordUpperCase = Integer.parseInt(
407 parser.getAttributeValue(null, "value"));
408 } else if ("min-password-lowercase".equals(tag)) {
409 minimumPasswordLowerCase = Integer.parseInt(
410 parser.getAttributeValue(null, "value"));
411 } else if ("min-password-letters".equals(tag)) {
412 minimumPasswordLetters = Integer.parseInt(
413 parser.getAttributeValue(null, "value"));
414 } else if ("min-password-numeric".equals(tag)) {
415 minimumPasswordNumeric = Integer.parseInt(
416 parser.getAttributeValue(null, "value"));
417 } else if ("min-password-symbols".equals(tag)) {
418 minimumPasswordSymbols = Integer.parseInt(
419 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700420 } else if ("min-password-nonletter".equals(tag)) {
421 minimumPasswordNonLetter = Integer.parseInt(
422 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800423 } else if ("max-time-to-unlock".equals(tag)) {
424 maximumTimeToUnlock = Long.parseLong(
425 parser.getAttributeValue(null, "value"));
426 } else if ("max-failed-password-wipe".equals(tag)) {
427 maximumFailedPasswordsForWipe = Integer.parseInt(
428 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700429 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800430 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700431 parser.getAttributeValue(null, "value"));
432 } else if ("global-proxy-spec".equals(tag)) {
433 globalProxySpec =
434 parser.getAttributeValue(null, "value");
435 } else if ("global-proxy-exclusion-list".equals(tag)) {
436 globalProxyExclusionList =
437 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800438 } else if ("password-expiration-timeout".equals(tag)) {
439 passwordExpirationTimeout = Long.parseLong(
440 parser.getAttributeValue(null, "value"));
441 } else if ("password-expiration-date".equals(tag)) {
442 passwordExpirationDate = Long.parseLong(
443 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800444 } else if ("encryption-requested".equals(tag)) {
445 encryptionRequested = Boolean.parseBoolean(
446 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700447 } else if ("disable-camera".equals(tag)) {
448 disableCamera = Boolean.parseBoolean(
449 parser.getAttributeValue(null, "value"));
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700450 } else if ("disable-keyguard-features".equals(tag)) {
451 disabledKeyguardFeatures = Integer.parseInt(
452 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800453 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700454 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800455 }
456 XmlUtils.skipCurrentTag(parser);
457 }
458 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700459
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800460 void dump(String prefix, PrintWriter pw) {
461 pw.print(prefix); pw.print("uid="); pw.println(getUid());
462 pw.print(prefix); pw.println("policies:");
463 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
464 if (pols != null) {
465 for (int i=0; i<pols.size(); i++) {
466 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
467 }
468 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700469 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700470 pw.println(Integer.toHexString(passwordQuality));
471 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800472 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700473 pw.print(prefix); pw.print("passwordHistoryLength=");
474 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700475 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
476 pw.println(minimumPasswordUpperCase);
477 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
478 pw.println(minimumPasswordLowerCase);
479 pw.print(prefix); pw.print("minimumPasswordLetters=");
480 pw.println(minimumPasswordLetters);
481 pw.print(prefix); pw.print("minimumPasswordNumeric=");
482 pw.println(minimumPasswordNumeric);
483 pw.print(prefix); pw.print("minimumPasswordSymbols=");
484 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700485 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
486 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800487 pw.print(prefix); pw.print("maximumTimeToUnlock=");
488 pw.println(maximumTimeToUnlock);
489 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
490 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700491 pw.print(prefix); pw.print("specifiesGlobalProxy=");
492 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800493 pw.print(prefix); pw.print("passwordExpirationTimeout=");
494 pw.println(passwordExpirationTimeout);
495 pw.print(prefix); pw.print("passwordExpirationDate=");
496 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700497 if (globalProxySpec != null) {
498 pw.print(prefix); pw.print("globalProxySpec=");
499 pw.println(globalProxySpec);
500 }
501 if (globalProxyExclusionList != null) {
502 pw.print(prefix); pw.print("globalProxyEclusionList=");
503 pw.println(globalProxyExclusionList);
504 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800505 pw.print(prefix); pw.print("encryptionRequested=");
506 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700507 pw.print(prefix); pw.print("disableCamera=");
508 pw.println(disableCamera);
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700509 pw.print(prefix); pw.print("disabledKeyguardFeatures=");
510 pw.println(disabledKeyguardFeatures);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800511 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800512 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700513
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700514 private void handlePackagesChanged(int userHandle) {
515 boolean removed = false;
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800516 if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700517 DevicePolicyData policy = getUserData(userHandle);
518 IPackageManager pm = AppGlobals.getPackageManager();
519 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
520 ActiveAdmin aa = policy.mAdminList.get(i);
521 try {
522 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
523 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
524 removed = true;
525 policy.mAdminList.remove(i);
Amith Yamasanif65c0a92013-11-11 11:44:37 -0800526 policy.mAdminMap.remove(aa.info.getComponent());
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800527 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700528 } catch (RemoteException re) {
529 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800530 }
531 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700532 if (removed) {
533 validatePasswordOwnerLocked(policy);
534 syncDeviceCapabilitiesLocked(policy);
535 saveSettingsLocked(policy.mUserHandle);
536 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800537 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700538
Dianne Hackbornd6847842010-01-12 18:14:19 -0800539 /**
540 * Instantiates the service.
541 */
542 public DevicePolicyManagerService(Context context) {
543 mContext = context;
Amith Yamasani44a01b72013-09-16 10:44:57 -0700544 mHasFeature = context.getPackageManager().hasSystemFeature(
545 PackageManager.FEATURE_DEVICE_ADMIN);
Dianne Hackborn42499172010-10-15 18:45:07 -0700546 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
547 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Amith Yamasani44a01b72013-09-16 10:44:57 -0700548 if (!mHasFeature) {
549 // Skip the rest of the initialization
550 return;
551 }
Jim Millera4e28d12010-11-08 16:15:47 -0800552 IntentFilter filter = new IntentFilter();
553 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
554 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700555 filter.addAction(Intent.ACTION_USER_REMOVED);
556 filter.addAction(Intent.ACTION_USER_STARTED);
Maggie Benthall0469f412013-09-05 15:30:26 -0400557 filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700558 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
559 filter = new IntentFilter();
560 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
561 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
562 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Amith Yamasani71e6c692013-03-24 17:39:28 -0700563 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700564 filter.addDataScheme("package");
565 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
566 }
567
568 /**
569 * Creates and loads the policy data from xml.
570 * @param userHandle the user for whom to load the policy data
571 * @return
572 */
573 DevicePolicyData getUserData(int userHandle) {
574 synchronized (this) {
575 DevicePolicyData policy = mUserData.get(userHandle);
576 if (policy == null) {
577 policy = new DevicePolicyData(userHandle);
578 mUserData.append(userHandle, policy);
579 loadSettingsLocked(policy, userHandle);
580 }
581 return policy;
582 }
583 }
584
585 void removeUserData(int userHandle) {
586 synchronized (this) {
587 if (userHandle == UserHandle.USER_OWNER) {
588 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
589 return;
590 }
591 DevicePolicyData policy = mUserData.get(userHandle);
592 if (policy != null) {
593 mUserData.remove(userHandle);
594 }
595 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
596 DEVICE_POLICIES_XML);
597 policyFile.delete();
598 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
599 }
Jim Millera4e28d12010-11-08 16:15:47 -0800600 }
601
Amith Yamasani71e6c692013-03-24 17:39:28 -0700602 void loadDeviceOwner() {
603 synchronized (this) {
604 if (DeviceOwner.isRegistered()) {
605 mDeviceOwner = new DeviceOwner();
606 }
607 }
608 }
609
Andy Stadler043116a2010-11-29 17:43:32 -0800610 /**
611 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
612 * reminders. Clears alarm if no expirations are configured.
613 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700614 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
615 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800616 final long now = System.currentTimeMillis();
617 final long timeToExpire = expiration - now;
618 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800619 if (expiration == 0) {
620 // No expirations are currently configured: Cancel alarm.
621 alarmTime = 0;
622 } else if (timeToExpire <= 0) {
623 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800624 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800625 } else {
626 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
627 // the expiration time.
628 long alarmInterval = timeToExpire % MS_PER_DAY;
629 if (alarmInterval == 0) {
630 alarmInterval = MS_PER_DAY;
631 }
632 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800633 }
634
Andy Stadler1f35d482010-11-19 15:39:41 -0800635 long token = Binder.clearCallingIdentity();
636 try {
637 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700638 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800639 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700640 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
641 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800642 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800643 if (alarmTime != 0) {
644 am.set(AlarmManager.RTC, alarmTime, pi);
645 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800646 } finally {
647 Binder.restoreCallingIdentity(token);
648 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800649 }
650
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800651 private IPowerManager getIPowerManager() {
652 if (mIPowerManager == null) {
653 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
654 mIPowerManager = IPowerManager.Stub.asInterface(b);
655 }
656 return mIPowerManager;
657 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700658
Jim Miller93c518e2012-01-17 15:55:31 -0800659 private IWindowManager getWindowManager() {
660 if (mIWindowManager == null) {
661 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
662 mIWindowManager = IWindowManager.Stub.asInterface(b);
663 }
664 return mIWindowManager;
665 }
666
Maggie Benthall0469f412013-09-05 15:30:26 -0400667 private NotificationManager getNotificationManager() {
668 if (mNotificationManager == null) {
669 mNotificationManager =
670 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
671 }
672 return mNotificationManager;
673 }
674
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700675 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
676 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800677 if (admin != null
678 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
679 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
680 return admin;
681 }
682 return null;
683 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700684
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800685 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
686 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800687 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700688 final int userHandle = UserHandle.getUserId(callingUid);
689 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800690 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700691 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800692 if (admin == null) {
693 throw new SecurityException("No active admin " + who);
694 }
695 if (admin.getUid() != callingUid) {
696 throw new SecurityException("Admin " + who + " is not owned by uid "
697 + Binder.getCallingUid());
698 }
699 if (!admin.info.usesPolicy(reqPolicy)) {
700 throw new SecurityException("Admin " + admin.info.getComponent()
701 + " did not specify uses-policy for: "
702 + admin.info.getTagForPolicy(reqPolicy));
703 }
704 return admin;
705 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700706 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800707 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700708 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800709 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
710 return admin;
711 }
712 }
713 throw new SecurityException("No active admin owned by uid "
714 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800715 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800716 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700717
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800718 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700719 sendAdminCommandLocked(admin, action, null);
720 }
721
722 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800723 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800724 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800725 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
726 intent.putExtra("expiration", admin.passwordExpirationDate);
727 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700728 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700729 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700730 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700731 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700732 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700733 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800734 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700735
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700736 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
737 final DevicePolicyData policy = getUserData(userHandle);
738 final int count = policy.mAdminList.size();
739 if (count > 0) {
740 for (int i = 0; i < count; i++) {
741 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800742 if (admin.info.usesPolicy(reqPolicy)) {
743 sendAdminCommandLocked(admin, action);
744 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800745 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800746 }
747 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700748
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700749 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
750 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800751 if (admin != null) {
752 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700753 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
754 new BroadcastReceiver() {
755 @Override
756 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700757 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700758 int userHandle = admin.getUserHandle().getIdentifier();
759 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700760 boolean doProxyCleanup = admin.info.usesPolicy(
761 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700762 policy.mAdminList.remove(admin);
763 policy.mAdminMap.remove(adminReceiver);
764 validatePasswordOwnerLocked(policy);
765 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700766 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700767 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700768 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700769 saveSettingsLocked(userHandle);
770 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700771 }
772 }
773 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800774 }
775 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700776
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700777 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -0700778 if (!mHasFeature) {
779 return null;
780 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700781 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800782 Intent resolveIntent = new Intent();
783 resolveIntent.setComponent(adminName);
784 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani71e6c692013-03-24 17:39:28 -0700785 resolveIntent,
786 PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
787 userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800788 if (infos == null || infos.size() <= 0) {
789 throw new IllegalArgumentException("Unknown admin: " + adminName);
790 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700791
Dianne Hackbornd6847842010-01-12 18:14:19 -0800792 try {
793 return new DeviceAdminInfo(mContext, infos.get(0));
794 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700795 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800796 return null;
797 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700798 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800799 return null;
800 }
801 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700802
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700803 private static JournaledFile makeJournaledFile(int userHandle) {
804 final String base = userHandle == 0
805 ? "/data/system/" + DEVICE_POLICIES_XML
806 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
807 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800808 return new JournaledFile(new File(base), new File(base + ".tmp"));
809 }
810
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700811 private void saveSettingsLocked(int userHandle) {
812 DevicePolicyData policy = getUserData(userHandle);
813 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800814 FileOutputStream stream = null;
815 try {
816 stream = new FileOutputStream(journal.chooseForWrite(), false);
817 XmlSerializer out = new FastXmlSerializer();
818 out.setOutput(stream, "utf-8");
819 out.startDocument(null, true);
820
821 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700822
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700823 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800824 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700825 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800826 if (ap != null) {
827 out.startTag(null, "admin");
828 out.attribute(null, "name", ap.info.getComponent().flattenToString());
829 ap.writeToXml(out);
830 out.endTag(null, "admin");
831 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800832 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700833
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700834 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800835 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700836 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800837 out.endTag(null, "password-owner");
838 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700839
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700840 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800841 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700842 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800843 out.endTag(null, "failed-password-attempts");
844 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700845
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700846 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
847 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
848 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
849 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700850 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700851 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
852 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
853 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
854 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
855 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700856 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700857 .toString(policy.mActivePasswordNumeric));
858 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
859 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700860 out.endTag(null, "active-password");
861 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700862
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700863 out.endTag(null, "policies");
864
Dianne Hackbornd6847842010-01-12 18:14:19 -0800865 out.endDocument();
866 stream.close();
867 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700868 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800869 } catch (IOException e) {
870 try {
871 if (stream != null) {
872 stream.close();
873 }
874 } catch (IOException ex) {
875 // Ignore
876 }
877 journal.rollback();
878 }
879 }
880
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700881 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700882 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
883 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700884 long ident = Binder.clearCallingIdentity();
885 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700886 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700887 } finally {
888 Binder.restoreCallingIdentity(ident);
889 }
Jim Miller284b62e2010-06-08 14:27:42 -0700890 }
891
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700892 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
893 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800894 FileInputStream stream = null;
895 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800896 try {
897 stream = new FileInputStream(file);
898 XmlPullParser parser = Xml.newPullParser();
899 parser.setInput(stream, null);
900
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800901 int type;
902 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
903 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800904 }
905 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800906 if (!"policies".equals(tag)) {
907 throw new XmlPullParserException(
908 "Settings do not start with policies tag: found " + tag);
909 }
910 type = parser.next();
911 int outerDepth = parser.getDepth();
912 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
913 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
914 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
915 continue;
916 }
917 tag = parser.getName();
918 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800919 String name = parser.getAttributeValue(null, "name");
920 try {
921 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700922 ComponentName.unflattenFromString(name), userHandle);
923 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
924 != userHandle)) {
925 Slog.w(TAG, "findAdmin returned an incorrect uid "
926 + dai.getActivityInfo().applicationInfo.uid + " for user "
927 + userHandle);
928 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800929 if (dai != null) {
930 ActiveAdmin ap = new ActiveAdmin(dai);
931 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700932 policy.mAdminMap.put(ap.info.getComponent(), ap);
933 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800934 }
935 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700936 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800937 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800938 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700939 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800940 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800941 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800942 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700943 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800944 parser.getAttributeValue(null, "value"));
945 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700946 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700947 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700948 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700949 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700950 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700951 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700952 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700953 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700954 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700955 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700956 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700957 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700958 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700959 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700960 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700961 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700962 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700963 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800964 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700965 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800966 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800967 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800968 }
969 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700970 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800971 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700972 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800973 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700974 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700975 } catch (FileNotFoundException e) {
976 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800977 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700978 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800979 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700980 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800981 }
982 try {
983 if (stream != null) {
984 stream.close();
985 }
986 } catch (IOException e) {
987 // Ignore
988 }
989
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700990 // Validate that what we stored for the password quality matches
991 // sufficiently what is currently set. Note that this is only
992 // a sanity check in case the two get out of sync; this should
993 // never normally happen.
994 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700995 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700996 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700997 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700998 + " does not match actual quality 0x"
999 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001000 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
1001 policy.mActivePasswordLength = 0;
1002 policy.mActivePasswordUpperCase = 0;
1003 policy.mActivePasswordLowerCase = 0;
1004 policy.mActivePasswordLetters = 0;
1005 policy.mActivePasswordNumeric = 0;
1006 policy.mActivePasswordSymbols = 0;
1007 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001008 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001009
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001010 validatePasswordOwnerLocked(policy);
1011 syncDeviceCapabilitiesLocked(policy);
1012 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001013 }
1014
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001015 static void validateQualityConstant(int quality) {
1016 switch (quality) {
1017 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -05001018 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001019 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
1020 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
1021 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
1022 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001023 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001024 return;
1025 }
1026 throw new IllegalArgumentException("Invalid quality constant: 0x"
1027 + Integer.toHexString(quality));
1028 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001029
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001030 void validatePasswordOwnerLocked(DevicePolicyData policy) {
1031 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001032 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001033 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
1034 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001035 haveOwner = true;
1036 break;
1037 }
1038 }
1039 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001040 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001041 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001042 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001043 }
1044 }
1045 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001046
Ben Komalo2447edd2011-05-09 16:05:33 -07001047 /**
1048 * Pushes down policy information to the system for any policies related to general device
1049 * capabilities that need to be enforced by lower level services (e.g. Camera services).
1050 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001051 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -07001052 // Ensure the status of the camera is synced down to the system. Interested native services
1053 // should monitor this value and act accordingly.
1054 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001055 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07001056 if (cameraDisabled != systemState) {
1057 long token = Binder.clearCallingIdentity();
1058 try {
1059 String value = cameraDisabled ? "1" : "0";
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001060 if (DBG) Slog.v(TAG, "Change in camera state ["
Ben Komalo2447edd2011-05-09 16:05:33 -07001061 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
1062 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
1063 } finally {
1064 Binder.restoreCallingIdentity(token);
1065 }
1066 }
1067 }
1068
Dianne Hackbornd6847842010-01-12 18:14:19 -08001069 public void systemReady() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001070 if (!mHasFeature) {
1071 return;
1072 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001073 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001074 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001075 loadDeviceOwner();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001076 }
1077 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001078
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001079 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -08001080 synchronized (this) {
1081 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001082 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001083 if (N <= 0) {
1084 return;
1085 }
1086 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001087 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001088 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1089 && admin.passwordExpirationTimeout > 0L
1090 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001091 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001092 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1093 }
1094 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001095 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001096 }
1097 }
1098
Maggie Benthall0469f412013-09-05 15:30:26 -04001099 private void manageMonitoringCertificateNotification(Intent intent) {
1100 final NotificationManager notificationManager = getNotificationManager();
1101
1102 final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
1103 if (! hasCert) {
1104 if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
1105 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1106 for (UserInfo user : um.getUsers()) {
1107 notificationManager.cancelAsUser(
1108 null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
1109 }
1110 }
1111 return;
1112 }
1113 final boolean isManaged = getDeviceOwner() != null;
1114 int smallIconId;
1115 String contentText;
1116 if (isManaged) {
1117 contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
1118 getDeviceOwnerName());
1119 smallIconId = R.drawable.stat_sys_certificate_info;
1120 } else {
1121 contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
1122 smallIconId = android.R.drawable.stat_sys_warning;
1123 }
1124
1125 Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
1126 dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1127 dialogIntent.setPackage("com.android.settings");
1128 // Notification will be sent individually to all users. The activity should start as
1129 // whichever user is current when it starts.
1130 PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
1131 PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
1132
1133 Notification noti = new Notification.Builder(mContext)
1134 .setSmallIcon(smallIconId)
1135 .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
1136 .setContentText(contentText)
1137 .setContentIntent(notifyIntent)
1138 .setPriority(Notification.PRIORITY_HIGH)
1139 .setShowWhen(false)
1140 .build();
1141
1142 // If this is a boot intent, this will fire for each user. But if this is a storage changed
1143 // intent, it will fire once, so we need to notify all users.
1144 if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
1145 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1146 for (UserInfo user : um.getUsers()) {
1147 notificationManager.notifyAsUser(
1148 null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
1149 }
1150 } else {
1151 notificationManager.notifyAsUser(
1152 null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
1153 }
1154 }
1155
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001156 /**
1157 * @param adminReceiver The admin to add
1158 * @param refreshing true = update an active admin, no error
1159 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001160 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001161 if (!mHasFeature) {
1162 return;
1163 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001164 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001165 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001166 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001167
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001168 DevicePolicyData policy = getUserData(userHandle);
1169 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001170 if (info == null) {
1171 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1172 }
1173 synchronized (this) {
1174 long ident = Binder.clearCallingIdentity();
1175 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001176 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001177 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001178 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001179 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001180 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001181 int replaceIndex = -1;
1182 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001183 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001184 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001185 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001186 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1187 replaceIndex = i;
1188 break;
1189 }
1190 }
1191 }
1192 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001193 policy.mAdminList.add(newAdmin);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001194 enableIfNecessary(info.getPackageName(), userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001195 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001196 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001197 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001198 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001199 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001200 } finally {
1201 Binder.restoreCallingIdentity(ident);
1202 }
1203 }
1204 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001205
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001206 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001207 if (!mHasFeature) {
1208 return false;
1209 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001210 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001211 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001212 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001213 }
1214 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001215
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001216 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001217 if (!mHasFeature) {
1218 return false;
1219 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001220 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001221 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001222 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001223 if (administrator == null) {
1224 throw new SecurityException("No active admin " + adminReceiver);
1225 }
1226 return administrator.info.usesPolicy(policyId);
1227 }
1228 }
1229
Amith Yamasani44a01b72013-09-16 10:44:57 -07001230 @SuppressWarnings("unchecked")
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001231 public List<ComponentName> getActiveAdmins(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001232 if (!mHasFeature) {
1233 return Collections.EMPTY_LIST;
1234 }
1235
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001236 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001237 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001238 DevicePolicyData policy = getUserData(userHandle);
1239 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001240 if (N <= 0) {
1241 return null;
1242 }
1243 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1244 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001245 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001246 }
1247 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001248 }
1249 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001250
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001251 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001252 if (!mHasFeature) {
1253 return false;
1254 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001255 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001256 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001257 DevicePolicyData policy = getUserData(userHandle);
1258 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001259 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001260 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001261 return true;
1262 }
1263 }
1264 return false;
1265 }
1266 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001267
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001268 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001269 if (!mHasFeature) {
1270 return;
1271 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001272 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001273 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001274 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001275 if (admin == null) {
1276 return;
1277 }
1278 if (admin.getUid() != Binder.getCallingUid()) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07001279 // If trying to remove device owner, refuse when the caller is not the owner.
1280 if (mDeviceOwner != null
1281 && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
1282 return;
1283 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001284 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001285 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001286 }
1287 long ident = Binder.clearCallingIdentity();
1288 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001289 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001290 } finally {
1291 Binder.restoreCallingIdentity(ident);
1292 }
1293 }
1294 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001295
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001296 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001297 if (!mHasFeature) {
1298 return;
1299 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001300 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001301 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001302
Dianne Hackbornd6847842010-01-12 18:14:19 -08001303 synchronized (this) {
1304 if (who == null) {
1305 throw new NullPointerException("ComponentName is null");
1306 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001307 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1308 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001309 if (ap.passwordQuality != quality) {
1310 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001311 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001312 }
1313 }
1314 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001315
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001316 public int getPasswordQuality(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001317 if (!mHasFeature) {
1318 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
1319 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001320 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001321 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001322 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001323 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001324
Dianne Hackborn254cb442010-01-27 19:23:59 -08001325 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001326 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001327 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001328 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001329
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001330 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001331 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001332 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001333 if (mode < admin.passwordQuality) {
1334 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001335 }
1336 }
1337 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001338 }
1339 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001340
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001341 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001342 if (!mHasFeature) {
1343 return;
1344 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001345 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001346 synchronized (this) {
1347 if (who == null) {
1348 throw new NullPointerException("ComponentName is null");
1349 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001350 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1351 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001352 if (ap.minimumPasswordLength != length) {
1353 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001354 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001355 }
1356 }
1357 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001358
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001359 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001360 if (!mHasFeature) {
1361 return 0;
1362 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001363 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001364 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001365 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001366 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001367
Dianne Hackborn254cb442010-01-27 19:23:59 -08001368 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001369 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001370 return admin != null ? admin.minimumPasswordLength : length;
1371 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001372
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001373 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001374 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001375 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001376 if (length < admin.minimumPasswordLength) {
1377 length = admin.minimumPasswordLength;
1378 }
1379 }
1380 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001381 }
1382 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001383
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001384 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001385 if (!mHasFeature) {
1386 return;
1387 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001388 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001389 synchronized (this) {
1390 if (who == null) {
1391 throw new NullPointerException("ComponentName is null");
1392 }
1393 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1394 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1395 if (ap.passwordHistoryLength != length) {
1396 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001397 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001398 }
1399 }
1400 }
1401
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001402 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001403 if (!mHasFeature) {
1404 return 0;
1405 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001406 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001407 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001408 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001409 int length = 0;
1410
1411 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001412 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001413 return admin != null ? admin.passwordHistoryLength : length;
1414 }
1415
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001416 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001417 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001418 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001419 if (length < admin.passwordHistoryLength) {
1420 length = admin.passwordHistoryLength;
1421 }
1422 }
1423 return length;
1424 }
1425 }
1426
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001427 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001428 if (!mHasFeature) {
1429 return;
1430 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001431 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001432 synchronized (this) {
1433 if (who == null) {
1434 throw new NullPointerException("ComponentName is null");
1435 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001436 if (timeout < 0) {
1437 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001438 }
1439 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1440 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1441 // Calling this API automatically bumps the expiration date
1442 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1443 ap.passwordExpirationDate = expiration;
1444 ap.passwordExpirationTimeout = timeout;
1445 if (timeout > 0L) {
1446 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1447 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1448 .format(new Date(expiration)));
1449 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001450 saveSettingsLocked(userHandle);
1451 // in case this is the first one
1452 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001453 }
1454 }
1455
Andy Stadler043116a2010-11-29 17:43:32 -08001456 /**
1457 * Return a single admin's expiration cycle time, or the min of all cycle times.
1458 * Returns 0 if not configured.
1459 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001460 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001461 if (!mHasFeature) {
1462 return 0L;
1463 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001464 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001465 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001466 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001467 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001468 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001469 }
1470
Andy Stadler043116a2010-11-29 17:43:32 -08001471 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001472 DevicePolicyData policy = getUserData(userHandle);
1473 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001474 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001475 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001476 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1477 && timeout > admin.passwordExpirationTimeout)) {
1478 timeout = admin.passwordExpirationTimeout;
1479 }
1480 }
1481 return timeout;
1482 }
1483 }
1484
Andy Stadler043116a2010-11-29 17:43:32 -08001485 /**
1486 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1487 * Returns 0 if not configured.
1488 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001489 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001490 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001491 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001492 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001493 }
1494
Andy Stadler043116a2010-11-29 17:43:32 -08001495 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001496 DevicePolicyData policy = getUserData(userHandle);
1497 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001498 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001499 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001500 if (timeout == 0L || (admin.passwordExpirationDate != 0
1501 && timeout > admin.passwordExpirationDate)) {
1502 timeout = admin.passwordExpirationDate;
1503 }
1504 }
1505 return timeout;
1506 }
1507
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001508 public long getPasswordExpiration(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001509 if (!mHasFeature) {
1510 return 0L;
1511 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001512 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001513 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001514 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001515 }
1516 }
1517
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001518 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001519 if (!mHasFeature) {
1520 return;
1521 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001522 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001523 synchronized (this) {
1524 if (who == null) {
1525 throw new NullPointerException("ComponentName is null");
1526 }
1527 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1528 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1529 if (ap.minimumPasswordUpperCase != length) {
1530 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001531 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001532 }
1533 }
1534 }
1535
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001536 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001537 if (!mHasFeature) {
1538 return 0;
1539 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001540 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.minimumPasswordUpperCase : 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.minimumPasswordUpperCase) {
1554 length = admin.minimumPasswordUpperCase;
1555 }
1556 }
1557 return length;
1558 }
1559 }
1560
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001561 public void setPasswordMinimumLowerCase(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.minimumPasswordLowerCase != length) {
1570 ap.minimumPasswordLowerCase = 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 getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001577 if (!mHasFeature) {
1578 return 0;
1579 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001580 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001581 synchronized (this) {
1582 int length = 0;
1583
1584 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001585 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001586 return admin != null ? admin.minimumPasswordLowerCase : length;
1587 }
1588
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001589 DevicePolicyData policy = getUserData(userHandle);
1590 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001591 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001592 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001593 if (length < admin.minimumPasswordLowerCase) {
1594 length = admin.minimumPasswordLowerCase;
1595 }
1596 }
1597 return length;
1598 }
1599 }
1600
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001601 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001602 if (!mHasFeature) {
1603 return;
1604 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001605 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001606 synchronized (this) {
1607 if (who == null) {
1608 throw new NullPointerException("ComponentName is null");
1609 }
1610 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1611 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1612 if (ap.minimumPasswordLetters != length) {
1613 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001614 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001615 }
1616 }
1617 }
1618
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001619 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001620 if (!mHasFeature) {
1621 return 0;
1622 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001623 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001624 synchronized (this) {
1625 int length = 0;
1626
1627 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001628 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001629 return admin != null ? admin.minimumPasswordLetters : length;
1630 }
1631
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001632 DevicePolicyData policy = getUserData(userHandle);
1633 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001634 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001635 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001636 if (length < admin.minimumPasswordLetters) {
1637 length = admin.minimumPasswordLetters;
1638 }
1639 }
1640 return length;
1641 }
1642 }
1643
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001644 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001645 if (!mHasFeature) {
1646 return;
1647 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001648 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001649 synchronized (this) {
1650 if (who == null) {
1651 throw new NullPointerException("ComponentName is null");
1652 }
1653 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1654 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1655 if (ap.minimumPasswordNumeric != length) {
1656 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001657 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001658 }
1659 }
1660 }
1661
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001662 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001663 if (!mHasFeature) {
1664 return 0;
1665 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001666 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001667 synchronized (this) {
1668 int length = 0;
1669
1670 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001671 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001672 return admin != null ? admin.minimumPasswordNumeric : length;
1673 }
1674
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001675 DevicePolicyData policy = getUserData(userHandle);
1676 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001677 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001678 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001679 if (length < admin.minimumPasswordNumeric) {
1680 length = admin.minimumPasswordNumeric;
1681 }
1682 }
1683 return length;
1684 }
1685 }
1686
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001687 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001688 if (!mHasFeature) {
1689 return;
1690 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001691 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001692 synchronized (this) {
1693 if (who == null) {
1694 throw new NullPointerException("ComponentName is null");
1695 }
1696 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1697 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1698 if (ap.minimumPasswordSymbols != length) {
1699 ap.minimumPasswordSymbols = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001700 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001701 }
1702 }
1703 }
1704
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001705 public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001706 if (!mHasFeature) {
1707 return 0;
1708 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001709 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001710 synchronized (this) {
1711 int length = 0;
1712
1713 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001714 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001715 return admin != null ? admin.minimumPasswordSymbols : length;
1716 }
1717
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001718 DevicePolicyData policy = getUserData(userHandle);
1719 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001720 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001721 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001722 if (length < admin.minimumPasswordSymbols) {
1723 length = admin.minimumPasswordSymbols;
1724 }
1725 }
1726 return length;
1727 }
1728 }
1729
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001730 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001731 if (!mHasFeature) {
1732 return;
1733 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001734 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001735 synchronized (this) {
1736 if (who == null) {
1737 throw new NullPointerException("ComponentName is null");
1738 }
1739 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1740 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1741 if (ap.minimumPasswordNonLetter != length) {
1742 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001743 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001744 }
1745 }
1746 }
1747
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001748 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001749 if (!mHasFeature) {
1750 return 0;
1751 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001752 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001753 synchronized (this) {
1754 int length = 0;
1755
1756 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001757 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001758 return admin != null ? admin.minimumPasswordNonLetter : length;
1759 }
1760
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001761 DevicePolicyData policy = getUserData(userHandle);
1762 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001763 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001764 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001765 if (length < admin.minimumPasswordNonLetter) {
1766 length = admin.minimumPasswordNonLetter;
1767 }
1768 }
1769 return length;
1770 }
1771 }
1772
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001773 public boolean isActivePasswordSufficient(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001774 if (!mHasFeature) {
1775 return true;
1776 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001777 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001778 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001779 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001780 // This API can only be called by an active device admin,
1781 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001782 getActiveAdminForCallerLocked(null,
1783 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001784 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1785 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001786 return false;
1787 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001788 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001789 return true;
1790 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001791 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1792 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1793 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1794 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1795 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1796 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001797 }
1798 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001799
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001800 public int getCurrentFailedPasswordAttempts(int userHandle) {
1801 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001802 synchronized (this) {
1803 // This API can only be called by an active device admin,
1804 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001805 getActiveAdminForCallerLocked(null,
1806 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001807 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001808 }
1809 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001810
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001811 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001812 if (!mHasFeature) {
1813 return;
1814 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001815 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001816 synchronized (this) {
1817 // This API can only be called by an active device admin,
1818 // so try to retrieve it to check that the caller is one.
1819 getActiveAdminForCallerLocked(who,
1820 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1821 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1822 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1823 if (ap.maximumFailedPasswordsForWipe != num) {
1824 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001825 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001826 }
1827 }
1828 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001829
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001830 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001831 if (!mHasFeature) {
1832 return 0;
1833 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001834 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001835 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001836 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001837 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001838
Dianne Hackborn254cb442010-01-27 19:23:59 -08001839 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001840 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001841 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1842 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001843
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001844 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001845 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001846 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001847 if (count == 0) {
1848 count = admin.maximumFailedPasswordsForWipe;
1849 } else if (admin.maximumFailedPasswordsForWipe != 0
1850 && count > admin.maximumFailedPasswordsForWipe) {
1851 count = admin.maximumFailedPasswordsForWipe;
1852 }
1853 }
1854 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001855 }
1856 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001857
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001858 public boolean resetPassword(String password, int flags, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001859 if (!mHasFeature) {
1860 return false;
1861 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001862 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001863 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001864 synchronized (this) {
1865 // This API can only be called by an active device admin,
1866 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001867 getActiveAdminForCallerLocked(null,
1868 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001869 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001870 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001871 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001872 if (realQuality < quality
1873 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001874 Slog.w(TAG, "resetPassword: password quality 0x"
joonyoung.choad83c192013-04-18 13:51:08 +09001875 + Integer.toHexString(realQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001876 + " does not meet required quality 0x"
1877 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001878 return false;
1879 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001880 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001881 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001882 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001883 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001884 Slog.w(TAG, "resetPassword: password length " + password.length()
1885 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001886 return false;
1887 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001888 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1889 int letters = 0;
1890 int uppercase = 0;
1891 int lowercase = 0;
1892 int numbers = 0;
1893 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001894 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001895 for (int i = 0; i < password.length(); i++) {
1896 char c = password.charAt(i);
1897 if (c >= 'A' && c <= 'Z') {
1898 letters++;
1899 uppercase++;
1900 } else if (c >= 'a' && c <= 'z') {
1901 letters++;
1902 lowercase++;
1903 } else if (c >= '0' && c <= '9') {
1904 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001905 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001906 } else {
1907 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001908 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001909 }
1910 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001911 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001912 if(letters < neededLetters) {
1913 Slog.w(TAG, "resetPassword: number of letters " + letters
1914 + " does not meet required number of letters " + neededLetters);
1915 return false;
1916 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001917 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001918 if (numbers < neededNumbers) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001919 Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
1920 + " does not meet required number of numerical digits "
1921 + neededNumbers);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001922 return false;
1923 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001924 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001925 if (lowercase < neededLowerCase) {
1926 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1927 + " does not meet required number of lowercase letters "
1928 + neededLowerCase);
1929 return false;
1930 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001931 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001932 if (uppercase < neededUpperCase) {
1933 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1934 + " does not meet required number of uppercase letters "
1935 + neededUpperCase);
1936 return false;
1937 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001938 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001939 if (symbols < neededSymbols) {
1940 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1941 + " does not meet required number of special symbols " + neededSymbols);
1942 return false;
1943 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001944 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001945 if (nonletter < neededNonLetter) {
1946 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1947 + " does not meet required number of non-letter characters "
1948 + neededNonLetter);
1949 return false;
1950 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001951 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001952 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001953
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001954 int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001955 DevicePolicyData policy = getUserData(userHandle);
1956 if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001957 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001958 return false;
1959 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001960
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001961 // Don't do this with the lock held, because it is going to call
1962 // back in to the service.
1963 long ident = Binder.clearCallingIdentity();
1964 try {
1965 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001966 utils.saveLockPassword(password, quality, false, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001967 synchronized (this) {
1968 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1969 != 0 ? callingUid : -1;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001970 if (policy.mPasswordOwner != newOwner) {
1971 policy.mPasswordOwner = newOwner;
1972 saveSettingsLocked(userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001973 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001974 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001975 } finally {
1976 Binder.restoreCallingIdentity(ident);
1977 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001978
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001979 return true;
1980 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001981
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001982 public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001983 if (!mHasFeature) {
1984 return;
1985 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001986 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001987 synchronized (this) {
1988 if (who == null) {
1989 throw new NullPointerException("ComponentName is null");
1990 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001991 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001992 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001993 if (ap.maximumTimeToUnlock != timeMs) {
1994 ap.maximumTimeToUnlock = timeMs;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001995 saveSettingsLocked(userHandle);
1996 updateMaximumTimeToLockLocked(getUserData(userHandle));
Dianne Hackbornd6847842010-01-12 18:14:19 -08001997 }
1998 }
1999 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002000
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002001 void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
2002 long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
2003 if (policy.mLastMaximumTimeToLock == timeMs) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002004 return;
2005 }
2006
2007 long ident = Binder.clearCallingIdentity();
2008 try {
2009 if (timeMs <= 0) {
2010 timeMs = Integer.MAX_VALUE;
2011 } else {
2012 // Make sure KEEP_SCREEN_ON is disabled, since that
2013 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07002014 Settings.Global.putInt(mContext.getContentResolver(),
2015 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002016 }
2017
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002018 policy.mLastMaximumTimeToLock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002019
2020 try {
Jeff Brown96307042012-07-27 15:51:34 -07002021 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002022 } catch (RemoteException e) {
2023 Slog.w(TAG, "Failure talking with power manager", e);
2024 }
2025 } finally {
2026 Binder.restoreCallingIdentity(ident);
2027 }
2028 }
2029
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002030 public long getMaximumTimeToLock(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002031 if (!mHasFeature) {
2032 return 0;
2033 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002034 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002035 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08002036 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002037
Dianne Hackborn254cb442010-01-27 19:23:59 -08002038 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002039 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08002040 return admin != null ? admin.maximumTimeToUnlock : time;
2041 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002042
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002043 DevicePolicyData policy = getUserData(userHandle);
2044 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08002045 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002046 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08002047 if (time == 0) {
2048 time = admin.maximumTimeToUnlock;
2049 } else if (admin.maximumTimeToUnlock != 0
2050 && time > admin.maximumTimeToUnlock) {
2051 time = admin.maximumTimeToUnlock;
2052 }
2053 }
2054 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08002055 }
2056 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002057
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002058 public void lockNow() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002059 if (!mHasFeature) {
2060 return;
2061 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002062 synchronized (this) {
2063 // This API can only be called by an active device admin,
2064 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08002065 getActiveAdminForCallerLocked(null,
2066 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002067 lockNowUnchecked();
2068 }
2069 }
2070
2071 private void lockNowUnchecked() {
2072 long ident = Binder.clearCallingIdentity();
2073 try {
2074 // Power off the display
2075 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
2076 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
2077 // Ensure the device is locked
Adam Cohenf7522022012-10-03 20:03:18 -07002078 getWindowManager().lockNow(null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002079 } catch (RemoteException e) {
2080 } finally {
2081 Binder.restoreCallingIdentity(ident);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002082 }
2083 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002084
Ben Komaloed48c8b2011-10-17 17:30:21 -07002085 private boolean isExtStorageEncrypted() {
2086 String state = SystemProperties.get("vold.decrypt");
2087 return !"".equals(state);
2088 }
2089
Maggie Benthallda51e682013-08-08 22:35:44 -04002090 public boolean installCaCert(byte[] certBuffer) throws RemoteException {
2091 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
2092 KeyChainConnection keyChainConnection = null;
2093 byte[] pemCert;
2094 try {
2095 X509Certificate cert = parseCert(certBuffer);
2096 pemCert = Credentials.convertToPem(cert);
2097 } catch (CertificateException ce) {
2098 Log.e(TAG, "Problem converting cert", ce);
2099 return false;
2100 } catch (IOException ioe) {
2101 Log.e(TAG, "Problem reading cert", ioe);
2102 return false;
2103 }
2104 try {
2105 keyChainConnection = KeyChain.bind(mContext);
2106 try {
2107 keyChainConnection.getService().installCaCertificate(pemCert);
2108 return true;
2109 } finally {
2110 if (keyChainConnection != null) {
2111 keyChainConnection.close();
2112 keyChainConnection = null;
2113 }
2114 }
2115 } catch (InterruptedException e1) {
2116 Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
2117 Thread.currentThread().interrupt();
2118 }
2119 return false;
2120 }
2121
2122 private static X509Certificate parseCert(byte[] certBuffer)
2123 throws CertificateException, IOException {
2124 CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
2125 return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
2126 certBuffer));
2127 }
2128
2129 public void uninstallCaCert(final byte[] certBuffer) {
2130 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
2131 TrustedCertificateStore certStore = new TrustedCertificateStore();
2132 String alias = null;
2133 try {
2134 X509Certificate cert = parseCert(certBuffer);
2135 alias = certStore.getCertificateAlias(cert);
2136 } catch (CertificateException ce) {
2137 Log.e(TAG, "Problem creating X509Certificate", ce);
2138 return;
2139 } catch (IOException ioe) {
2140 Log.e(TAG, "Problem reading certificate", ioe);
2141 return;
2142 }
2143 try {
2144 KeyChainConnection keyChainConnection = KeyChain.bind(mContext);
2145 IKeyChainService service = keyChainConnection.getService();
2146 try {
2147 service.deleteCaCertificate(alias);
2148 } catch (RemoteException e) {
2149 Log.e(TAG, "from CaCertUninstaller: ", e);
2150 } finally {
2151 keyChainConnection.close();
2152 keyChainConnection = null;
2153 }
2154 } catch (InterruptedException ie) {
2155 Log.w(TAG, "CaCertUninstaller: ", ie);
2156 Thread.currentThread().interrupt();
2157 }
2158 }
2159
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002160 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07002161 // If the SD card is encrypted and non-removable, we have to force a wipe.
2162 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
2163 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
2164
2165 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
2166 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07002167 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09002168 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07002169 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
2170 mWakeLock.acquire(10000);
2171 mContext.startService(intent);
2172 } else {
2173 try {
2174 RecoverySystem.rebootWipeUserData(mContext);
2175 } catch (IOException e) {
2176 Slog.w(TAG, "Failed requesting data wipe", e);
2177 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002178 }
2179 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002180
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002181 public void wipeData(int flags, final int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002182 if (!mHasFeature) {
2183 return;
2184 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002185 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002186 synchronized (this) {
2187 // This API can only be called by an active device admin,
2188 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08002189 getActiveAdminForCallerLocked(null,
2190 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002191 long ident = Binder.clearCallingIdentity();
2192 try {
Amith Yamasani32f07422012-11-16 15:09:13 -08002193 wipeDeviceOrUserLocked(flags, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002194 } finally {
2195 Binder.restoreCallingIdentity(ident);
2196 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002197 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002198 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002199
Amith Yamasani32f07422012-11-16 15:09:13 -08002200 private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
2201 if (userHandle == UserHandle.USER_OWNER) {
2202 wipeDataLocked(flags);
2203 } else {
2204 lockNowUnchecked();
2205 mHandler.post(new Runnable() {
2206 public void run() {
2207 try {
Amith Yamasanie4cf7342012-12-17 11:12:09 -08002208 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
Amith Yamasani32f07422012-11-16 15:09:13 -08002209 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
2210 .removeUser(userHandle);
2211 } catch (RemoteException re) {
2212 // Shouldn't happen
2213 }
2214 }
2215 });
2216 }
2217 }
2218
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002219 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002220 if (!mHasFeature) {
2221 return;
2222 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002223 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002224 mContext.enforceCallingOrSelfPermission(
2225 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002226
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002227 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002228 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002229 if (admin == null) {
2230 try {
2231 result.sendResult(null);
2232 } catch (RemoteException e) {
2233 }
2234 return;
2235 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002236 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002237 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002238 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002239 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002240 @Override
2241 public void onReceive(Context context, Intent intent) {
2242 try {
2243 result.sendResult(getResultExtras(false));
2244 } catch (RemoteException e) {
2245 }
2246 }
2247 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002248 }
2249 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002250
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002251 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002252 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002253 if (!mHasFeature) {
2254 return;
2255 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002256 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002257 mContext.enforceCallingOrSelfPermission(
2258 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002259 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002260
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002261 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002262
Dianne Hackbornd6847842010-01-12 18:14:19 -08002263 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002264 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
2265 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
2266 || p.mActivePasswordUpperCase != uppercase
2267 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
2268 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002269 long ident = Binder.clearCallingIdentity();
2270 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002271 p.mActivePasswordQuality = quality;
2272 p.mActivePasswordLength = length;
2273 p.mActivePasswordLetters = letters;
2274 p.mActivePasswordLowerCase = lowercase;
2275 p.mActivePasswordUpperCase = uppercase;
2276 p.mActivePasswordNumeric = numbers;
2277 p.mActivePasswordSymbols = symbols;
2278 p.mActivePasswordNonLetter = nonletter;
2279 p.mFailedPasswordAttempts = 0;
2280 saveSettingsLocked(userHandle);
2281 updatePasswordExpirationsLocked(userHandle);
2282 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002283 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002284 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002285 } finally {
2286 Binder.restoreCallingIdentity(ident);
2287 }
2288 }
2289 }
2290 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002291
Andy Stadler043116a2010-11-29 17:43:32 -08002292 /**
2293 * Called any time the device password is updated. Resets all password expiration clocks.
2294 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002295 private void updatePasswordExpirationsLocked(int userHandle) {
2296 DevicePolicyData policy = getUserData(userHandle);
2297 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08002298 if (N > 0) {
2299 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002300 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08002301 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08002302 long timeout = admin.passwordExpirationTimeout;
2303 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
2304 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08002305 }
2306 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002307 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08002308 }
2309 }
2310
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002311 public void reportFailedPasswordAttempt(int userHandle) {
2312 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002313 mContext.enforceCallingOrSelfPermission(
2314 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002315
Dianne Hackbornd6847842010-01-12 18:14:19 -08002316 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002317 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002318 long ident = Binder.clearCallingIdentity();
2319 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002320 policy.mFailedPasswordAttempts++;
2321 saveSettingsLocked(userHandle);
Amith Yamasani44a01b72013-09-16 10:44:57 -07002322 if (mHasFeature) {
2323 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
2324 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
2325 wipeDeviceOrUserLocked(0, userHandle);
2326 }
2327 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
2328 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002329 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002330 } finally {
2331 Binder.restoreCallingIdentity(ident);
2332 }
2333 }
2334 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002335
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002336 public void reportSuccessfulPasswordAttempt(int userHandle) {
2337 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002338 mContext.enforceCallingOrSelfPermission(
2339 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002340
Dianne Hackbornd6847842010-01-12 18:14:19 -08002341 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002342 DevicePolicyData policy = getUserData(userHandle);
2343 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002344 long ident = Binder.clearCallingIdentity();
2345 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002346 policy.mFailedPasswordAttempts = 0;
2347 policy.mPasswordOwner = -1;
2348 saveSettingsLocked(userHandle);
Amith Yamasani44a01b72013-09-16 10:44:57 -07002349 if (mHasFeature) {
2350 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
2351 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
2352 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002353 } finally {
2354 Binder.restoreCallingIdentity(ident);
2355 }
2356 }
2357 }
2358 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002359
Oscar Montemayor69238c62010-08-03 10:51:06 -07002360 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002361 String exclusionList, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002362 if (!mHasFeature) {
2363 return null;
2364 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002365 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002366 synchronized(this) {
2367 if (who == null) {
2368 throw new NullPointerException("ComponentName is null");
2369 }
2370
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002371 // Only check if owner has set global proxy. We don't allow other users to set it.
2372 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002373 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2374 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2375
2376 // Scan through active admins and find if anyone has already
2377 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002378 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002379 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002380 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002381 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2382 // Another admin already sets the global proxy
2383 // Return it to the caller.
2384 return component;
2385 }
2386 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002387
2388 // If the user is not the owner, don't set the global proxy. Fail silently.
2389 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2390 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2391 + userHandle + " is not permitted.");
2392 return null;
2393 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002394 if (proxySpec == null) {
2395 admin.specifiesGlobalProxy = false;
2396 admin.globalProxySpec = null;
2397 admin.globalProxyExclusionList = null;
2398 } else {
2399
2400 admin.specifiesGlobalProxy = true;
2401 admin.globalProxySpec = proxySpec;
2402 admin.globalProxyExclusionList = exclusionList;
2403 }
2404
2405 // Reset the global proxy accordingly
2406 // Do this using system permissions, as apps cannot write to secure settings
2407 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002408 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002409 Binder.restoreCallingIdentity(origId);
2410 return null;
2411 }
2412 }
2413
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002414 public ComponentName getGlobalProxyAdmin(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002415 if (!mHasFeature) {
2416 return null;
2417 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002418 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002419 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002420 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002421 // Scan through active admins and find if anyone has already
2422 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002423 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002424 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002425 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002426 if (ap.specifiesGlobalProxy) {
2427 // Device admin sets the global proxy
2428 // Return it to the caller.
2429 return ap.info.getComponent();
2430 }
2431 }
2432 }
2433 // No device admin sets the global proxy.
2434 return null;
2435 }
2436
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002437 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2438 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002439 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002440 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002441 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002442 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002443 return;
2444 }
2445 }
2446 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002447 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002448 }
2449
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002450 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002451 if (exclusionList == null) {
2452 exclusionList = "";
2453 }
2454 if (proxySpec == null) {
2455 proxySpec = "";
2456 }
2457 // Remove white spaces
2458 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002459 String data[] = proxySpec.split(":");
2460 int proxyPort = 8080;
2461 if (data.length > 1) {
2462 try {
2463 proxyPort = Integer.parseInt(data[1]);
2464 } catch (NumberFormatException e) {}
2465 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002466 exclusionList = exclusionList.trim();
2467 ContentResolver res = mContext.getContentResolver();
Raj Mamadgi92d024912013-11-11 13:52:58 -08002468
2469 ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
2470 if (!proxyProperties.isValid()) {
2471 Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
2472 return;
2473 }
Jeff Sharkey625239a2012-09-26 22:03:49 -07002474 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
2475 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2476 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwalt434203a2010-10-11 16:00:27 -07002477 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002478 }
2479
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002480 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002481 * Set the storage encryption request for a single admin. Returns the new total request
2482 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002483 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002484 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002485 if (!mHasFeature) {
2486 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2487 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002488 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002489 synchronized (this) {
2490 // Check for permissions
2491 if (who == null) {
2492 throw new NullPointerException("ComponentName is null");
2493 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002494 // Only owner can set storage encryption
2495 if (userHandle != UserHandle.USER_OWNER
2496 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2497 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2498 + UserHandle.getCallingUserId() + " is not permitted.");
2499 return 0;
2500 }
2501
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002502 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2503 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2504
Andy Stadler22dbfda2011-01-17 12:47:31 -08002505 // Quick exit: If the filesystem does not support encryption, we can exit early.
2506 if (!isEncryptionSupported()) {
2507 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2508 }
2509
2510 // (1) Record the value for the admin so it's sticky
2511 if (ap.encryptionRequested != encrypt) {
2512 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002513 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002514 }
2515
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002516 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002517 // (2) Compute "max" for all admins
2518 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002519 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002520 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002521 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002522 }
2523
2524 // Notify OS of new request
2525 setEncryptionRequested(newRequested);
2526
2527 // Return the new global request status
2528 return newRequested
2529 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2530 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002531 }
2532 }
2533
2534 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002535 * Get the current storage encryption request status for a given admin, or aggregate of all
2536 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002537 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002538 public boolean getStorageEncryption(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002539 if (!mHasFeature) {
2540 return false;
2541 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002542 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002543 synchronized (this) {
2544 // Check for permissions if a particular caller is specified
2545 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002546 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002547 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002548 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002549 }
2550
Andy Stadler22dbfda2011-01-17 12:47:31 -08002551 // If no particular caller is specified, return the aggregate set of requests.
2552 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002553 DevicePolicyData policy = getUserData(userHandle);
2554 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002555 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002556 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002557 return true;
2558 }
2559 }
2560 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002561 }
2562 }
2563
Andy Stadler22dbfda2011-01-17 12:47:31 -08002564 /**
2565 * Get the current encryption status of the device.
2566 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002567 public int getStorageEncryptionStatus(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002568 if (!mHasFeature) {
2569 // Ok to return current status.
2570 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002571 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002572 return getEncryptionStatus();
2573 }
2574
2575 /**
2576 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2577 */
2578 private boolean isEncryptionSupported() {
2579 // Note, this can be implemented as
2580 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2581 // But is provided as a separate internal method if there's a faster way to do a
2582 // simple check for supported-or-not.
2583 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2584 }
2585
2586 /**
2587 * Hook to low-levels: Reporting the current status of encryption.
2588 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2589 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2590 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2591 */
2592 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002593 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2594 if ("encrypted".equalsIgnoreCase(status)) {
2595 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2596 } else if ("unencrypted".equalsIgnoreCase(status)) {
2597 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2598 } else {
2599 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2600 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002601 }
2602
2603 /**
2604 * Hook to low-levels: If needed, record the new admin setting for encryption.
2605 */
2606 private void setEncryptionRequested(boolean encrypt) {
2607 }
2608
Ben Komalo2447edd2011-05-09 16:05:33 -07002609 /**
2610 * The system property used to share the state of the camera. The native camera service
2611 * is expected to read this property and act accordingly.
2612 */
2613 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2614
2615 /**
2616 * Disables all device cameras according to the specified admin.
2617 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002618 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002619 if (!mHasFeature) {
2620 return;
2621 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002622 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002623 synchronized (this) {
2624 if (who == null) {
2625 throw new NullPointerException("ComponentName is null");
2626 }
2627 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2628 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2629 if (ap.disableCamera != disabled) {
2630 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002631 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002632 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002633 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002634 }
2635 }
2636
2637 /**
2638 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2639 * active admins.
2640 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002641 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002642 if (!mHasFeature) {
2643 return false;
2644 }
Ben Komalo2447edd2011-05-09 16:05:33 -07002645 synchronized (this) {
2646 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002647 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002648 return (admin != null) ? admin.disableCamera : false;
2649 }
2650
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002651 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002652 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002653 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002654 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002655 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002656 if (admin.disableCamera) {
2657 return true;
2658 }
2659 }
2660 return false;
2661 }
2662 }
2663
Jim Millerb8ec4702012-08-31 17:19:10 -07002664 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002665 * Selectively disable keyguard features.
Jim Millerb8ec4702012-08-31 17:19:10 -07002666 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002667 public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002668 if (!mHasFeature) {
2669 return;
2670 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002671 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002672 synchronized (this) {
2673 if (who == null) {
2674 throw new NullPointerException("ComponentName is null");
2675 }
2676 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Jim Miller48b9b0d2012-09-19 23:16:50 -07002677 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
2678 if (ap.disabledKeyguardFeatures != which) {
2679 ap.disabledKeyguardFeatures = which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002680 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002681 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002682 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002683 }
2684 }
2685
2686 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002687 * Gets the disabled state for features in keyguard for the given admin,
Jim Millerb8ec4702012-08-31 17:19:10 -07002688 * or the aggregate of all active admins if who is null.
2689 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002690 public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002691 if (!mHasFeature) {
2692 return 0;
2693 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002694 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002695 synchronized (this) {
2696 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002697 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002698 return (admin != null) ? admin.disabledKeyguardFeatures : 0;
Jim Millerb8ec4702012-08-31 17:19:10 -07002699 }
2700
Jim Miller48b9b0d2012-09-19 23:16:50 -07002701 // Determine which keyguard features are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002702 DevicePolicyData policy = getUserData(userHandle);
2703 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002704 int which = 0;
2705 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002706 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002707 which |= admin.disabledKeyguardFeatures;
Jim Millerb8ec4702012-08-31 17:19:10 -07002708 }
2709 return which;
2710 }
2711 }
2712
Amith Yamasani71e6c692013-03-24 17:39:28 -07002713 @Override
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002714 public boolean setDeviceOwner(String packageName, String ownerName) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002715 if (!mHasFeature) {
2716 return false;
2717 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002718 if (packageName == null
2719 || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
2720 throw new IllegalArgumentException("Invalid package name " + packageName
2721 + " for device owner");
2722 }
2723 synchronized (this) {
2724 if (mDeviceOwner == null && !isDeviceProvisioned()) {
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002725 mDeviceOwner = new DeviceOwner(packageName, ownerName);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002726 mDeviceOwner.writeOwnerFile();
2727 return true;
2728 } else {
2729 throw new IllegalStateException("Trying to set device owner to " + packageName
2730 + ", owner=" + mDeviceOwner.getPackageName()
2731 + ", device_provisioned=" + isDeviceProvisioned());
2732 }
2733 }
2734 }
2735
2736 @Override
2737 public boolean isDeviceOwner(String packageName) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002738 if (!mHasFeature) {
2739 return false;
2740 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002741 synchronized (this) {
2742 return mDeviceOwner != null
2743 && mDeviceOwner.getPackageName().equals(packageName);
2744 }
2745 }
2746
2747 @Override
2748 public String getDeviceOwner() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002749 if (!mHasFeature) {
2750 return null;
2751 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002752 synchronized (this) {
2753 if (mDeviceOwner != null) {
2754 return mDeviceOwner.getPackageName();
2755 }
2756 }
2757 return null;
2758 }
2759
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002760 @Override
2761 public String getDeviceOwnerName() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002762 if (!mHasFeature) {
2763 return null;
2764 }
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002765 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
2766 synchronized (this) {
2767 if (mDeviceOwner != null) {
2768 return mDeviceOwner.getName();
2769 }
2770 }
2771 return null;
2772 }
2773
Amith Yamasani71e6c692013-03-24 17:39:28 -07002774 private boolean isDeviceProvisioned() {
2775 return Settings.Global.getInt(mContext.getContentResolver(),
2776 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
2777 }
2778
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002779 private void enforceCrossUserPermission(int userHandle) {
2780 if (userHandle < 0) {
2781 throw new IllegalArgumentException("Invalid userId " + userHandle);
2782 }
2783 final int callingUid = Binder.getCallingUid();
2784 if (userHandle == UserHandle.getUserId(callingUid)) return;
2785 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2786 mContext.enforceCallingOrSelfPermission(
2787 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2788 + " INTERACT_ACROSS_USERS_FULL permission");
2789 }
2790 }
2791
Amith Yamasani71e6c692013-03-24 17:39:28 -07002792 private void enableIfNecessary(String packageName, int userId) {
2793 try {
2794 IPackageManager ipm = AppGlobals.getPackageManager();
2795 ApplicationInfo ai = ipm.getApplicationInfo(packageName,
2796 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2797 userId);
2798 if (ai.enabledSetting
2799 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
2800 ipm.setApplicationEnabledSetting(packageName,
2801 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002802 PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
Amith Yamasani71e6c692013-03-24 17:39:28 -07002803 }
2804 } catch (RemoteException e) {
2805 }
2806 }
2807
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002808 @Override
2809 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2810 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2811 != PackageManager.PERMISSION_GRANTED) {
2812
2813 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2814 + Binder.getCallingPid()
2815 + ", uid=" + Binder.getCallingUid());
2816 return;
2817 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002818
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002819 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002820
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002821 synchronized (this) {
2822 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002823
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002824 int userCount = mUserData.size();
2825 for (int u = 0; u < userCount; u++) {
2826 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2827 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2828 final int N = policy.mAdminList.size();
2829 for (int i=0; i<N; i++) {
2830 ActiveAdmin ap = policy.mAdminList.get(i);
2831 if (ap != null) {
2832 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2833 pw.println(":");
2834 ap.dump(" ", pw);
2835 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002836 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002837
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002838 pw.println(" ");
2839 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2840 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002841 }
2842 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002843
2844 static class DeviceOwner {
2845 private static final String DEVICE_OWNER_XML = "device_owner.xml";
2846 private static final String TAG_DEVICE_OWNER = "device-owner";
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002847 private static final String ATTR_NAME = "name";
Amith Yamasani71e6c692013-03-24 17:39:28 -07002848 private static final String ATTR_PACKAGE = "package";
2849 private String mPackageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002850 private String mOwnerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002851
2852 DeviceOwner() {
2853 readOwnerFile();
2854 }
2855
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002856 DeviceOwner(String packageName, String ownerName) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07002857 this.mPackageName = packageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002858 this.mOwnerName = ownerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002859 }
2860
2861 static boolean isRegistered() {
2862 return new File(Environment.getSystemSecureDirectory(),
2863 DEVICE_OWNER_XML).exists();
2864 }
2865
2866 String getPackageName() {
2867 return mPackageName;
2868 }
2869
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002870 String getName() {
2871 return mOwnerName;
2872 }
2873
Amith Yamasani71e6c692013-03-24 17:39:28 -07002874 static boolean isInstalled(String packageName, PackageManager pm) {
2875 try {
2876 PackageInfo pi;
2877 if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
2878 if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
2879 return true;
2880 }
2881 }
2882 } catch (NameNotFoundException nnfe) {
2883 Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
2884 }
2885 return false;
2886 }
2887
2888 void readOwnerFile() {
2889 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2890 DEVICE_OWNER_XML));
2891 try {
2892 FileInputStream input = file.openRead();
2893 XmlPullParser parser = Xml.newPullParser();
2894 parser.setInput(input, null);
2895 int type;
2896 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2897 && type != XmlPullParser.START_TAG) {
2898 }
2899 String tag = parser.getName();
2900 if (!TAG_DEVICE_OWNER.equals(tag)) {
2901 throw new XmlPullParserException(
2902 "Device Owner file does not start with device-owner tag: found " + tag);
2903 }
2904 mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002905 mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002906 input.close();
2907 } catch (XmlPullParserException xppe) {
2908 Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
2909 } catch (IOException ioe) {
2910 Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
2911 }
2912 }
2913
2914 void writeOwnerFile() {
2915 synchronized (this) {
2916 writeOwnerFileLocked();
2917 }
2918 }
2919
2920 private void writeOwnerFileLocked() {
2921 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2922 DEVICE_OWNER_XML));
2923 try {
2924 FileOutputStream output = file.startWrite();
2925 XmlSerializer out = new FastXmlSerializer();
2926 out.setOutput(output, "utf-8");
2927 out.startDocument(null, true);
2928 out.startTag(null, TAG_DEVICE_OWNER);
2929 out.attribute(null, ATTR_PACKAGE, mPackageName);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002930 if (mOwnerName != null) {
2931 out.attribute(null, ATTR_NAME, mOwnerName);
2932 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002933 out.endTag(null, TAG_DEVICE_OWNER);
2934 out.endDocument();
2935 out.flush();
2936 file.finishWrite(output);
2937 } catch (IOException ioe) {
2938 Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
2939 }
2940 }
2941 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002942}