blob: 8cc80f7d70d38732570dfed6b66bb95769d6f08b [file] [log] [blame]
Dianne Hackbornd6847842010-01-12 18:14:19 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Maggie Benthallda51e682013-08-08 22:35:44 -040019import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
20
Maggie Benthall0469f412013-09-05 15:30:26 -040021import com.android.internal.R;
Dianne Hackborn42499172010-10-15 18:45:07 -070022import com.android.internal.os.storage.ExternalStorageFormatter;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080023import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070024import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080025import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080026import com.android.internal.widget.LockPatternUtils;
Maggie Benthallda51e682013-08-08 22:35:44 -040027import com.android.org.conscrypt.TrustedCertificateStore;
Dianne Hackbornd6847842010-01-12 18:14:19 -080028
29import org.xmlpull.v1.XmlPullParser;
30import org.xmlpull.v1.XmlPullParserException;
31import org.xmlpull.v1.XmlSerializer;
32
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080033import android.app.Activity;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070034import android.app.ActivityManagerNative;
Jim Millera4e28d12010-11-08 16:15:47 -080035import android.app.AlarmManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070036import android.app.AppGlobals;
Maggie Benthall0469f412013-09-05 15:30:26 -040037import android.app.INotificationManager;
38import android.app.Notification;
39import android.app.NotificationManager;
Jim Millera4e28d12010-11-08 16:15:47 -080040import android.app.PendingIntent;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080041import android.app.admin.DeviceAdminInfo;
42import android.app.admin.DeviceAdminReceiver;
43import android.app.admin.DevicePolicyManager;
44import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080045import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080046import android.content.ComponentName;
Oscar Montemayor69238c62010-08-03 10:51:06 -070047import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080048import android.content.Context;
49import android.content.Intent;
Jim Millera4e28d12010-11-08 16:15:47 -080050import android.content.IntentFilter;
Amith Yamasani71e6c692013-03-24 17:39:28 -070051import android.content.pm.ApplicationInfo;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070052import android.content.pm.IPackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070053import android.content.pm.PackageInfo;
Dianne Hackbornd6847842010-01-12 18:14:19 -080054import android.content.pm.PackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070055import android.content.pm.Signature;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080056import android.content.pm.PackageManager.NameNotFoundException;
Andy Stadler1f35d482010-11-19 15:39:41 -080057import android.content.pm.ResolveInfo;
Maggie Benthall0469f412013-09-05 15:30:26 -040058import android.content.pm.UserInfo;
Amith Yamasani71e6c692013-03-24 17:39:28 -070059import android.net.Uri;
Maggie Benthallda51e682013-08-08 22:35:44 -040060import android.os.AsyncTask;
Dianne Hackbornd6847842010-01-12 18:14:19 -080061import android.os.Binder;
Adam Cohenf7522022012-10-03 20:03:18 -070062import android.os.Bundle;
Ben Komaloed48c8b2011-10-17 17:30:21 -070063import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080064import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080065import android.os.IBinder;
66import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070067import android.os.PowerManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070068import android.os.Process;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080069import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080070import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080071import android.os.RemoteException;
72import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080073import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080074import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070075import android.os.UserHandle;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070076import android.os.UserManager;
Oscar Montemayor69238c62010-08-03 10:51:06 -070077import android.provider.Settings;
Maggie Benthallda51e682013-08-08 22:35:44 -040078import android.security.Credentials;
79import android.security.IKeyChainService;
80import android.security.KeyChain;
81import android.security.KeyChain.KeyChainConnection;
Amith Yamasani71e6c692013-03-24 17:39:28 -070082import android.util.AtomicFile;
Maggie Benthallda51e682013-08-08 22:35:44 -040083import android.util.Log;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080084import android.util.PrintWriterPrinter;
85import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080086import android.util.Slog;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070087import android.util.SparseArray;
Dianne Hackbornd6847842010-01-12 18:14:19 -080088import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080089import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080090import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080091
Maggie Benthallda51e682013-08-08 22:35:44 -040092import java.io.ByteArrayInputStream;
Dianne Hackbornd6847842010-01-12 18:14:19 -080093import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080094import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080095import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070096import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080097import java.io.FileOutputStream;
98import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080099import java.io.PrintWriter;
Maggie Benthallda51e682013-08-08 22:35:44 -0400100import java.security.KeyStore.TrustedCertificateEntry;
101import java.security.cert.CertificateException;
102import java.security.cert.CertificateFactory;
103import java.security.cert.X509Certificate;
Jim Millera4e28d12010-11-08 16:15:47 -0800104import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800105import java.util.ArrayList;
Maggie Benthallda51e682013-08-08 22:35:44 -0400106import java.util.Arrays;
107import java.util.Collection;
Amith Yamasani44a01b72013-09-16 10:44:57 -0700108import java.util.Collections;
Jim Millera4e28d12010-11-08 16:15:47 -0800109import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800110import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800111import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -0700112import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800113
114/**
115 * Implementation of the device policy APIs.
116 */
117public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700118
Jim Miller6b857682011-02-16 16:27:41 -0800119 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -0800120
Amith Yamasani71e6c692013-03-24 17:39:28 -0700121 private static final String DEVICE_POLICIES_XML = "device_policies.xml";
122
Jim Miller6b857682011-02-16 16:27:41 -0800123 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700124
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700125 private static final long MS_PER_DAY = 86400 * 1000;
126
127 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
Jim Millera4e28d12010-11-08 16:15:47 -0800128
129 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
130 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
131
Maggie Benthall0469f412013-09-05 15:30:26 -0400132 private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
133
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700134 private static final boolean DBG = false;
Jim Millera4e28d12010-11-08 16:15:47 -0800135
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800136 final Context mContext;
Dianne Hackborn42499172010-10-15 18:45:07 -0700137 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800138
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800139 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800140 IWindowManager mIWindowManager;
Maggie Benthall0469f412013-09-05 15:30:26 -0400141 NotificationManager mNotificationManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700142
Amith Yamasani71e6c692013-03-24 17:39:28 -0700143 private DeviceOwner mDeviceOwner;
144
Amith Yamasani44a01b72013-09-16 10:44:57 -0700145 /**
146 * Whether or not device admin feature is supported. If it isn't return defaults for all
147 * public methods.
148 */
149 private boolean mHasFeature;
150
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700151 public static class DevicePolicyData {
152 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
153 int mActivePasswordLength = 0;
154 int mActivePasswordUpperCase = 0;
155 int mActivePasswordLowerCase = 0;
156 int mActivePasswordLetters = 0;
157 int mActivePasswordNumeric = 0;
158 int mActivePasswordSymbols = 0;
159 int mActivePasswordNonLetter = 0;
160 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700161
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700162 int mUserHandle;;
163 int mPasswordOwner = -1;
164 long mLastMaximumTimeToLock = -1;
165
166 final HashMap<ComponentName, ActiveAdmin> mAdminMap
167 = new HashMap<ComponentName, ActiveAdmin>();
168 final ArrayList<ActiveAdmin> mAdminList
169 = new ArrayList<ActiveAdmin>();
170
171 public DevicePolicyData(int userHandle) {
172 mUserHandle = userHandle;
173 }
174 }
175
176 final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
177
Jim Millera4e28d12010-11-08 16:15:47 -0800178 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700179
Jim Millera4e28d12010-11-08 16:15:47 -0800180 BroadcastReceiver mReceiver = new BroadcastReceiver() {
181 @Override
182 public void onReceive(Context context, Intent intent) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700183 final String action = intent.getAction();
184 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
185 getSendingUserId());
Jim Millera4e28d12010-11-08 16:15:47 -0800186 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
187 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800188 if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
189 + action + " for user " + userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800190 mHandler.post(new Runnable() {
191 public void run() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700192 handlePasswordExpirationNotification(getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -0800193 }
194 });
Maggie Benthall0469f412013-09-05 15:30:26 -0400195 }
196 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
197 || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
198 manageMonitoringCertificateNotification(intent);
199 }
200 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700201 removeUserData(userHandle);
202 } else if (Intent.ACTION_USER_STARTED.equals(action)
203 || Intent.ACTION_PACKAGE_CHANGED.equals(action)
204 || Intent.ACTION_PACKAGE_REMOVED.equals(action)
205 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
206
207 if (Intent.ACTION_USER_STARTED.equals(action)) {
208 // Reset the policy data
209 synchronized (DevicePolicyManagerService.this) {
210 mUserData.remove(userHandle);
211 }
212 }
213
214 handlePackagesChanged(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800215 }
216 }
217 };
218
Dianne Hackbornd6847842010-01-12 18:14:19 -0800219 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800220 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700221
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800222 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700223
224 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
225 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
226
227 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
228 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
229
230 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
231 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
232
233 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
234 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
235
236 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700237 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700238
239 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
240 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
241
242 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
243 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
244
245 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
246 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
247
248 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
249 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
250
251 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
252 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
253
254 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
255 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
256
257 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
258 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
259
Jim Miller48b9b0d2012-09-19 23:16:50 -0700260 static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
261 int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
Jim Millerb8ec4702012-08-31 17:19:10 -0700262
Andy Stadler22dbfda2011-01-17 12:47:31 -0800263 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700264 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700265
Oscar Montemayor69238c62010-08-03 10:51:06 -0700266 // TODO: review implementation decisions with frameworks team
267 boolean specifiesGlobalProxy = false;
268 String globalProxySpec = null;
269 String globalProxyExclusionList = null;
270
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800271 ActiveAdmin(DeviceAdminInfo _info) {
272 info = _info;
273 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700274
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800275 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700276
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700277 public UserHandle getUserHandle() {
278 return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
279 }
280
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800281 void writeToXml(XmlSerializer out)
282 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800283 out.startTag(null, "policies");
284 info.writePoliciesToXml(out);
285 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800286 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
287 out.startTag(null, "password-quality");
288 out.attribute(null, "value", Integer.toString(passwordQuality));
289 out.endTag(null, "password-quality");
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700290 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800291 out.startTag(null, "min-password-length");
292 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700293 out.endTag(null, "min-password-length");
294 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700295 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700296 out.startTag(null, "password-history-length");
297 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
298 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800299 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700300 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700301 out.startTag(null, "min-password-uppercase");
302 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
303 out.endTag(null, "min-password-uppercase");
304 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700305 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700306 out.startTag(null, "min-password-lowercase");
307 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
308 out.endTag(null, "min-password-lowercase");
309 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700310 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700311 out.startTag(null, "min-password-letters");
312 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
313 out.endTag(null, "min-password-letters");
314 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700315 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700316 out.startTag(null, "min-password-numeric");
317 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
318 out.endTag(null, "min-password-numeric");
319 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700320 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700321 out.startTag(null, "min-password-symbols");
322 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
323 out.endTag(null, "min-password-symbols");
324 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700325 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700326 out.startTag(null, "min-password-nonletter");
327 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
328 out.endTag(null, "min-password-nonletter");
329 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800330 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700331 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800332 out.startTag(null, "max-time-to-unlock");
333 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
334 out.endTag(null, "max-time-to-unlock");
335 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700336 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800337 out.startTag(null, "max-failed-password-wipe");
338 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
339 out.endTag(null, "max-failed-password-wipe");
340 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700341 if (specifiesGlobalProxy) {
342 out.startTag(null, "specifies-global-proxy");
343 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
344 out.endTag(null, "specifies_global_proxy");
345 if (globalProxySpec != null) {
346 out.startTag(null, "global-proxy-spec");
347 out.attribute(null, "value", globalProxySpec);
348 out.endTag(null, "global-proxy-spec");
349 }
350 if (globalProxyExclusionList != null) {
351 out.startTag(null, "global-proxy-exclusion-list");
352 out.attribute(null, "value", globalProxyExclusionList);
353 out.endTag(null, "global-proxy-exclusion-list");
354 }
355 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700356 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800357 out.startTag(null, "password-expiration-timeout");
358 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
359 out.endTag(null, "password-expiration-timeout");
360 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700361 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800362 out.startTag(null, "password-expiration-date");
363 out.attribute(null, "value", Long.toString(passwordExpirationDate));
364 out.endTag(null, "password-expiration-date");
365 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800366 if (encryptionRequested) {
367 out.startTag(null, "encryption-requested");
368 out.attribute(null, "value", Boolean.toString(encryptionRequested));
369 out.endTag(null, "encryption-requested");
370 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700371 if (disableCamera) {
372 out.startTag(null, "disable-camera");
373 out.attribute(null, "value", Boolean.toString(disableCamera));
374 out.endTag(null, "disable-camera");
375 }
Jim Miller48b9b0d2012-09-19 23:16:50 -0700376 if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
377 out.startTag(null, "disable-keyguard-features");
378 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
379 out.endTag(null, "disable-keyguard-features");
Jim Millerb8ec4702012-08-31 17:19:10 -0700380 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800381 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700382
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800383 void readFromXml(XmlPullParser parser)
384 throws XmlPullParserException, IOException {
385 int outerDepth = parser.getDepth();
386 int type;
387 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
388 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
389 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
390 continue;
391 }
392 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800393 if ("policies".equals(tag)) {
394 info.readPoliciesFromXml(parser);
395 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800396 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800397 parser.getAttributeValue(null, "value"));
398 } else if ("min-password-length".equals(tag)) {
399 minimumPasswordLength = Integer.parseInt(
400 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700401 } else if ("password-history-length".equals(tag)) {
402 passwordHistoryLength = Integer.parseInt(
403 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700404 } else if ("min-password-uppercase".equals(tag)) {
405 minimumPasswordUpperCase = Integer.parseInt(
406 parser.getAttributeValue(null, "value"));
407 } else if ("min-password-lowercase".equals(tag)) {
408 minimumPasswordLowerCase = Integer.parseInt(
409 parser.getAttributeValue(null, "value"));
410 } else if ("min-password-letters".equals(tag)) {
411 minimumPasswordLetters = Integer.parseInt(
412 parser.getAttributeValue(null, "value"));
413 } else if ("min-password-numeric".equals(tag)) {
414 minimumPasswordNumeric = Integer.parseInt(
415 parser.getAttributeValue(null, "value"));
416 } else if ("min-password-symbols".equals(tag)) {
417 minimumPasswordSymbols = Integer.parseInt(
418 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700419 } else if ("min-password-nonletter".equals(tag)) {
420 minimumPasswordNonLetter = Integer.parseInt(
421 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800422 } else if ("max-time-to-unlock".equals(tag)) {
423 maximumTimeToUnlock = Long.parseLong(
424 parser.getAttributeValue(null, "value"));
425 } else if ("max-failed-password-wipe".equals(tag)) {
426 maximumFailedPasswordsForWipe = Integer.parseInt(
427 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700428 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800429 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700430 parser.getAttributeValue(null, "value"));
431 } else if ("global-proxy-spec".equals(tag)) {
432 globalProxySpec =
433 parser.getAttributeValue(null, "value");
434 } else if ("global-proxy-exclusion-list".equals(tag)) {
435 globalProxyExclusionList =
436 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800437 } else if ("password-expiration-timeout".equals(tag)) {
438 passwordExpirationTimeout = Long.parseLong(
439 parser.getAttributeValue(null, "value"));
440 } else if ("password-expiration-date".equals(tag)) {
441 passwordExpirationDate = Long.parseLong(
442 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800443 } else if ("encryption-requested".equals(tag)) {
444 encryptionRequested = Boolean.parseBoolean(
445 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700446 } else if ("disable-camera".equals(tag)) {
447 disableCamera = Boolean.parseBoolean(
448 parser.getAttributeValue(null, "value"));
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700449 } else if ("disable-keyguard-features".equals(tag)) {
450 disabledKeyguardFeatures = Integer.parseInt(
451 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800452 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700453 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800454 }
455 XmlUtils.skipCurrentTag(parser);
456 }
457 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700458
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800459 void dump(String prefix, PrintWriter pw) {
460 pw.print(prefix); pw.print("uid="); pw.println(getUid());
461 pw.print(prefix); pw.println("policies:");
462 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
463 if (pols != null) {
464 for (int i=0; i<pols.size(); i++) {
465 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
466 }
467 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700468 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700469 pw.println(Integer.toHexString(passwordQuality));
470 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800471 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700472 pw.print(prefix); pw.print("passwordHistoryLength=");
473 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700474 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
475 pw.println(minimumPasswordUpperCase);
476 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
477 pw.println(minimumPasswordLowerCase);
478 pw.print(prefix); pw.print("minimumPasswordLetters=");
479 pw.println(minimumPasswordLetters);
480 pw.print(prefix); pw.print("minimumPasswordNumeric=");
481 pw.println(minimumPasswordNumeric);
482 pw.print(prefix); pw.print("minimumPasswordSymbols=");
483 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700484 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
485 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800486 pw.print(prefix); pw.print("maximumTimeToUnlock=");
487 pw.println(maximumTimeToUnlock);
488 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
489 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700490 pw.print(prefix); pw.print("specifiesGlobalProxy=");
491 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800492 pw.print(prefix); pw.print("passwordExpirationTimeout=");
493 pw.println(passwordExpirationTimeout);
494 pw.print(prefix); pw.print("passwordExpirationDate=");
495 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700496 if (globalProxySpec != null) {
497 pw.print(prefix); pw.print("globalProxySpec=");
498 pw.println(globalProxySpec);
499 }
500 if (globalProxyExclusionList != null) {
501 pw.print(prefix); pw.print("globalProxyEclusionList=");
502 pw.println(globalProxyExclusionList);
503 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800504 pw.print(prefix); pw.print("encryptionRequested=");
505 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700506 pw.print(prefix); pw.print("disableCamera=");
507 pw.println(disableCamera);
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700508 pw.print(prefix); pw.print("disabledKeyguardFeatures=");
509 pw.println(disabledKeyguardFeatures);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800510 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800511 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700512
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700513 private void handlePackagesChanged(int userHandle) {
514 boolean removed = false;
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800515 if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700516 DevicePolicyData policy = getUserData(userHandle);
517 IPackageManager pm = AppGlobals.getPackageManager();
518 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
519 ActiveAdmin aa = policy.mAdminList.get(i);
520 try {
521 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
522 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
523 removed = true;
524 policy.mAdminList.remove(i);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800525 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700526 } catch (RemoteException re) {
527 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800528 }
529 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700530 if (removed) {
531 validatePasswordOwnerLocked(policy);
532 syncDeviceCapabilitiesLocked(policy);
533 saveSettingsLocked(policy.mUserHandle);
534 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800535 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700536
Dianne Hackbornd6847842010-01-12 18:14:19 -0800537 /**
538 * Instantiates the service.
539 */
540 public DevicePolicyManagerService(Context context) {
541 mContext = context;
Amith Yamasani44a01b72013-09-16 10:44:57 -0700542 mHasFeature = context.getPackageManager().hasSystemFeature(
543 PackageManager.FEATURE_DEVICE_ADMIN);
Dianne Hackborn42499172010-10-15 18:45:07 -0700544 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
545 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Amith Yamasani44a01b72013-09-16 10:44:57 -0700546 if (!mHasFeature) {
547 // Skip the rest of the initialization
548 return;
549 }
Jim Millera4e28d12010-11-08 16:15:47 -0800550 IntentFilter filter = new IntentFilter();
551 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
552 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700553 filter.addAction(Intent.ACTION_USER_REMOVED);
554 filter.addAction(Intent.ACTION_USER_STARTED);
Maggie Benthall0469f412013-09-05 15:30:26 -0400555 filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700556 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
557 filter = new IntentFilter();
558 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
559 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
560 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Amith Yamasani71e6c692013-03-24 17:39:28 -0700561 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700562 filter.addDataScheme("package");
563 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
564 }
565
566 /**
567 * Creates and loads the policy data from xml.
568 * @param userHandle the user for whom to load the policy data
569 * @return
570 */
571 DevicePolicyData getUserData(int userHandle) {
572 synchronized (this) {
573 DevicePolicyData policy = mUserData.get(userHandle);
574 if (policy == null) {
575 policy = new DevicePolicyData(userHandle);
576 mUserData.append(userHandle, policy);
577 loadSettingsLocked(policy, userHandle);
578 }
579 return policy;
580 }
581 }
582
583 void removeUserData(int userHandle) {
584 synchronized (this) {
585 if (userHandle == UserHandle.USER_OWNER) {
586 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
587 return;
588 }
589 DevicePolicyData policy = mUserData.get(userHandle);
590 if (policy != null) {
591 mUserData.remove(userHandle);
592 }
593 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
594 DEVICE_POLICIES_XML);
595 policyFile.delete();
596 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
597 }
Jim Millera4e28d12010-11-08 16:15:47 -0800598 }
599
Amith Yamasani71e6c692013-03-24 17:39:28 -0700600 void loadDeviceOwner() {
601 synchronized (this) {
602 if (DeviceOwner.isRegistered()) {
603 mDeviceOwner = new DeviceOwner();
604 }
605 }
606 }
607
Andy Stadler043116a2010-11-29 17:43:32 -0800608 /**
609 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
610 * reminders. Clears alarm if no expirations are configured.
611 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700612 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
613 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800614 final long now = System.currentTimeMillis();
615 final long timeToExpire = expiration - now;
616 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800617 if (expiration == 0) {
618 // No expirations are currently configured: Cancel alarm.
619 alarmTime = 0;
620 } else if (timeToExpire <= 0) {
621 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800622 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800623 } else {
624 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
625 // the expiration time.
626 long alarmInterval = timeToExpire % MS_PER_DAY;
627 if (alarmInterval == 0) {
628 alarmInterval = MS_PER_DAY;
629 }
630 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800631 }
632
Andy Stadler1f35d482010-11-19 15:39:41 -0800633 long token = Binder.clearCallingIdentity();
634 try {
635 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700636 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800637 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700638 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
639 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800640 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800641 if (alarmTime != 0) {
642 am.set(AlarmManager.RTC, alarmTime, pi);
643 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800644 } finally {
645 Binder.restoreCallingIdentity(token);
646 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800647 }
648
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800649 private IPowerManager getIPowerManager() {
650 if (mIPowerManager == null) {
651 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
652 mIPowerManager = IPowerManager.Stub.asInterface(b);
653 }
654 return mIPowerManager;
655 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700656
Jim Miller93c518e2012-01-17 15:55:31 -0800657 private IWindowManager getWindowManager() {
658 if (mIWindowManager == null) {
659 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
660 mIWindowManager = IWindowManager.Stub.asInterface(b);
661 }
662 return mIWindowManager;
663 }
664
Maggie Benthall0469f412013-09-05 15:30:26 -0400665 private NotificationManager getNotificationManager() {
666 if (mNotificationManager == null) {
667 mNotificationManager =
668 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
669 }
670 return mNotificationManager;
671 }
672
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700673 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
674 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800675 if (admin != null
676 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
677 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
678 return admin;
679 }
680 return null;
681 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700682
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800683 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
684 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800685 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700686 final int userHandle = UserHandle.getUserId(callingUid);
687 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800688 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700689 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800690 if (admin == null) {
691 throw new SecurityException("No active admin " + who);
692 }
693 if (admin.getUid() != callingUid) {
694 throw new SecurityException("Admin " + who + " is not owned by uid "
695 + Binder.getCallingUid());
696 }
697 if (!admin.info.usesPolicy(reqPolicy)) {
698 throw new SecurityException("Admin " + admin.info.getComponent()
699 + " did not specify uses-policy for: "
700 + admin.info.getTagForPolicy(reqPolicy));
701 }
702 return admin;
703 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700704 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800705 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700706 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800707 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
708 return admin;
709 }
710 }
711 throw new SecurityException("No active admin owned by uid "
712 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800713 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800714 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700715
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800716 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700717 sendAdminCommandLocked(admin, action, null);
718 }
719
720 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800721 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800722 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800723 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
724 intent.putExtra("expiration", admin.passwordExpirationDate);
725 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700726 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700727 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700728 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700729 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700730 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700731 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800732 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700733
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700734 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
735 final DevicePolicyData policy = getUserData(userHandle);
736 final int count = policy.mAdminList.size();
737 if (count > 0) {
738 for (int i = 0; i < count; i++) {
739 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800740 if (admin.info.usesPolicy(reqPolicy)) {
741 sendAdminCommandLocked(admin, action);
742 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800743 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800744 }
745 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700746
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700747 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
748 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800749 if (admin != null) {
750 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700751 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
752 new BroadcastReceiver() {
753 @Override
754 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700755 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700756 int userHandle = admin.getUserHandle().getIdentifier();
757 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700758 boolean doProxyCleanup = admin.info.usesPolicy(
759 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700760 policy.mAdminList.remove(admin);
761 policy.mAdminMap.remove(adminReceiver);
762 validatePasswordOwnerLocked(policy);
763 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700764 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700765 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700766 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700767 saveSettingsLocked(userHandle);
768 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700769 }
770 }
771 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800772 }
773 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700774
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700775 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -0700776 if (!mHasFeature) {
777 return null;
778 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700779 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800780 Intent resolveIntent = new Intent();
781 resolveIntent.setComponent(adminName);
782 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani71e6c692013-03-24 17:39:28 -0700783 resolveIntent,
784 PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
785 userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800786 if (infos == null || infos.size() <= 0) {
787 throw new IllegalArgumentException("Unknown admin: " + adminName);
788 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700789
Dianne Hackbornd6847842010-01-12 18:14:19 -0800790 try {
791 return new DeviceAdminInfo(mContext, infos.get(0));
792 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700793 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800794 return null;
795 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700796 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800797 return null;
798 }
799 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700800
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700801 private static JournaledFile makeJournaledFile(int userHandle) {
802 final String base = userHandle == 0
803 ? "/data/system/" + DEVICE_POLICIES_XML
804 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
805 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800806 return new JournaledFile(new File(base), new File(base + ".tmp"));
807 }
808
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700809 private void saveSettingsLocked(int userHandle) {
810 DevicePolicyData policy = getUserData(userHandle);
811 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800812 FileOutputStream stream = null;
813 try {
814 stream = new FileOutputStream(journal.chooseForWrite(), false);
815 XmlSerializer out = new FastXmlSerializer();
816 out.setOutput(stream, "utf-8");
817 out.startDocument(null, true);
818
819 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700820
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700821 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800822 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700823 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800824 if (ap != null) {
825 out.startTag(null, "admin");
826 out.attribute(null, "name", ap.info.getComponent().flattenToString());
827 ap.writeToXml(out);
828 out.endTag(null, "admin");
829 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800830 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700831
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700832 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800833 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700834 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800835 out.endTag(null, "password-owner");
836 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700837
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700838 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800839 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700840 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800841 out.endTag(null, "failed-password-attempts");
842 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700843
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700844 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
845 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
846 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
847 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700848 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700849 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
850 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
851 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
852 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
853 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700854 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700855 .toString(policy.mActivePasswordNumeric));
856 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
857 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700858 out.endTag(null, "active-password");
859 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700860
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700861 out.endTag(null, "policies");
862
Dianne Hackbornd6847842010-01-12 18:14:19 -0800863 out.endDocument();
864 stream.close();
865 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700866 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800867 } catch (IOException e) {
868 try {
869 if (stream != null) {
870 stream.close();
871 }
872 } catch (IOException ex) {
873 // Ignore
874 }
875 journal.rollback();
876 }
877 }
878
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700879 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700880 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
881 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700882 long ident = Binder.clearCallingIdentity();
883 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700884 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700885 } finally {
886 Binder.restoreCallingIdentity(ident);
887 }
Jim Miller284b62e2010-06-08 14:27:42 -0700888 }
889
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700890 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
891 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800892 FileInputStream stream = null;
893 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800894 try {
895 stream = new FileInputStream(file);
896 XmlPullParser parser = Xml.newPullParser();
897 parser.setInput(stream, null);
898
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800899 int type;
900 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
901 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800902 }
903 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800904 if (!"policies".equals(tag)) {
905 throw new XmlPullParserException(
906 "Settings do not start with policies tag: found " + tag);
907 }
908 type = parser.next();
909 int outerDepth = parser.getDepth();
910 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
911 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
912 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
913 continue;
914 }
915 tag = parser.getName();
916 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800917 String name = parser.getAttributeValue(null, "name");
918 try {
919 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700920 ComponentName.unflattenFromString(name), userHandle);
921 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
922 != userHandle)) {
923 Slog.w(TAG, "findAdmin returned an incorrect uid "
924 + dai.getActivityInfo().applicationInfo.uid + " for user "
925 + userHandle);
926 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800927 if (dai != null) {
928 ActiveAdmin ap = new ActiveAdmin(dai);
929 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700930 policy.mAdminMap.put(ap.info.getComponent(), ap);
931 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800932 }
933 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700934 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800935 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800936 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700937 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800938 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800939 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800940 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700941 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800942 parser.getAttributeValue(null, "value"));
943 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700944 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700945 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700946 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700947 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700948 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700949 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700950 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700951 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700952 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700953 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700954 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700955 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700956 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700957 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700958 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700959 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700960 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700961 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800962 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700963 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800964 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800965 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800966 }
967 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700968 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800969 } catch (NumberFormatException 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 (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700972 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700973 } catch (FileNotFoundException e) {
974 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800975 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700976 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800977 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700978 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800979 }
980 try {
981 if (stream != null) {
982 stream.close();
983 }
984 } catch (IOException e) {
985 // Ignore
986 }
987
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700988 // Validate that what we stored for the password quality matches
989 // sufficiently what is currently set. Note that this is only
990 // a sanity check in case the two get out of sync; this should
991 // never normally happen.
992 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700993 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700994 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700995 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700996 + " does not match actual quality 0x"
997 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700998 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
999 policy.mActivePasswordLength = 0;
1000 policy.mActivePasswordUpperCase = 0;
1001 policy.mActivePasswordLowerCase = 0;
1002 policy.mActivePasswordLetters = 0;
1003 policy.mActivePasswordNumeric = 0;
1004 policy.mActivePasswordSymbols = 0;
1005 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001006 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001007
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001008 validatePasswordOwnerLocked(policy);
1009 syncDeviceCapabilitiesLocked(policy);
1010 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001011 }
1012
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001013 static void validateQualityConstant(int quality) {
1014 switch (quality) {
1015 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -05001016 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001017 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
1018 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
1019 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
1020 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001021 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001022 return;
1023 }
1024 throw new IllegalArgumentException("Invalid quality constant: 0x"
1025 + Integer.toHexString(quality));
1026 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001027
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001028 void validatePasswordOwnerLocked(DevicePolicyData policy) {
1029 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001030 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001031 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
1032 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001033 haveOwner = true;
1034 break;
1035 }
1036 }
1037 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001038 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001039 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001040 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001041 }
1042 }
1043 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001044
Ben Komalo2447edd2011-05-09 16:05:33 -07001045 /**
1046 * Pushes down policy information to the system for any policies related to general device
1047 * capabilities that need to be enforced by lower level services (e.g. Camera services).
1048 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001049 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -07001050 // Ensure the status of the camera is synced down to the system. Interested native services
1051 // should monitor this value and act accordingly.
1052 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001053 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07001054 if (cameraDisabled != systemState) {
1055 long token = Binder.clearCallingIdentity();
1056 try {
1057 String value = cameraDisabled ? "1" : "0";
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001058 if (DBG) Slog.v(TAG, "Change in camera state ["
Ben Komalo2447edd2011-05-09 16:05:33 -07001059 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
1060 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
1061 } finally {
1062 Binder.restoreCallingIdentity(token);
1063 }
1064 }
1065 }
1066
Dianne Hackbornd6847842010-01-12 18:14:19 -08001067 public void systemReady() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001068 if (!mHasFeature) {
1069 return;
1070 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001071 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001072 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001073 loadDeviceOwner();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001074 }
1075 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001076
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001077 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -08001078 synchronized (this) {
1079 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001080 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001081 if (N <= 0) {
1082 return;
1083 }
1084 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001085 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001086 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1087 && admin.passwordExpirationTimeout > 0L
1088 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001089 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001090 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1091 }
1092 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001093 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001094 }
1095 }
1096
Maggie Benthall0469f412013-09-05 15:30:26 -04001097 private void manageMonitoringCertificateNotification(Intent intent) {
1098 final NotificationManager notificationManager = getNotificationManager();
1099
1100 final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
1101 if (! hasCert) {
1102 if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
1103 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1104 for (UserInfo user : um.getUsers()) {
1105 notificationManager.cancelAsUser(
1106 null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
1107 }
1108 }
1109 return;
1110 }
1111 final boolean isManaged = getDeviceOwner() != null;
1112 int smallIconId;
1113 String contentText;
1114 if (isManaged) {
1115 contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
1116 getDeviceOwnerName());
1117 smallIconId = R.drawable.stat_sys_certificate_info;
1118 } else {
1119 contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
1120 smallIconId = android.R.drawable.stat_sys_warning;
1121 }
1122
1123 Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
1124 dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1125 dialogIntent.setPackage("com.android.settings");
1126 // Notification will be sent individually to all users. The activity should start as
1127 // whichever user is current when it starts.
1128 PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
1129 PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
1130
1131 Notification noti = new Notification.Builder(mContext)
1132 .setSmallIcon(smallIconId)
1133 .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
1134 .setContentText(contentText)
1135 .setContentIntent(notifyIntent)
1136 .setPriority(Notification.PRIORITY_HIGH)
1137 .setShowWhen(false)
1138 .build();
1139
1140 // If this is a boot intent, this will fire for each user. But if this is a storage changed
1141 // intent, it will fire once, so we need to notify all users.
1142 if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
1143 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1144 for (UserInfo user : um.getUsers()) {
1145 notificationManager.notifyAsUser(
1146 null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
1147 }
1148 } else {
1149 notificationManager.notifyAsUser(
1150 null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
1151 }
1152 }
1153
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001154 /**
1155 * @param adminReceiver The admin to add
1156 * @param refreshing true = update an active admin, no error
1157 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001158 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001159 if (!mHasFeature) {
1160 return;
1161 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001162 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001163 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001164 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001165
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001166 DevicePolicyData policy = getUserData(userHandle);
1167 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001168 if (info == null) {
1169 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1170 }
1171 synchronized (this) {
1172 long ident = Binder.clearCallingIdentity();
1173 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001174 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001175 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001176 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001177 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001178 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001179 int replaceIndex = -1;
1180 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001181 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001182 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001183 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001184 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1185 replaceIndex = i;
1186 break;
1187 }
1188 }
1189 }
1190 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001191 policy.mAdminList.add(newAdmin);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001192 enableIfNecessary(info.getPackageName(), userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001193 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001194 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001195 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001196 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001197 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001198 } finally {
1199 Binder.restoreCallingIdentity(ident);
1200 }
1201 }
1202 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001203
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001204 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001205 if (!mHasFeature) {
1206 return false;
1207 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001208 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001209 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001210 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001211 }
1212 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001213
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001214 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001215 if (!mHasFeature) {
1216 return false;
1217 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001218 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001219 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001220 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001221 if (administrator == null) {
1222 throw new SecurityException("No active admin " + adminReceiver);
1223 }
1224 return administrator.info.usesPolicy(policyId);
1225 }
1226 }
1227
Amith Yamasani44a01b72013-09-16 10:44:57 -07001228 @SuppressWarnings("unchecked")
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001229 public List<ComponentName> getActiveAdmins(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001230 if (!mHasFeature) {
1231 return Collections.EMPTY_LIST;
1232 }
1233
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001234 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001235 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001236 DevicePolicyData policy = getUserData(userHandle);
1237 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001238 if (N <= 0) {
1239 return null;
1240 }
1241 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1242 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001243 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001244 }
1245 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001246 }
1247 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001248
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001249 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001250 if (!mHasFeature) {
1251 return false;
1252 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001253 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001254 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001255 DevicePolicyData policy = getUserData(userHandle);
1256 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001257 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001258 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001259 return true;
1260 }
1261 }
1262 return false;
1263 }
1264 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001265
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001266 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001267 if (!mHasFeature) {
1268 return;
1269 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001270 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001271 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001272 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001273 if (admin == null) {
1274 return;
1275 }
1276 if (admin.getUid() != Binder.getCallingUid()) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07001277 // If trying to remove device owner, refuse when the caller is not the owner.
1278 if (mDeviceOwner != null
1279 && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
1280 return;
1281 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001282 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001283 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001284 }
1285 long ident = Binder.clearCallingIdentity();
1286 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001287 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001288 } finally {
1289 Binder.restoreCallingIdentity(ident);
1290 }
1291 }
1292 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001293
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001294 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001295 if (!mHasFeature) {
1296 return;
1297 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001298 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001299 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001300
Dianne Hackbornd6847842010-01-12 18:14:19 -08001301 synchronized (this) {
1302 if (who == null) {
1303 throw new NullPointerException("ComponentName is null");
1304 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001305 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1306 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001307 if (ap.passwordQuality != quality) {
1308 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001309 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001310 }
1311 }
1312 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001313
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001314 public int getPasswordQuality(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001315 if (!mHasFeature) {
1316 return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
1317 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001318 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001319 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001320 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001321 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001322
Dianne Hackborn254cb442010-01-27 19:23:59 -08001323 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001324 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001325 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001326 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001327
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001328 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001329 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001330 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001331 if (mode < admin.passwordQuality) {
1332 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001333 }
1334 }
1335 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001336 }
1337 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001338
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001339 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001340 if (!mHasFeature) {
1341 return;
1342 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001343 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001344 synchronized (this) {
1345 if (who == null) {
1346 throw new NullPointerException("ComponentName is null");
1347 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001348 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1349 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001350 if (ap.minimumPasswordLength != length) {
1351 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001352 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001353 }
1354 }
1355 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001356
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001357 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001358 if (!mHasFeature) {
1359 return 0;
1360 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001361 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001362 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001363 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001364 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001365
Dianne Hackborn254cb442010-01-27 19:23:59 -08001366 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001367 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001368 return admin != null ? admin.minimumPasswordLength : length;
1369 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001370
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001371 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001372 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001373 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001374 if (length < admin.minimumPasswordLength) {
1375 length = admin.minimumPasswordLength;
1376 }
1377 }
1378 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001379 }
1380 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001381
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001382 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001383 if (!mHasFeature) {
1384 return;
1385 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001386 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001387 synchronized (this) {
1388 if (who == null) {
1389 throw new NullPointerException("ComponentName is null");
1390 }
1391 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1392 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1393 if (ap.passwordHistoryLength != length) {
1394 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001395 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001396 }
1397 }
1398 }
1399
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001400 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001401 if (!mHasFeature) {
1402 return 0;
1403 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001404 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001405 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001406 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001407 int length = 0;
1408
1409 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001410 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001411 return admin != null ? admin.passwordHistoryLength : length;
1412 }
1413
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001414 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001415 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001416 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001417 if (length < admin.passwordHistoryLength) {
1418 length = admin.passwordHistoryLength;
1419 }
1420 }
1421 return length;
1422 }
1423 }
1424
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001425 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001426 if (!mHasFeature) {
1427 return;
1428 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001429 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001430 synchronized (this) {
1431 if (who == null) {
1432 throw new NullPointerException("ComponentName is null");
1433 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001434 if (timeout < 0) {
1435 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001436 }
1437 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1438 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1439 // Calling this API automatically bumps the expiration date
1440 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1441 ap.passwordExpirationDate = expiration;
1442 ap.passwordExpirationTimeout = timeout;
1443 if (timeout > 0L) {
1444 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1445 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1446 .format(new Date(expiration)));
1447 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001448 saveSettingsLocked(userHandle);
1449 // in case this is the first one
1450 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001451 }
1452 }
1453
Andy Stadler043116a2010-11-29 17:43:32 -08001454 /**
1455 * Return a single admin's expiration cycle time, or the min of all cycle times.
1456 * Returns 0 if not configured.
1457 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001458 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001459 if (!mHasFeature) {
1460 return 0L;
1461 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001462 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001463 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001464 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001465 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001466 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001467 }
1468
Andy Stadler043116a2010-11-29 17:43:32 -08001469 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001470 DevicePolicyData policy = getUserData(userHandle);
1471 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001472 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001473 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001474 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1475 && timeout > admin.passwordExpirationTimeout)) {
1476 timeout = admin.passwordExpirationTimeout;
1477 }
1478 }
1479 return timeout;
1480 }
1481 }
1482
Andy Stadler043116a2010-11-29 17:43:32 -08001483 /**
1484 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1485 * Returns 0 if not configured.
1486 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001487 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001488 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001489 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001490 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001491 }
1492
Andy Stadler043116a2010-11-29 17:43:32 -08001493 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001494 DevicePolicyData policy = getUserData(userHandle);
1495 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001496 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001497 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001498 if (timeout == 0L || (admin.passwordExpirationDate != 0
1499 && timeout > admin.passwordExpirationDate)) {
1500 timeout = admin.passwordExpirationDate;
1501 }
1502 }
1503 return timeout;
1504 }
1505
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001506 public long getPasswordExpiration(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001507 if (!mHasFeature) {
1508 return 0L;
1509 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001510 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001511 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001512 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001513 }
1514 }
1515
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001516 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001517 if (!mHasFeature) {
1518 return;
1519 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001520 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001521 synchronized (this) {
1522 if (who == null) {
1523 throw new NullPointerException("ComponentName is null");
1524 }
1525 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1526 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1527 if (ap.minimumPasswordUpperCase != length) {
1528 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001529 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001530 }
1531 }
1532 }
1533
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001534 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001535 if (!mHasFeature) {
1536 return 0;
1537 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001538 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001539 synchronized (this) {
1540 int length = 0;
1541
1542 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001543 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001544 return admin != null ? admin.minimumPasswordUpperCase : length;
1545 }
1546
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001547 DevicePolicyData policy = getUserData(userHandle);
1548 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001549 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001550 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001551 if (length < admin.minimumPasswordUpperCase) {
1552 length = admin.minimumPasswordUpperCase;
1553 }
1554 }
1555 return length;
1556 }
1557 }
1558
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001559 public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
1560 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001561 synchronized (this) {
1562 if (who == null) {
1563 throw new NullPointerException("ComponentName is null");
1564 }
1565 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1566 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1567 if (ap.minimumPasswordLowerCase != length) {
1568 ap.minimumPasswordLowerCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001569 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001570 }
1571 }
1572 }
1573
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001574 public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001575 if (!mHasFeature) {
1576 return 0;
1577 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001578 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001579 synchronized (this) {
1580 int length = 0;
1581
1582 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001583 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001584 return admin != null ? admin.minimumPasswordLowerCase : length;
1585 }
1586
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001587 DevicePolicyData policy = getUserData(userHandle);
1588 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001589 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001590 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001591 if (length < admin.minimumPasswordLowerCase) {
1592 length = admin.minimumPasswordLowerCase;
1593 }
1594 }
1595 return length;
1596 }
1597 }
1598
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001599 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001600 if (!mHasFeature) {
1601 return;
1602 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001603 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001604 synchronized (this) {
1605 if (who == null) {
1606 throw new NullPointerException("ComponentName is null");
1607 }
1608 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1609 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1610 if (ap.minimumPasswordLetters != length) {
1611 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001612 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001613 }
1614 }
1615 }
1616
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001617 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001618 if (!mHasFeature) {
1619 return 0;
1620 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001621 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001622 synchronized (this) {
1623 int length = 0;
1624
1625 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001626 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001627 return admin != null ? admin.minimumPasswordLetters : length;
1628 }
1629
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001630 DevicePolicyData policy = getUserData(userHandle);
1631 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001632 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001633 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001634 if (length < admin.minimumPasswordLetters) {
1635 length = admin.minimumPasswordLetters;
1636 }
1637 }
1638 return length;
1639 }
1640 }
1641
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001642 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001643 if (!mHasFeature) {
1644 return;
1645 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001646 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001647 synchronized (this) {
1648 if (who == null) {
1649 throw new NullPointerException("ComponentName is null");
1650 }
1651 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1652 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1653 if (ap.minimumPasswordNumeric != length) {
1654 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001655 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001656 }
1657 }
1658 }
1659
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001660 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001661 if (!mHasFeature) {
1662 return 0;
1663 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001664 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001665 synchronized (this) {
1666 int length = 0;
1667
1668 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001669 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001670 return admin != null ? admin.minimumPasswordNumeric : length;
1671 }
1672
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001673 DevicePolicyData policy = getUserData(userHandle);
1674 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001675 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001676 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001677 if (length < admin.minimumPasswordNumeric) {
1678 length = admin.minimumPasswordNumeric;
1679 }
1680 }
1681 return length;
1682 }
1683 }
1684
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001685 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001686 if (!mHasFeature) {
1687 return;
1688 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001689 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001690 synchronized (this) {
1691 if (who == null) {
1692 throw new NullPointerException("ComponentName is null");
1693 }
1694 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1695 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1696 if (ap.minimumPasswordSymbols != length) {
1697 ap.minimumPasswordSymbols = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001698 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001699 }
1700 }
1701 }
1702
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001703 public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001704 if (!mHasFeature) {
1705 return 0;
1706 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001707 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001708 synchronized (this) {
1709 int length = 0;
1710
1711 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001712 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001713 return admin != null ? admin.minimumPasswordSymbols : length;
1714 }
1715
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001716 DevicePolicyData policy = getUserData(userHandle);
1717 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001718 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001719 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001720 if (length < admin.minimumPasswordSymbols) {
1721 length = admin.minimumPasswordSymbols;
1722 }
1723 }
1724 return length;
1725 }
1726 }
1727
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001728 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001729 if (!mHasFeature) {
1730 return;
1731 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001732 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001733 synchronized (this) {
1734 if (who == null) {
1735 throw new NullPointerException("ComponentName is null");
1736 }
1737 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1738 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1739 if (ap.minimumPasswordNonLetter != length) {
1740 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001741 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001742 }
1743 }
1744 }
1745
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001746 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001747 if (!mHasFeature) {
1748 return 0;
1749 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001750 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001751 synchronized (this) {
1752 int length = 0;
1753
1754 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001755 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001756 return admin != null ? admin.minimumPasswordNonLetter : length;
1757 }
1758
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001759 DevicePolicyData policy = getUserData(userHandle);
1760 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001761 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001762 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001763 if (length < admin.minimumPasswordNonLetter) {
1764 length = admin.minimumPasswordNonLetter;
1765 }
1766 }
1767 return length;
1768 }
1769 }
1770
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001771 public boolean isActivePasswordSufficient(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001772 if (!mHasFeature) {
1773 return true;
1774 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001775 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001776 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001777 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001778 // This API can only be called by an active device admin,
1779 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001780 getActiveAdminForCallerLocked(null,
1781 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001782 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1783 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001784 return false;
1785 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001786 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001787 return true;
1788 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001789 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1790 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1791 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1792 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1793 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1794 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001795 }
1796 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001797
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001798 public int getCurrentFailedPasswordAttempts(int userHandle) {
1799 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001800 synchronized (this) {
1801 // This API can only be called by an active device admin,
1802 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001803 getActiveAdminForCallerLocked(null,
1804 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001805 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001806 }
1807 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001808
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001809 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001810 if (!mHasFeature) {
1811 return;
1812 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001813 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001814 synchronized (this) {
1815 // This API can only be called by an active device admin,
1816 // so try to retrieve it to check that the caller is one.
1817 getActiveAdminForCallerLocked(who,
1818 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1819 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1820 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1821 if (ap.maximumFailedPasswordsForWipe != num) {
1822 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001823 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001824 }
1825 }
1826 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001827
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001828 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001829 if (!mHasFeature) {
1830 return 0;
1831 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001832 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001833 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001834 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001835 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001836
Dianne Hackborn254cb442010-01-27 19:23:59 -08001837 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001838 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001839 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1840 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001841
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001842 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001843 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001844 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001845 if (count == 0) {
1846 count = admin.maximumFailedPasswordsForWipe;
1847 } else if (admin.maximumFailedPasswordsForWipe != 0
1848 && count > admin.maximumFailedPasswordsForWipe) {
1849 count = admin.maximumFailedPasswordsForWipe;
1850 }
1851 }
1852 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001853 }
1854 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001855
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001856 public boolean resetPassword(String password, int flags, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001857 if (!mHasFeature) {
1858 return false;
1859 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001860 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001861 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001862 synchronized (this) {
1863 // This API can only be called by an active device admin,
1864 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001865 getActiveAdminForCallerLocked(null,
1866 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001867 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001868 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001869 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001870 if (realQuality < quality
1871 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001872 Slog.w(TAG, "resetPassword: password quality 0x"
joonyoung.choad83c192013-04-18 13:51:08 +09001873 + Integer.toHexString(realQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001874 + " does not meet required quality 0x"
1875 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001876 return false;
1877 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001878 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001879 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001880 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001881 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001882 Slog.w(TAG, "resetPassword: password length " + password.length()
1883 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001884 return false;
1885 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001886 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1887 int letters = 0;
1888 int uppercase = 0;
1889 int lowercase = 0;
1890 int numbers = 0;
1891 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001892 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001893 for (int i = 0; i < password.length(); i++) {
1894 char c = password.charAt(i);
1895 if (c >= 'A' && c <= 'Z') {
1896 letters++;
1897 uppercase++;
1898 } else if (c >= 'a' && c <= 'z') {
1899 letters++;
1900 lowercase++;
1901 } else if (c >= '0' && c <= '9') {
1902 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001903 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001904 } else {
1905 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001906 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001907 }
1908 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001909 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001910 if(letters < neededLetters) {
1911 Slog.w(TAG, "resetPassword: number of letters " + letters
1912 + " does not meet required number of letters " + neededLetters);
1913 return false;
1914 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001915 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001916 if (numbers < neededNumbers) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001917 Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
1918 + " does not meet required number of numerical digits "
1919 + neededNumbers);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001920 return false;
1921 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001922 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001923 if (lowercase < neededLowerCase) {
1924 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1925 + " does not meet required number of lowercase letters "
1926 + neededLowerCase);
1927 return false;
1928 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001929 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001930 if (uppercase < neededUpperCase) {
1931 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1932 + " does not meet required number of uppercase letters "
1933 + neededUpperCase);
1934 return false;
1935 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001936 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001937 if (symbols < neededSymbols) {
1938 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1939 + " does not meet required number of special symbols " + neededSymbols);
1940 return false;
1941 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001942 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001943 if (nonletter < neededNonLetter) {
1944 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1945 + " does not meet required number of non-letter characters "
1946 + neededNonLetter);
1947 return false;
1948 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001949 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001950 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001951
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001952 int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001953 DevicePolicyData policy = getUserData(userHandle);
1954 if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001955 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001956 return false;
1957 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001958
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001959 // Don't do this with the lock held, because it is going to call
1960 // back in to the service.
1961 long ident = Binder.clearCallingIdentity();
1962 try {
1963 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001964 utils.saveLockPassword(password, quality, false, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001965 synchronized (this) {
1966 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1967 != 0 ? callingUid : -1;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001968 if (policy.mPasswordOwner != newOwner) {
1969 policy.mPasswordOwner = newOwner;
1970 saveSettingsLocked(userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001971 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001972 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001973 } finally {
1974 Binder.restoreCallingIdentity(ident);
1975 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001976
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001977 return true;
1978 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001979
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001980 public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07001981 if (!mHasFeature) {
1982 return;
1983 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001984 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001985 synchronized (this) {
1986 if (who == null) {
1987 throw new NullPointerException("ComponentName is null");
1988 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001989 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001990 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001991 if (ap.maximumTimeToUnlock != timeMs) {
1992 ap.maximumTimeToUnlock = timeMs;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001993 saveSettingsLocked(userHandle);
1994 updateMaximumTimeToLockLocked(getUserData(userHandle));
Dianne Hackbornd6847842010-01-12 18:14:19 -08001995 }
1996 }
1997 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001998
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001999 void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
2000 long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
2001 if (policy.mLastMaximumTimeToLock == timeMs) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002002 return;
2003 }
2004
2005 long ident = Binder.clearCallingIdentity();
2006 try {
2007 if (timeMs <= 0) {
2008 timeMs = Integer.MAX_VALUE;
2009 } else {
2010 // Make sure KEEP_SCREEN_ON is disabled, since that
2011 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07002012 Settings.Global.putInt(mContext.getContentResolver(),
2013 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002014 }
2015
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002016 policy.mLastMaximumTimeToLock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002017
2018 try {
Jeff Brown96307042012-07-27 15:51:34 -07002019 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002020 } catch (RemoteException e) {
2021 Slog.w(TAG, "Failure talking with power manager", e);
2022 }
2023 } finally {
2024 Binder.restoreCallingIdentity(ident);
2025 }
2026 }
2027
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002028 public long getMaximumTimeToLock(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002029 if (!mHasFeature) {
2030 return 0;
2031 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002032 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002033 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08002034 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002035
Dianne Hackborn254cb442010-01-27 19:23:59 -08002036 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002037 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08002038 return admin != null ? admin.maximumTimeToUnlock : time;
2039 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002040
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002041 DevicePolicyData policy = getUserData(userHandle);
2042 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08002043 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002044 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08002045 if (time == 0) {
2046 time = admin.maximumTimeToUnlock;
2047 } else if (admin.maximumTimeToUnlock != 0
2048 && time > admin.maximumTimeToUnlock) {
2049 time = admin.maximumTimeToUnlock;
2050 }
2051 }
2052 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08002053 }
2054 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002055
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002056 public void lockNow() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002057 if (!mHasFeature) {
2058 return;
2059 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002060 synchronized (this) {
2061 // This API can only be called by an active device admin,
2062 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08002063 getActiveAdminForCallerLocked(null,
2064 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002065 lockNowUnchecked();
2066 }
2067 }
2068
2069 private void lockNowUnchecked() {
2070 long ident = Binder.clearCallingIdentity();
2071 try {
2072 // Power off the display
2073 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
2074 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
2075 // Ensure the device is locked
Adam Cohenf7522022012-10-03 20:03:18 -07002076 getWindowManager().lockNow(null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002077 } catch (RemoteException e) {
2078 } finally {
2079 Binder.restoreCallingIdentity(ident);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002080 }
2081 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002082
Ben Komaloed48c8b2011-10-17 17:30:21 -07002083 private boolean isExtStorageEncrypted() {
2084 String state = SystemProperties.get("vold.decrypt");
2085 return !"".equals(state);
2086 }
2087
Maggie Benthallda51e682013-08-08 22:35:44 -04002088 public boolean installCaCert(byte[] certBuffer) throws RemoteException {
2089 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
2090 KeyChainConnection keyChainConnection = null;
2091 byte[] pemCert;
2092 try {
2093 X509Certificate cert = parseCert(certBuffer);
2094 pemCert = Credentials.convertToPem(cert);
2095 } catch (CertificateException ce) {
2096 Log.e(TAG, "Problem converting cert", ce);
2097 return false;
2098 } catch (IOException ioe) {
2099 Log.e(TAG, "Problem reading cert", ioe);
2100 return false;
2101 }
2102 try {
2103 keyChainConnection = KeyChain.bind(mContext);
2104 try {
2105 keyChainConnection.getService().installCaCertificate(pemCert);
2106 return true;
2107 } finally {
2108 if (keyChainConnection != null) {
2109 keyChainConnection.close();
2110 keyChainConnection = null;
2111 }
2112 }
2113 } catch (InterruptedException e1) {
2114 Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
2115 Thread.currentThread().interrupt();
2116 }
2117 return false;
2118 }
2119
2120 private static X509Certificate parseCert(byte[] certBuffer)
2121 throws CertificateException, IOException {
2122 CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
2123 return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
2124 certBuffer));
2125 }
2126
2127 public void uninstallCaCert(final byte[] certBuffer) {
2128 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
2129 TrustedCertificateStore certStore = new TrustedCertificateStore();
2130 String alias = null;
2131 try {
2132 X509Certificate cert = parseCert(certBuffer);
2133 alias = certStore.getCertificateAlias(cert);
2134 } catch (CertificateException ce) {
2135 Log.e(TAG, "Problem creating X509Certificate", ce);
2136 return;
2137 } catch (IOException ioe) {
2138 Log.e(TAG, "Problem reading certificate", ioe);
2139 return;
2140 }
2141 try {
2142 KeyChainConnection keyChainConnection = KeyChain.bind(mContext);
2143 IKeyChainService service = keyChainConnection.getService();
2144 try {
2145 service.deleteCaCertificate(alias);
2146 } catch (RemoteException e) {
2147 Log.e(TAG, "from CaCertUninstaller: ", e);
2148 } finally {
2149 keyChainConnection.close();
2150 keyChainConnection = null;
2151 }
2152 } catch (InterruptedException ie) {
2153 Log.w(TAG, "CaCertUninstaller: ", ie);
2154 Thread.currentThread().interrupt();
2155 }
2156 }
2157
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002158 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07002159 // If the SD card is encrypted and non-removable, we have to force a wipe.
2160 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
2161 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
2162
2163 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
2164 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07002165 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09002166 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07002167 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
2168 mWakeLock.acquire(10000);
2169 mContext.startService(intent);
2170 } else {
2171 try {
2172 RecoverySystem.rebootWipeUserData(mContext);
2173 } catch (IOException e) {
2174 Slog.w(TAG, "Failed requesting data wipe", e);
2175 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002176 }
2177 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002178
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002179 public void wipeData(int flags, final int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002180 if (!mHasFeature) {
2181 return;
2182 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002183 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002184 synchronized (this) {
2185 // This API can only be called by an active device admin,
2186 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08002187 getActiveAdminForCallerLocked(null,
2188 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002189 long ident = Binder.clearCallingIdentity();
2190 try {
Amith Yamasani32f07422012-11-16 15:09:13 -08002191 wipeDeviceOrUserLocked(flags, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002192 } finally {
2193 Binder.restoreCallingIdentity(ident);
2194 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08002195 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002196 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002197
Amith Yamasani32f07422012-11-16 15:09:13 -08002198 private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
2199 if (userHandle == UserHandle.USER_OWNER) {
2200 wipeDataLocked(flags);
2201 } else {
2202 lockNowUnchecked();
2203 mHandler.post(new Runnable() {
2204 public void run() {
2205 try {
Amith Yamasanie4cf7342012-12-17 11:12:09 -08002206 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
Amith Yamasani32f07422012-11-16 15:09:13 -08002207 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
2208 .removeUser(userHandle);
2209 } catch (RemoteException re) {
2210 // Shouldn't happen
2211 }
2212 }
2213 });
2214 }
2215 }
2216
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002217 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002218 if (!mHasFeature) {
2219 return;
2220 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002221 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002222 mContext.enforceCallingOrSelfPermission(
2223 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002224
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002225 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002226 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002227 if (admin == null) {
2228 try {
2229 result.sendResult(null);
2230 } catch (RemoteException e) {
2231 }
2232 return;
2233 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002234 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002235 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002236 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002237 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002238 @Override
2239 public void onReceive(Context context, Intent intent) {
2240 try {
2241 result.sendResult(getResultExtras(false));
2242 } catch (RemoteException e) {
2243 }
2244 }
2245 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002246 }
2247 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002248
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002249 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002250 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002251 if (!mHasFeature) {
2252 return;
2253 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002254 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002255 mContext.enforceCallingOrSelfPermission(
2256 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002257 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002258
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002259 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002260
Dianne Hackbornd6847842010-01-12 18:14:19 -08002261 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002262 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
2263 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
2264 || p.mActivePasswordUpperCase != uppercase
2265 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
2266 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002267 long ident = Binder.clearCallingIdentity();
2268 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002269 p.mActivePasswordQuality = quality;
2270 p.mActivePasswordLength = length;
2271 p.mActivePasswordLetters = letters;
2272 p.mActivePasswordLowerCase = lowercase;
2273 p.mActivePasswordUpperCase = uppercase;
2274 p.mActivePasswordNumeric = numbers;
2275 p.mActivePasswordSymbols = symbols;
2276 p.mActivePasswordNonLetter = nonletter;
2277 p.mFailedPasswordAttempts = 0;
2278 saveSettingsLocked(userHandle);
2279 updatePasswordExpirationsLocked(userHandle);
2280 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002281 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002282 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002283 } finally {
2284 Binder.restoreCallingIdentity(ident);
2285 }
2286 }
2287 }
2288 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002289
Andy Stadler043116a2010-11-29 17:43:32 -08002290 /**
2291 * Called any time the device password is updated. Resets all password expiration clocks.
2292 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002293 private void updatePasswordExpirationsLocked(int userHandle) {
2294 DevicePolicyData policy = getUserData(userHandle);
2295 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08002296 if (N > 0) {
2297 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002298 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08002299 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08002300 long timeout = admin.passwordExpirationTimeout;
2301 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
2302 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08002303 }
2304 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002305 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08002306 }
2307 }
2308
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002309 public void reportFailedPasswordAttempt(int userHandle) {
2310 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002311 mContext.enforceCallingOrSelfPermission(
2312 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002313
Dianne Hackbornd6847842010-01-12 18:14:19 -08002314 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002315 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002316 long ident = Binder.clearCallingIdentity();
2317 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002318 policy.mFailedPasswordAttempts++;
2319 saveSettingsLocked(userHandle);
Amith Yamasani44a01b72013-09-16 10:44:57 -07002320 if (mHasFeature) {
2321 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
2322 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
2323 wipeDeviceOrUserLocked(0, userHandle);
2324 }
2325 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
2326 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002327 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002328 } finally {
2329 Binder.restoreCallingIdentity(ident);
2330 }
2331 }
2332 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002333
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002334 public void reportSuccessfulPasswordAttempt(int userHandle) {
2335 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002336 mContext.enforceCallingOrSelfPermission(
2337 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002338
Dianne Hackbornd6847842010-01-12 18:14:19 -08002339 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002340 DevicePolicyData policy = getUserData(userHandle);
2341 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002342 long ident = Binder.clearCallingIdentity();
2343 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002344 policy.mFailedPasswordAttempts = 0;
2345 policy.mPasswordOwner = -1;
2346 saveSettingsLocked(userHandle);
Amith Yamasani44a01b72013-09-16 10:44:57 -07002347 if (mHasFeature) {
2348 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
2349 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
2350 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002351 } finally {
2352 Binder.restoreCallingIdentity(ident);
2353 }
2354 }
2355 }
2356 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002357
Oscar Montemayor69238c62010-08-03 10:51:06 -07002358 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002359 String exclusionList, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002360 if (!mHasFeature) {
2361 return null;
2362 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002363 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002364 synchronized(this) {
2365 if (who == null) {
2366 throw new NullPointerException("ComponentName is null");
2367 }
2368
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002369 // Only check if owner has set global proxy. We don't allow other users to set it.
2370 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002371 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2372 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2373
2374 // Scan through active admins and find if anyone has already
2375 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002376 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002377 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002378 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002379 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2380 // Another admin already sets the global proxy
2381 // Return it to the caller.
2382 return component;
2383 }
2384 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002385
2386 // If the user is not the owner, don't set the global proxy. Fail silently.
2387 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2388 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2389 + userHandle + " is not permitted.");
2390 return null;
2391 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002392 if (proxySpec == null) {
2393 admin.specifiesGlobalProxy = false;
2394 admin.globalProxySpec = null;
2395 admin.globalProxyExclusionList = null;
2396 } else {
2397
2398 admin.specifiesGlobalProxy = true;
2399 admin.globalProxySpec = proxySpec;
2400 admin.globalProxyExclusionList = exclusionList;
2401 }
2402
2403 // Reset the global proxy accordingly
2404 // Do this using system permissions, as apps cannot write to secure settings
2405 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002406 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002407 Binder.restoreCallingIdentity(origId);
2408 return null;
2409 }
2410 }
2411
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002412 public ComponentName getGlobalProxyAdmin(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002413 if (!mHasFeature) {
2414 return null;
2415 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002416 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002417 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002418 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002419 // Scan through active admins and find if anyone has already
2420 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002421 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002422 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002423 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002424 if (ap.specifiesGlobalProxy) {
2425 // Device admin sets the global proxy
2426 // Return it to the caller.
2427 return ap.info.getComponent();
2428 }
2429 }
2430 }
2431 // No device admin sets the global proxy.
2432 return null;
2433 }
2434
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002435 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2436 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002437 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002438 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002439 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002440 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002441 return;
2442 }
2443 }
2444 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002445 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002446 }
2447
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002448 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002449 if (exclusionList == null) {
2450 exclusionList = "";
2451 }
2452 if (proxySpec == null) {
2453 proxySpec = "";
2454 }
2455 // Remove white spaces
2456 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002457 String data[] = proxySpec.split(":");
2458 int proxyPort = 8080;
2459 if (data.length > 1) {
2460 try {
2461 proxyPort = Integer.parseInt(data[1]);
2462 } catch (NumberFormatException e) {}
2463 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002464 exclusionList = exclusionList.trim();
2465 ContentResolver res = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -07002466 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
2467 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2468 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwalt434203a2010-10-11 16:00:27 -07002469 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002470 }
2471
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002472 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002473 * Set the storage encryption request for a single admin. Returns the new total request
2474 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002475 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002476 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002477 if (!mHasFeature) {
2478 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2479 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002480 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002481 synchronized (this) {
2482 // Check for permissions
2483 if (who == null) {
2484 throw new NullPointerException("ComponentName is null");
2485 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002486 // Only owner can set storage encryption
2487 if (userHandle != UserHandle.USER_OWNER
2488 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2489 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2490 + UserHandle.getCallingUserId() + " is not permitted.");
2491 return 0;
2492 }
2493
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002494 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2495 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2496
Andy Stadler22dbfda2011-01-17 12:47:31 -08002497 // Quick exit: If the filesystem does not support encryption, we can exit early.
2498 if (!isEncryptionSupported()) {
2499 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2500 }
2501
2502 // (1) Record the value for the admin so it's sticky
2503 if (ap.encryptionRequested != encrypt) {
2504 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002505 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002506 }
2507
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002508 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002509 // (2) Compute "max" for all admins
2510 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002511 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002512 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002513 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002514 }
2515
2516 // Notify OS of new request
2517 setEncryptionRequested(newRequested);
2518
2519 // Return the new global request status
2520 return newRequested
2521 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2522 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002523 }
2524 }
2525
2526 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002527 * Get the current storage encryption request status for a given admin, or aggregate of all
2528 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002529 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002530 public boolean getStorageEncryption(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002531 if (!mHasFeature) {
2532 return false;
2533 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002534 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002535 synchronized (this) {
2536 // Check for permissions if a particular caller is specified
2537 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002538 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002539 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002540 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002541 }
2542
Andy Stadler22dbfda2011-01-17 12:47:31 -08002543 // If no particular caller is specified, return the aggregate set of requests.
2544 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002545 DevicePolicyData policy = getUserData(userHandle);
2546 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002547 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002548 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002549 return true;
2550 }
2551 }
2552 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002553 }
2554 }
2555
Andy Stadler22dbfda2011-01-17 12:47:31 -08002556 /**
2557 * Get the current encryption status of the device.
2558 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002559 public int getStorageEncryptionStatus(int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002560 if (!mHasFeature) {
2561 // Ok to return current status.
2562 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002563 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002564 return getEncryptionStatus();
2565 }
2566
2567 /**
2568 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2569 */
2570 private boolean isEncryptionSupported() {
2571 // Note, this can be implemented as
2572 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2573 // But is provided as a separate internal method if there's a faster way to do a
2574 // simple check for supported-or-not.
2575 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2576 }
2577
2578 /**
2579 * Hook to low-levels: Reporting the current status of encryption.
2580 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2581 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2582 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2583 */
2584 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002585 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2586 if ("encrypted".equalsIgnoreCase(status)) {
2587 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2588 } else if ("unencrypted".equalsIgnoreCase(status)) {
2589 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2590 } else {
2591 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2592 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002593 }
2594
2595 /**
2596 * Hook to low-levels: If needed, record the new admin setting for encryption.
2597 */
2598 private void setEncryptionRequested(boolean encrypt) {
2599 }
2600
Ben Komalo2447edd2011-05-09 16:05:33 -07002601 /**
2602 * The system property used to share the state of the camera. The native camera service
2603 * is expected to read this property and act accordingly.
2604 */
2605 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2606
2607 /**
2608 * Disables all device cameras according to the specified admin.
2609 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002610 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002611 if (!mHasFeature) {
2612 return;
2613 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002614 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002615 synchronized (this) {
2616 if (who == null) {
2617 throw new NullPointerException("ComponentName is null");
2618 }
2619 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2620 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2621 if (ap.disableCamera != disabled) {
2622 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002623 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002624 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002625 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002626 }
2627 }
2628
2629 /**
2630 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2631 * active admins.
2632 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002633 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002634 if (!mHasFeature) {
2635 return false;
2636 }
Ben Komalo2447edd2011-05-09 16:05:33 -07002637 synchronized (this) {
2638 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002639 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002640 return (admin != null) ? admin.disableCamera : false;
2641 }
2642
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002643 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002644 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002645 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002646 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002647 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002648 if (admin.disableCamera) {
2649 return true;
2650 }
2651 }
2652 return false;
2653 }
2654 }
2655
Jim Millerb8ec4702012-08-31 17:19:10 -07002656 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002657 * Selectively disable keyguard features.
Jim Millerb8ec4702012-08-31 17:19:10 -07002658 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002659 public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002660 if (!mHasFeature) {
2661 return;
2662 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002663 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002664 synchronized (this) {
2665 if (who == null) {
2666 throw new NullPointerException("ComponentName is null");
2667 }
2668 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Jim Miller48b9b0d2012-09-19 23:16:50 -07002669 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
2670 if (ap.disabledKeyguardFeatures != which) {
2671 ap.disabledKeyguardFeatures = which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002672 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002673 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002674 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002675 }
2676 }
2677
2678 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002679 * Gets the disabled state for features in keyguard for the given admin,
Jim Millerb8ec4702012-08-31 17:19:10 -07002680 * or the aggregate of all active admins if who is null.
2681 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002682 public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002683 if (!mHasFeature) {
2684 return 0;
2685 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002686 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002687 synchronized (this) {
2688 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002689 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002690 return (admin != null) ? admin.disabledKeyguardFeatures : 0;
Jim Millerb8ec4702012-08-31 17:19:10 -07002691 }
2692
Jim Miller48b9b0d2012-09-19 23:16:50 -07002693 // Determine which keyguard features are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002694 DevicePolicyData policy = getUserData(userHandle);
2695 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002696 int which = 0;
2697 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002698 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002699 which |= admin.disabledKeyguardFeatures;
Jim Millerb8ec4702012-08-31 17:19:10 -07002700 }
2701 return which;
2702 }
2703 }
2704
Amith Yamasani71e6c692013-03-24 17:39:28 -07002705 @Override
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002706 public boolean setDeviceOwner(String packageName, String ownerName) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002707 if (!mHasFeature) {
2708 return false;
2709 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002710 if (packageName == null
2711 || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
2712 throw new IllegalArgumentException("Invalid package name " + packageName
2713 + " for device owner");
2714 }
2715 synchronized (this) {
2716 if (mDeviceOwner == null && !isDeviceProvisioned()) {
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002717 mDeviceOwner = new DeviceOwner(packageName, ownerName);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002718 mDeviceOwner.writeOwnerFile();
2719 return true;
2720 } else {
2721 throw new IllegalStateException("Trying to set device owner to " + packageName
2722 + ", owner=" + mDeviceOwner.getPackageName()
2723 + ", device_provisioned=" + isDeviceProvisioned());
2724 }
2725 }
2726 }
2727
2728 @Override
2729 public boolean isDeviceOwner(String packageName) {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002730 if (!mHasFeature) {
2731 return false;
2732 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002733 synchronized (this) {
2734 return mDeviceOwner != null
2735 && mDeviceOwner.getPackageName().equals(packageName);
2736 }
2737 }
2738
2739 @Override
2740 public String getDeviceOwner() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002741 if (!mHasFeature) {
2742 return null;
2743 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002744 synchronized (this) {
2745 if (mDeviceOwner != null) {
2746 return mDeviceOwner.getPackageName();
2747 }
2748 }
2749 return null;
2750 }
2751
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002752 @Override
2753 public String getDeviceOwnerName() {
Amith Yamasani44a01b72013-09-16 10:44:57 -07002754 if (!mHasFeature) {
2755 return null;
2756 }
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002757 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
2758 synchronized (this) {
2759 if (mDeviceOwner != null) {
2760 return mDeviceOwner.getName();
2761 }
2762 }
2763 return null;
2764 }
2765
Amith Yamasani71e6c692013-03-24 17:39:28 -07002766 private boolean isDeviceProvisioned() {
2767 return Settings.Global.getInt(mContext.getContentResolver(),
2768 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
2769 }
2770
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002771 private void enforceCrossUserPermission(int userHandle) {
2772 if (userHandle < 0) {
2773 throw new IllegalArgumentException("Invalid userId " + userHandle);
2774 }
2775 final int callingUid = Binder.getCallingUid();
2776 if (userHandle == UserHandle.getUserId(callingUid)) return;
2777 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2778 mContext.enforceCallingOrSelfPermission(
2779 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2780 + " INTERACT_ACROSS_USERS_FULL permission");
2781 }
2782 }
2783
Amith Yamasani71e6c692013-03-24 17:39:28 -07002784 private void enableIfNecessary(String packageName, int userId) {
2785 try {
2786 IPackageManager ipm = AppGlobals.getPackageManager();
2787 ApplicationInfo ai = ipm.getApplicationInfo(packageName,
2788 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2789 userId);
2790 if (ai.enabledSetting
2791 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
2792 ipm.setApplicationEnabledSetting(packageName,
2793 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002794 PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
Amith Yamasani71e6c692013-03-24 17:39:28 -07002795 }
2796 } catch (RemoteException e) {
2797 }
2798 }
2799
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002800 @Override
2801 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2802 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2803 != PackageManager.PERMISSION_GRANTED) {
2804
2805 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2806 + Binder.getCallingPid()
2807 + ", uid=" + Binder.getCallingUid());
2808 return;
2809 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002810
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002811 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002812
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002813 synchronized (this) {
2814 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002815
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002816 int userCount = mUserData.size();
2817 for (int u = 0; u < userCount; u++) {
2818 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2819 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2820 final int N = policy.mAdminList.size();
2821 for (int i=0; i<N; i++) {
2822 ActiveAdmin ap = policy.mAdminList.get(i);
2823 if (ap != null) {
2824 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2825 pw.println(":");
2826 ap.dump(" ", pw);
2827 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002828 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002829
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002830 pw.println(" ");
2831 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2832 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002833 }
2834 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002835
2836 static class DeviceOwner {
2837 private static final String DEVICE_OWNER_XML = "device_owner.xml";
2838 private static final String TAG_DEVICE_OWNER = "device-owner";
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002839 private static final String ATTR_NAME = "name";
Amith Yamasani71e6c692013-03-24 17:39:28 -07002840 private static final String ATTR_PACKAGE = "package";
2841 private String mPackageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002842 private String mOwnerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002843
2844 DeviceOwner() {
2845 readOwnerFile();
2846 }
2847
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002848 DeviceOwner(String packageName, String ownerName) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07002849 this.mPackageName = packageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002850 this.mOwnerName = ownerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002851 }
2852
2853 static boolean isRegistered() {
2854 return new File(Environment.getSystemSecureDirectory(),
2855 DEVICE_OWNER_XML).exists();
2856 }
2857
2858 String getPackageName() {
2859 return mPackageName;
2860 }
2861
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002862 String getName() {
2863 return mOwnerName;
2864 }
2865
Amith Yamasani71e6c692013-03-24 17:39:28 -07002866 static boolean isInstalled(String packageName, PackageManager pm) {
2867 try {
2868 PackageInfo pi;
2869 if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
2870 if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
2871 return true;
2872 }
2873 }
2874 } catch (NameNotFoundException nnfe) {
2875 Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
2876 }
2877 return false;
2878 }
2879
2880 void readOwnerFile() {
2881 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2882 DEVICE_OWNER_XML));
2883 try {
2884 FileInputStream input = file.openRead();
2885 XmlPullParser parser = Xml.newPullParser();
2886 parser.setInput(input, null);
2887 int type;
2888 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2889 && type != XmlPullParser.START_TAG) {
2890 }
2891 String tag = parser.getName();
2892 if (!TAG_DEVICE_OWNER.equals(tag)) {
2893 throw new XmlPullParserException(
2894 "Device Owner file does not start with device-owner tag: found " + tag);
2895 }
2896 mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002897 mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002898 input.close();
2899 } catch (XmlPullParserException xppe) {
2900 Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
2901 } catch (IOException ioe) {
2902 Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
2903 }
2904 }
2905
2906 void writeOwnerFile() {
2907 synchronized (this) {
2908 writeOwnerFileLocked();
2909 }
2910 }
2911
2912 private void writeOwnerFileLocked() {
2913 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2914 DEVICE_OWNER_XML));
2915 try {
2916 FileOutputStream output = file.startWrite();
2917 XmlSerializer out = new FastXmlSerializer();
2918 out.setOutput(output, "utf-8");
2919 out.startDocument(null, true);
2920 out.startTag(null, TAG_DEVICE_OWNER);
2921 out.attribute(null, ATTR_PACKAGE, mPackageName);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002922 if (mOwnerName != null) {
2923 out.attribute(null, ATTR_NAME, mOwnerName);
2924 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002925 out.endTag(null, TAG_DEVICE_OWNER);
2926 out.endDocument();
2927 out.flush();
2928 file.finishWrite(output);
2929 } catch (IOException ioe) {
2930 Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
2931 }
2932 }
2933 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002934}