blob: 7e833965c38a56bf09ea1098a5fce155cef67de3 [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
Dianne Hackborn42499172010-10-15 18:45:07 -070021import com.android.internal.os.storage.ExternalStorageFormatter;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080022import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070023import com.android.internal.util.JournaledFile;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080024import com.android.internal.util.XmlUtils;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080025import com.android.internal.widget.LockPatternUtils;
Maggie Benthallda51e682013-08-08 22:35:44 -040026import com.android.org.conscrypt.TrustedCertificateStore;
Dianne Hackbornd6847842010-01-12 18:14:19 -080027
28import org.xmlpull.v1.XmlPullParser;
29import org.xmlpull.v1.XmlPullParserException;
30import org.xmlpull.v1.XmlSerializer;
31
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080032import android.app.Activity;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070033import android.app.ActivityManagerNative;
Jim Millera4e28d12010-11-08 16:15:47 -080034import android.app.AlarmManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070035import android.app.AppGlobals;
Jim Millera4e28d12010-11-08 16:15:47 -080036import android.app.PendingIntent;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080037import android.app.admin.DeviceAdminInfo;
38import android.app.admin.DeviceAdminReceiver;
39import android.app.admin.DevicePolicyManager;
40import android.app.admin.IDevicePolicyManager;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080041import android.content.BroadcastReceiver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080042import android.content.ComponentName;
Oscar Montemayor69238c62010-08-03 10:51:06 -070043import android.content.ContentResolver;
Dianne Hackbornd6847842010-01-12 18:14:19 -080044import android.content.Context;
45import android.content.Intent;
Jim Millera4e28d12010-11-08 16:15:47 -080046import android.content.IntentFilter;
Amith Yamasani71e6c692013-03-24 17:39:28 -070047import android.content.pm.ApplicationInfo;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070048import android.content.pm.IPackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070049import android.content.pm.PackageInfo;
Dianne Hackbornd6847842010-01-12 18:14:19 -080050import android.content.pm.PackageManager;
Amith Yamasani71e6c692013-03-24 17:39:28 -070051import android.content.pm.Signature;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080052import android.content.pm.PackageManager.NameNotFoundException;
Andy Stadler1f35d482010-11-19 15:39:41 -080053import android.content.pm.ResolveInfo;
Amith Yamasani71e6c692013-03-24 17:39:28 -070054import android.net.Uri;
Maggie Benthallda51e682013-08-08 22:35:44 -040055import android.os.AsyncTask;
Dianne Hackbornd6847842010-01-12 18:14:19 -080056import android.os.Binder;
Adam Cohenf7522022012-10-03 20:03:18 -070057import android.os.Bundle;
Ben Komaloed48c8b2011-10-17 17:30:21 -070058import android.os.Environment;
Jim Millera4e28d12010-11-08 16:15:47 -080059import android.os.Handler;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080060import android.os.IBinder;
61import android.os.IPowerManager;
Dianne Hackborn42499172010-10-15 18:45:07 -070062import android.os.PowerManager;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070063import android.os.Process;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080064import android.os.RecoverySystem;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -080065import android.os.RemoteCallback;
Dianne Hackborndf83afa2010-01-20 13:37:26 -080066import android.os.RemoteException;
67import android.os.ServiceManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080068import android.os.SystemClock;
Andy Stadler0fe45de2011-01-20 16:35:09 -080069import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070070import android.os.UserHandle;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070071import android.os.UserManager;
Oscar Montemayor69238c62010-08-03 10:51:06 -070072import android.provider.Settings;
Maggie Benthallda51e682013-08-08 22:35:44 -040073import android.security.Credentials;
74import android.security.IKeyChainService;
75import android.security.KeyChain;
76import android.security.KeyChain.KeyChainConnection;
Amith Yamasani71e6c692013-03-24 17:39:28 -070077import android.util.AtomicFile;
Maggie Benthallda51e682013-08-08 22:35:44 -040078import android.util.Log;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080079import android.util.PrintWriterPrinter;
80import android.util.Printer;
Andy Stadler1f35d482010-11-19 15:39:41 -080081import android.util.Slog;
Amith Yamasani599dd7c2012-09-14 23:20:08 -070082import android.util.SparseArray;
Dianne Hackbornd6847842010-01-12 18:14:19 -080083import android.util.Xml;
Jim Miller93c518e2012-01-17 15:55:31 -080084import android.view.IWindowManager;
Dianne Hackborn254cb442010-01-27 19:23:59 -080085import android.view.WindowManagerPolicy;
Dianne Hackbornd6847842010-01-12 18:14:19 -080086
Maggie Benthallda51e682013-08-08 22:35:44 -040087import java.io.ByteArrayInputStream;
Dianne Hackbornd6847842010-01-12 18:14:19 -080088import java.io.File;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080089import java.io.FileDescriptor;
Dianne Hackbornd6847842010-01-12 18:14:19 -080090import java.io.FileInputStream;
Dianne Hackborncef65ee2010-09-30 18:27:22 -070091import java.io.FileNotFoundException;
Dianne Hackbornd6847842010-01-12 18:14:19 -080092import java.io.FileOutputStream;
93import java.io.IOException;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -080094import java.io.PrintWriter;
Maggie Benthallda51e682013-08-08 22:35:44 -040095import java.security.KeyStore.TrustedCertificateEntry;
96import java.security.cert.CertificateException;
97import java.security.cert.CertificateFactory;
98import java.security.cert.X509Certificate;
Jim Millera4e28d12010-11-08 16:15:47 -080099import java.text.DateFormat;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800100import java.util.ArrayList;
Maggie Benthallda51e682013-08-08 22:35:44 -0400101import java.util.Arrays;
102import java.util.Collection;
Jim Millera4e28d12010-11-08 16:15:47 -0800103import java.util.Date;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800104import java.util.HashMap;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800105import java.util.List;
Oscar Montemayor69238c62010-08-03 10:51:06 -0700106import java.util.Set;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800107
108/**
109 * Implementation of the device policy APIs.
110 */
111public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700112
Jim Miller6b857682011-02-16 16:27:41 -0800113 private static final String TAG = "DevicePolicyManagerService";
Jim Millera4e28d12010-11-08 16:15:47 -0800114
Amith Yamasani71e6c692013-03-24 17:39:28 -0700115 private static final String DEVICE_POLICIES_XML = "device_policies.xml";
116
Jim Miller6b857682011-02-16 16:27:41 -0800117 private static final int REQUEST_EXPIRE_PASSWORD = 5571;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700118
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700119 private static final long MS_PER_DAY = 86400 * 1000;
120
121 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
Jim Millera4e28d12010-11-08 16:15:47 -0800122
123 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
124 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
125
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700126 private static final boolean DBG = false;
Jim Millera4e28d12010-11-08 16:15:47 -0800127
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800128 final Context mContext;
Dianne Hackborn42499172010-10-15 18:45:07 -0700129 final PowerManager.WakeLock mWakeLock;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800130
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800131 IPowerManager mIPowerManager;
Jim Miller93c518e2012-01-17 15:55:31 -0800132 IWindowManager mIWindowManager;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700133
Amith Yamasani71e6c692013-03-24 17:39:28 -0700134 private DeviceOwner mDeviceOwner;
135
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700136 public static class DevicePolicyData {
137 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
138 int mActivePasswordLength = 0;
139 int mActivePasswordUpperCase = 0;
140 int mActivePasswordLowerCase = 0;
141 int mActivePasswordLetters = 0;
142 int mActivePasswordNumeric = 0;
143 int mActivePasswordSymbols = 0;
144 int mActivePasswordNonLetter = 0;
145 int mFailedPasswordAttempts = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700146
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700147 int mUserHandle;;
148 int mPasswordOwner = -1;
149 long mLastMaximumTimeToLock = -1;
150
151 final HashMap<ComponentName, ActiveAdmin> mAdminMap
152 = new HashMap<ComponentName, ActiveAdmin>();
153 final ArrayList<ActiveAdmin> mAdminList
154 = new ArrayList<ActiveAdmin>();
155
156 public DevicePolicyData(int userHandle) {
157 mUserHandle = userHandle;
158 }
159 }
160
161 final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
162
Jim Millera4e28d12010-11-08 16:15:47 -0800163 Handler mHandler = new Handler();
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700164
Jim Millera4e28d12010-11-08 16:15:47 -0800165 BroadcastReceiver mReceiver = new BroadcastReceiver() {
166 @Override
167 public void onReceive(Context context, Intent intent) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700168 final String action = intent.getAction();
169 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
170 getSendingUserId());
Jim Millera4e28d12010-11-08 16:15:47 -0800171 if (Intent.ACTION_BOOT_COMPLETED.equals(action)
172 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800173 if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
174 + action + " for user " + userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800175 mHandler.post(new Runnable() {
176 public void run() {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700177 handlePasswordExpirationNotification(getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -0800178 }
179 });
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700180 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
181 removeUserData(userHandle);
182 } else if (Intent.ACTION_USER_STARTED.equals(action)
183 || Intent.ACTION_PACKAGE_CHANGED.equals(action)
184 || Intent.ACTION_PACKAGE_REMOVED.equals(action)
185 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
186
187 if (Intent.ACTION_USER_STARTED.equals(action)) {
188 // Reset the policy data
189 synchronized (DevicePolicyManagerService.this) {
190 mUserData.remove(userHandle);
191 }
192 }
193
194 handlePackagesChanged(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800195 }
196 }
197 };
198
Dianne Hackbornd6847842010-01-12 18:14:19 -0800199 static class ActiveAdmin {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800200 final DeviceAdminInfo info;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700201
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800202 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700203
204 static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
205 int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
206
207 static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
208 int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
209
210 static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
211 int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
212
213 static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
214 int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
215
216 static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
Dianne Hackborn2a108402011-05-26 11:45:00 -0700217 int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700218
219 static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
220 int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
221
222 static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
223 int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
224
225 static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
226 int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
227
228 static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
229 long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
230
231 static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
232 int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
233
234 static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
235 long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
236
237 static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
238 long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
239
Jim Miller48b9b0d2012-09-19 23:16:50 -0700240 static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
241 int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
Jim Millerb8ec4702012-08-31 17:19:10 -0700242
Andy Stadler22dbfda2011-01-17 12:47:31 -0800243 boolean encryptionRequested = false;
Ben Komalo2447edd2011-05-09 16:05:33 -0700244 boolean disableCamera = false;
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700245
Oscar Montemayor69238c62010-08-03 10:51:06 -0700246 // TODO: review implementation decisions with frameworks team
247 boolean specifiesGlobalProxy = false;
248 String globalProxySpec = null;
249 String globalProxyExclusionList = null;
250
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800251 ActiveAdmin(DeviceAdminInfo _info) {
252 info = _info;
253 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700254
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800255 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700256
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700257 public UserHandle getUserHandle() {
258 return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
259 }
260
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800261 void writeToXml(XmlSerializer out)
262 throws IllegalArgumentException, IllegalStateException, IOException {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800263 out.startTag(null, "policies");
264 info.writePoliciesToXml(out);
265 out.endTag(null, "policies");
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800266 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
267 out.startTag(null, "password-quality");
268 out.attribute(null, "value", Integer.toString(passwordQuality));
269 out.endTag(null, "password-quality");
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700270 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800271 out.startTag(null, "min-password-length");
272 out.attribute(null, "value", Integer.toString(minimumPasswordLength));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700273 out.endTag(null, "min-password-length");
274 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700275 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700276 out.startTag(null, "password-history-length");
277 out.attribute(null, "value", Integer.toString(passwordHistoryLength));
278 out.endTag(null, "password-history-length");
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800279 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700280 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700281 out.startTag(null, "min-password-uppercase");
282 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
283 out.endTag(null, "min-password-uppercase");
284 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700285 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700286 out.startTag(null, "min-password-lowercase");
287 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
288 out.endTag(null, "min-password-lowercase");
289 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700290 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700291 out.startTag(null, "min-password-letters");
292 out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
293 out.endTag(null, "min-password-letters");
294 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700295 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700296 out.startTag(null, "min-password-numeric");
297 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
298 out.endTag(null, "min-password-numeric");
299 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700300 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700301 out.startTag(null, "min-password-symbols");
302 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
303 out.endTag(null, "min-password-symbols");
304 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700305 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700306 out.startTag(null, "min-password-nonletter");
307 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
308 out.endTag(null, "min-password-nonletter");
309 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800310 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700311 if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800312 out.startTag(null, "max-time-to-unlock");
313 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
314 out.endTag(null, "max-time-to-unlock");
315 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700316 if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800317 out.startTag(null, "max-failed-password-wipe");
318 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
319 out.endTag(null, "max-failed-password-wipe");
320 }
Oscar Montemayor69238c62010-08-03 10:51:06 -0700321 if (specifiesGlobalProxy) {
322 out.startTag(null, "specifies-global-proxy");
323 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
324 out.endTag(null, "specifies_global_proxy");
325 if (globalProxySpec != null) {
326 out.startTag(null, "global-proxy-spec");
327 out.attribute(null, "value", globalProxySpec);
328 out.endTag(null, "global-proxy-spec");
329 }
330 if (globalProxyExclusionList != null) {
331 out.startTag(null, "global-proxy-exclusion-list");
332 out.attribute(null, "value", globalProxyExclusionList);
333 out.endTag(null, "global-proxy-exclusion-list");
334 }
335 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700336 if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
Jim Millera4e28d12010-11-08 16:15:47 -0800337 out.startTag(null, "password-expiration-timeout");
338 out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
339 out.endTag(null, "password-expiration-timeout");
340 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700341 if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
Jim Millera4e28d12010-11-08 16:15:47 -0800342 out.startTag(null, "password-expiration-date");
343 out.attribute(null, "value", Long.toString(passwordExpirationDate));
344 out.endTag(null, "password-expiration-date");
345 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800346 if (encryptionRequested) {
347 out.startTag(null, "encryption-requested");
348 out.attribute(null, "value", Boolean.toString(encryptionRequested));
349 out.endTag(null, "encryption-requested");
350 }
Ben Komalo2447edd2011-05-09 16:05:33 -0700351 if (disableCamera) {
352 out.startTag(null, "disable-camera");
353 out.attribute(null, "value", Boolean.toString(disableCamera));
354 out.endTag(null, "disable-camera");
355 }
Jim Miller48b9b0d2012-09-19 23:16:50 -0700356 if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
357 out.startTag(null, "disable-keyguard-features");
358 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
359 out.endTag(null, "disable-keyguard-features");
Jim Millerb8ec4702012-08-31 17:19:10 -0700360 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800361 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700362
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800363 void readFromXml(XmlPullParser parser)
364 throws XmlPullParserException, IOException {
365 int outerDepth = parser.getDepth();
366 int type;
367 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
368 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
369 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
370 continue;
371 }
372 String tag = parser.getName();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800373 if ("policies".equals(tag)) {
374 info.readPoliciesFromXml(parser);
375 } else if ("password-quality".equals(tag)) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -0800376 passwordQuality = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800377 parser.getAttributeValue(null, "value"));
378 } else if ("min-password-length".equals(tag)) {
379 minimumPasswordLength = Integer.parseInt(
380 parser.getAttributeValue(null, "value"));
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700381 } else if ("password-history-length".equals(tag)) {
382 passwordHistoryLength = Integer.parseInt(
383 parser.getAttributeValue(null, "value"));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700384 } else if ("min-password-uppercase".equals(tag)) {
385 minimumPasswordUpperCase = Integer.parseInt(
386 parser.getAttributeValue(null, "value"));
387 } else if ("min-password-lowercase".equals(tag)) {
388 minimumPasswordLowerCase = Integer.parseInt(
389 parser.getAttributeValue(null, "value"));
390 } else if ("min-password-letters".equals(tag)) {
391 minimumPasswordLetters = Integer.parseInt(
392 parser.getAttributeValue(null, "value"));
393 } else if ("min-password-numeric".equals(tag)) {
394 minimumPasswordNumeric = Integer.parseInt(
395 parser.getAttributeValue(null, "value"));
396 } else if ("min-password-symbols".equals(tag)) {
397 minimumPasswordSymbols = Integer.parseInt(
398 parser.getAttributeValue(null, "value"));
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700399 } else if ("min-password-nonletter".equals(tag)) {
400 minimumPasswordNonLetter = Integer.parseInt(
401 parser.getAttributeValue(null, "value"));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800402 } else if ("max-time-to-unlock".equals(tag)) {
403 maximumTimeToUnlock = Long.parseLong(
404 parser.getAttributeValue(null, "value"));
405 } else if ("max-failed-password-wipe".equals(tag)) {
406 maximumFailedPasswordsForWipe = Integer.parseInt(
407 parser.getAttributeValue(null, "value"));
Oscar Montemayor69238c62010-08-03 10:51:06 -0700408 } else if ("specifies-global-proxy".equals(tag)) {
Andy Stadler22dbfda2011-01-17 12:47:31 -0800409 specifiesGlobalProxy = Boolean.parseBoolean(
Oscar Montemayor69238c62010-08-03 10:51:06 -0700410 parser.getAttributeValue(null, "value"));
411 } else if ("global-proxy-spec".equals(tag)) {
412 globalProxySpec =
413 parser.getAttributeValue(null, "value");
414 } else if ("global-proxy-exclusion-list".equals(tag)) {
415 globalProxyExclusionList =
416 parser.getAttributeValue(null, "value");
Jim Millera4e28d12010-11-08 16:15:47 -0800417 } else if ("password-expiration-timeout".equals(tag)) {
418 passwordExpirationTimeout = Long.parseLong(
419 parser.getAttributeValue(null, "value"));
420 } else if ("password-expiration-date".equals(tag)) {
421 passwordExpirationDate = Long.parseLong(
422 parser.getAttributeValue(null, "value"));
Andy Stadler22dbfda2011-01-17 12:47:31 -0800423 } else if ("encryption-requested".equals(tag)) {
424 encryptionRequested = Boolean.parseBoolean(
425 parser.getAttributeValue(null, "value"));
Ben Komalo2447edd2011-05-09 16:05:33 -0700426 } else if ("disable-camera".equals(tag)) {
427 disableCamera = Boolean.parseBoolean(
428 parser.getAttributeValue(null, "value"));
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700429 } else if ("disable-keyguard-features".equals(tag)) {
430 disabledKeyguardFeatures = Integer.parseInt(
431 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800432 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700433 Slog.w(TAG, "Unknown admin tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800434 }
435 XmlUtils.skipCurrentTag(parser);
436 }
437 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700438
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800439 void dump(String prefix, PrintWriter pw) {
440 pw.print(prefix); pw.print("uid="); pw.println(getUid());
441 pw.print(prefix); pw.println("policies:");
442 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
443 if (pols != null) {
444 for (int i=0; i<pols.size(); i++) {
445 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
446 }
447 }
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700448 pw.print(prefix); pw.print("passwordQuality=0x");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700449 pw.println(Integer.toHexString(passwordQuality));
450 pw.print(prefix); pw.print("minimumPasswordLength=");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800451 pw.println(minimumPasswordLength);
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700452 pw.print(prefix); pw.print("passwordHistoryLength=");
453 pw.println(passwordHistoryLength);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700454 pw.print(prefix); pw.print("minimumPasswordUpperCase=");
455 pw.println(minimumPasswordUpperCase);
456 pw.print(prefix); pw.print("minimumPasswordLowerCase=");
457 pw.println(minimumPasswordLowerCase);
458 pw.print(prefix); pw.print("minimumPasswordLetters=");
459 pw.println(minimumPasswordLetters);
460 pw.print(prefix); pw.print("minimumPasswordNumeric=");
461 pw.println(minimumPasswordNumeric);
462 pw.print(prefix); pw.print("minimumPasswordSymbols=");
463 pw.println(minimumPasswordSymbols);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700464 pw.print(prefix); pw.print("minimumPasswordNonLetter=");
465 pw.println(minimumPasswordNonLetter);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800466 pw.print(prefix); pw.print("maximumTimeToUnlock=");
467 pw.println(maximumTimeToUnlock);
468 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
469 pw.println(maximumFailedPasswordsForWipe);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700470 pw.print(prefix); pw.print("specifiesGlobalProxy=");
471 pw.println(specifiesGlobalProxy);
Jim Millera4e28d12010-11-08 16:15:47 -0800472 pw.print(prefix); pw.print("passwordExpirationTimeout=");
473 pw.println(passwordExpirationTimeout);
474 pw.print(prefix); pw.print("passwordExpirationDate=");
475 pw.println(passwordExpirationDate);
Oscar Montemayor69238c62010-08-03 10:51:06 -0700476 if (globalProxySpec != null) {
477 pw.print(prefix); pw.print("globalProxySpec=");
478 pw.println(globalProxySpec);
479 }
480 if (globalProxyExclusionList != null) {
481 pw.print(prefix); pw.print("globalProxyEclusionList=");
482 pw.println(globalProxyExclusionList);
483 }
Andy Stadler22dbfda2011-01-17 12:47:31 -0800484 pw.print(prefix); pw.print("encryptionRequested=");
485 pw.println(encryptionRequested);
Ben Komalo2447edd2011-05-09 16:05:33 -0700486 pw.print(prefix); pw.print("disableCamera=");
487 pw.println(disableCamera);
Amith Yamasani7077b3c2012-10-04 10:28:50 -0700488 pw.print(prefix); pw.print("disabledKeyguardFeatures=");
489 pw.println(disabledKeyguardFeatures);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800490 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800491 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700492
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700493 private void handlePackagesChanged(int userHandle) {
494 boolean removed = false;
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800495 if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700496 DevicePolicyData policy = getUserData(userHandle);
497 IPackageManager pm = AppGlobals.getPackageManager();
498 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
499 ActiveAdmin aa = policy.mAdminList.get(i);
500 try {
501 if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
502 || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
503 removed = true;
504 policy.mAdminList.remove(i);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800505 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700506 } catch (RemoteException re) {
507 // Shouldn't happen
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800508 }
509 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700510 if (removed) {
511 validatePasswordOwnerLocked(policy);
512 syncDeviceCapabilitiesLocked(policy);
513 saveSettingsLocked(policy.mUserHandle);
514 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800515 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700516
Dianne Hackbornd6847842010-01-12 18:14:19 -0800517 /**
518 * Instantiates the service.
519 */
520 public DevicePolicyManagerService(Context context) {
521 mContext = context;
Dianne Hackborn42499172010-10-15 18:45:07 -0700522 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
523 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
Jim Millera4e28d12010-11-08 16:15:47 -0800524 IntentFilter filter = new IntentFilter();
525 filter.addAction(Intent.ACTION_BOOT_COMPLETED);
526 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700527 filter.addAction(Intent.ACTION_USER_REMOVED);
528 filter.addAction(Intent.ACTION_USER_STARTED);
529 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
530 filter = new IntentFilter();
531 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
532 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
533 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Amith Yamasani71e6c692013-03-24 17:39:28 -0700534 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700535 filter.addDataScheme("package");
536 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
537 }
538
539 /**
540 * Creates and loads the policy data from xml.
541 * @param userHandle the user for whom to load the policy data
542 * @return
543 */
544 DevicePolicyData getUserData(int userHandle) {
545 synchronized (this) {
546 DevicePolicyData policy = mUserData.get(userHandle);
547 if (policy == null) {
548 policy = new DevicePolicyData(userHandle);
549 mUserData.append(userHandle, policy);
550 loadSettingsLocked(policy, userHandle);
551 }
552 return policy;
553 }
554 }
555
556 void removeUserData(int userHandle) {
557 synchronized (this) {
558 if (userHandle == UserHandle.USER_OWNER) {
559 Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
560 return;
561 }
562 DevicePolicyData policy = mUserData.get(userHandle);
563 if (policy != null) {
564 mUserData.remove(userHandle);
565 }
566 File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
567 DEVICE_POLICIES_XML);
568 policyFile.delete();
569 Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
570 }
Jim Millera4e28d12010-11-08 16:15:47 -0800571 }
572
Amith Yamasani71e6c692013-03-24 17:39:28 -0700573 void loadDeviceOwner() {
574 synchronized (this) {
575 if (DeviceOwner.isRegistered()) {
576 mDeviceOwner = new DeviceOwner();
577 }
578 }
579 }
580
Andy Stadler043116a2010-11-29 17:43:32 -0800581 /**
582 * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
583 * reminders. Clears alarm if no expirations are configured.
584 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700585 protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
586 final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
Jim Millera4e28d12010-11-08 16:15:47 -0800587 final long now = System.currentTimeMillis();
588 final long timeToExpire = expiration - now;
589 final long alarmTime;
Andy Stadler043116a2010-11-29 17:43:32 -0800590 if (expiration == 0) {
591 // No expirations are currently configured: Cancel alarm.
592 alarmTime = 0;
593 } else if (timeToExpire <= 0) {
594 // The password has already expired: Repeat every 24 hours.
Jim Millera4e28d12010-11-08 16:15:47 -0800595 alarmTime = now + MS_PER_DAY;
Andy Stadler043116a2010-11-29 17:43:32 -0800596 } else {
597 // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
598 // the expiration time.
599 long alarmInterval = timeToExpire % MS_PER_DAY;
600 if (alarmInterval == 0) {
601 alarmInterval = MS_PER_DAY;
602 }
603 alarmTime = now + alarmInterval;
Jim Millera4e28d12010-11-08 16:15:47 -0800604 }
605
Andy Stadler1f35d482010-11-19 15:39:41 -0800606 long token = Binder.clearCallingIdentity();
607 try {
608 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700609 PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
Andy Stadler1f35d482010-11-19 15:39:41 -0800610 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700611 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
612 new UserHandle(policy.mUserHandle));
Andy Stadler1f35d482010-11-19 15:39:41 -0800613 am.cancel(pi);
Andy Stadler043116a2010-11-29 17:43:32 -0800614 if (alarmTime != 0) {
615 am.set(AlarmManager.RTC, alarmTime, pi);
616 }
Andy Stadler1f35d482010-11-19 15:39:41 -0800617 } finally {
618 Binder.restoreCallingIdentity(token);
619 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800620 }
621
Dianne Hackborndf83afa2010-01-20 13:37:26 -0800622 private IPowerManager getIPowerManager() {
623 if (mIPowerManager == null) {
624 IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
625 mIPowerManager = IPowerManager.Stub.asInterface(b);
626 }
627 return mIPowerManager;
628 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700629
Jim Miller93c518e2012-01-17 15:55:31 -0800630 private IWindowManager getWindowManager() {
631 if (mIWindowManager == null) {
632 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
633 mIWindowManager = IWindowManager.Stub.asInterface(b);
634 }
635 return mIWindowManager;
636 }
637
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700638 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
639 ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800640 if (admin != null
641 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
642 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
643 return admin;
644 }
645 return null;
646 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700647
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800648 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
649 throws SecurityException {
Dianne Hackborn254cb442010-01-27 19:23:59 -0800650 final int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700651 final int userHandle = UserHandle.getUserId(callingUid);
652 final DevicePolicyData policy = getUserData(userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800653 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700654 ActiveAdmin admin = policy.mAdminMap.get(who);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800655 if (admin == null) {
656 throw new SecurityException("No active admin " + who);
657 }
658 if (admin.getUid() != callingUid) {
659 throw new SecurityException("Admin " + who + " is not owned by uid "
660 + Binder.getCallingUid());
661 }
662 if (!admin.info.usesPolicy(reqPolicy)) {
663 throw new SecurityException("Admin " + admin.info.getComponent()
664 + " did not specify uses-policy for: "
665 + admin.info.getTagForPolicy(reqPolicy));
666 }
667 return admin;
668 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700669 final int N = policy.mAdminList.size();
Dianne Hackborn254cb442010-01-27 19:23:59 -0800670 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700671 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn254cb442010-01-27 19:23:59 -0800672 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
673 return admin;
674 }
675 }
676 throw new SecurityException("No active admin owned by uid "
677 + Binder.getCallingUid() + " for policy #" + reqPolicy);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800678 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800679 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700680
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800681 void sendAdminCommandLocked(ActiveAdmin admin, String action) {
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700682 sendAdminCommandLocked(admin, action, null);
683 }
684
685 void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800686 Intent intent = new Intent(action);
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800687 intent.setComponent(admin.info.getComponent());
Jim Millera4e28d12010-11-08 16:15:47 -0800688 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
689 intent.putExtra("expiration", admin.passwordExpirationDate);
690 }
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700691 if (result != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700692 mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700693 null, result, mHandler, Activity.RESULT_OK, null, null);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700694 } else {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700695 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700696 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800697 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700698
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700699 void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
700 final DevicePolicyData policy = getUserData(userHandle);
701 final int count = policy.mAdminList.size();
702 if (count > 0) {
703 for (int i = 0; i < count; i++) {
704 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800705 if (admin.info.usesPolicy(reqPolicy)) {
706 sendAdminCommandLocked(admin, action);
707 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800708 }
Dianne Hackborn4141d032010-01-21 16:29:00 -0800709 }
710 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700711
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700712 void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
713 final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800714 if (admin != null) {
715 sendAdminCommandLocked(admin,
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700716 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
717 new BroadcastReceiver() {
718 @Override
719 public void onReceive(Context context, Intent intent) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -0700720 synchronized (DevicePolicyManagerService.this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700721 int userHandle = admin.getUserHandle().getIdentifier();
722 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700723 boolean doProxyCleanup = admin.info.usesPolicy(
724 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700725 policy.mAdminList.remove(admin);
726 policy.mAdminMap.remove(adminReceiver);
727 validatePasswordOwnerLocked(policy);
728 syncDeviceCapabilitiesLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700729 if (doProxyCleanup) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700730 resetGlobalProxyLocked(getUserData(userHandle));
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700731 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700732 saveSettingsLocked(userHandle);
733 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd998acb32011-05-25 10:48:28 -0700734 }
735 }
736 });
Dianne Hackbornd6847842010-01-12 18:14:19 -0800737 }
738 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700739
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700740 public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
741 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800742 Intent resolveIntent = new Intent();
743 resolveIntent.setComponent(adminName);
744 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
Amith Yamasani71e6c692013-03-24 17:39:28 -0700745 resolveIntent,
746 PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
747 userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800748 if (infos == null || infos.size() <= 0) {
749 throw new IllegalArgumentException("Unknown admin: " + adminName);
750 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700751
Dianne Hackbornd6847842010-01-12 18:14:19 -0800752 try {
753 return new DeviceAdminInfo(mContext, infos.get(0));
754 } catch (XmlPullParserException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700755 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800756 return null;
757 } catch (IOException e) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700758 Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800759 return null;
760 }
761 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700762
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700763 private static JournaledFile makeJournaledFile(int userHandle) {
764 final String base = userHandle == 0
765 ? "/data/system/" + DEVICE_POLICIES_XML
766 : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
767 .getAbsolutePath();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800768 return new JournaledFile(new File(base), new File(base + ".tmp"));
769 }
770
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700771 private void saveSettingsLocked(int userHandle) {
772 DevicePolicyData policy = getUserData(userHandle);
773 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800774 FileOutputStream stream = null;
775 try {
776 stream = new FileOutputStream(journal.chooseForWrite(), false);
777 XmlSerializer out = new FastXmlSerializer();
778 out.setOutput(stream, "utf-8");
779 out.startDocument(null, true);
780
781 out.startTag(null, "policies");
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700782
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700783 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800784 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700785 ActiveAdmin ap = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -0800786 if (ap != null) {
787 out.startTag(null, "admin");
788 out.attribute(null, "name", ap.info.getComponent().flattenToString());
789 ap.writeToXml(out);
790 out.endTag(null, "admin");
791 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800792 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700793
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700794 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800795 out.startTag(null, "password-owner");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700796 out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800797 out.endTag(null, "password-owner");
798 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700799
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700800 if (policy.mFailedPasswordAttempts != 0) {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800801 out.startTag(null, "failed-password-attempts");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700802 out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800803 out.endTag(null, "failed-password-attempts");
804 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700805
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700806 if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
807 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
808 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
809 || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700810 out.startTag(null, "active-password");
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700811 out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
812 out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
813 out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
814 out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
815 out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700816 out.attribute(null, "numeric", Integer
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700817 .toString(policy.mActivePasswordNumeric));
818 out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
819 out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700820 out.endTag(null, "active-password");
821 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700822
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700823 out.endTag(null, "policies");
824
Dianne Hackbornd6847842010-01-12 18:14:19 -0800825 out.endDocument();
826 stream.close();
827 journal.commit();
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700828 sendChangedNotification(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800829 } catch (IOException e) {
830 try {
831 if (stream != null) {
832 stream.close();
833 }
834 } catch (IOException ex) {
835 // Ignore
836 }
837 journal.rollback();
838 }
839 }
840
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700841 private void sendChangedNotification(int userHandle) {
Jim Miller284b62e2010-06-08 14:27:42 -0700842 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
843 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Amith Yamasanib7a68592012-09-10 10:24:36 -0700844 long ident = Binder.clearCallingIdentity();
845 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700846 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
Amith Yamasanib7a68592012-09-10 10:24:36 -0700847 } finally {
848 Binder.restoreCallingIdentity(ident);
849 }
Jim Miller284b62e2010-06-08 14:27:42 -0700850 }
851
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700852 private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
853 JournaledFile journal = makeJournaledFile(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800854 FileInputStream stream = null;
855 File file = journal.chooseForRead();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800856 try {
857 stream = new FileInputStream(file);
858 XmlPullParser parser = Xml.newPullParser();
859 parser.setInput(stream, null);
860
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800861 int type;
862 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
863 && type != XmlPullParser.START_TAG) {
Dianne Hackbornd6847842010-01-12 18:14:19 -0800864 }
865 String tag = parser.getName();
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800866 if (!"policies".equals(tag)) {
867 throw new XmlPullParserException(
868 "Settings do not start with policies tag: found " + tag);
869 }
870 type = parser.next();
871 int outerDepth = parser.getDepth();
872 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
873 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
874 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
875 continue;
876 }
877 tag = parser.getName();
878 if ("admin".equals(tag)) {
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800879 String name = parser.getAttributeValue(null, "name");
880 try {
881 DeviceAdminInfo dai = findAdmin(
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700882 ComponentName.unflattenFromString(name), userHandle);
883 if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
884 != userHandle)) {
885 Slog.w(TAG, "findAdmin returned an incorrect uid "
886 + dai.getActivityInfo().applicationInfo.uid + " for user "
887 + userHandle);
888 }
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800889 if (dai != null) {
890 ActiveAdmin ap = new ActiveAdmin(dai);
891 ap.readFromXml(parser);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700892 policy.mAdminMap.put(ap.info.getComponent(), ap);
893 policy.mAdminList.add(ap);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800894 }
895 } catch (RuntimeException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700896 Slog.w(TAG, "Failed loading admin " + name, e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800897 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800898 } else if ("failed-password-attempts".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700899 policy.mFailedPasswordAttempts = Integer.parseInt(
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800900 parser.getAttributeValue(null, "value"));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800901 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800902 } else if ("password-owner".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700903 policy.mPasswordOwner = Integer.parseInt(
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800904 parser.getAttributeValue(null, "value"));
905 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700906 } else if ("active-password".equals(tag)) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700907 policy.mActivePasswordQuality = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700908 parser.getAttributeValue(null, "quality"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700909 policy.mActivePasswordLength = Integer.parseInt(
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700910 parser.getAttributeValue(null, "length"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700911 policy.mActivePasswordUpperCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700912 parser.getAttributeValue(null, "uppercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700913 policy.mActivePasswordLowerCase = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700914 parser.getAttributeValue(null, "lowercase"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700915 policy.mActivePasswordLetters = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700916 parser.getAttributeValue(null, "letters"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700917 policy.mActivePasswordNumeric = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700918 parser.getAttributeValue(null, "numeric"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700919 policy.mActivePasswordSymbols = Integer.parseInt(
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700920 parser.getAttributeValue(null, "symbols"));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700921 policy.mActivePasswordNonLetter = Integer.parseInt(
Konstantin Lopyrevc8577402010-06-04 17:15:02 -0700922 parser.getAttributeValue(null, "nonletter"));
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700923 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800924 } else {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700925 Slog.w(TAG, "Unknown tag: " + tag);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800926 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -0800927 }
Dianne Hackbornd6847842010-01-12 18:14:19 -0800928 }
929 } catch (NullPointerException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700930 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800931 } catch (NumberFormatException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700932 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800933 } catch (XmlPullParserException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700934 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackborncef65ee2010-09-30 18:27:22 -0700935 } catch (FileNotFoundException e) {
936 // Don't be noisy, this is normal if we haven't defined any policies.
Dianne Hackbornd6847842010-01-12 18:14:19 -0800937 } catch (IOException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700938 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800939 } catch (IndexOutOfBoundsException e) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700940 Slog.w(TAG, "failed parsing " + file + " " + e);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800941 }
942 try {
943 if (stream != null) {
944 stream.close();
945 }
946 } catch (IOException e) {
947 // Ignore
948 }
949
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700950 // Validate that what we stored for the password quality matches
951 // sufficiently what is currently set. Note that this is only
952 // a sanity check in case the two get out of sync; this should
953 // never normally happen.
954 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700955 if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700956 Slog.w(TAG, "Active password quality 0x"
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700957 + Integer.toHexString(policy.mActivePasswordQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700958 + " does not match actual quality 0x"
959 + Integer.toHexString(utils.getActivePasswordQuality()));
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700960 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
961 policy.mActivePasswordLength = 0;
962 policy.mActivePasswordUpperCase = 0;
963 policy.mActivePasswordLowerCase = 0;
964 policy.mActivePasswordLetters = 0;
965 policy.mActivePasswordNumeric = 0;
966 policy.mActivePasswordSymbols = 0;
967 policy.mActivePasswordNonLetter = 0;
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700968 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700969
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700970 validatePasswordOwnerLocked(policy);
971 syncDeviceCapabilitiesLocked(policy);
972 updateMaximumTimeToLockLocked(policy);
Dianne Hackbornd6847842010-01-12 18:14:19 -0800973 }
974
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700975 static void validateQualityConstant(int quality) {
976 switch (quality) {
977 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
Danielle Millettde7a2f32011-12-21 17:02:32 -0500978 case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700979 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
980 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
981 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
982 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -0700983 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -0700984 return;
985 }
986 throw new IllegalArgumentException("Invalid quality constant: 0x"
987 + Integer.toHexString(quality));
988 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -0700989
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700990 void validatePasswordOwnerLocked(DevicePolicyData policy) {
991 if (policy.mPasswordOwner >= 0) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800992 boolean haveOwner = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700993 for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
994 if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800995 haveOwner = true;
996 break;
997 }
998 }
999 if (!haveOwner) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001000 Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001001 + " no longer active; disabling");
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001002 policy.mPasswordOwner = -1;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001003 }
1004 }
1005 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001006
Ben Komalo2447edd2011-05-09 16:05:33 -07001007 /**
1008 * Pushes down policy information to the system for any policies related to general device
1009 * capabilities that need to be enforced by lower level services (e.g. Camera services).
1010 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001011 void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
Ben Komalo2447edd2011-05-09 16:05:33 -07001012 // Ensure the status of the camera is synced down to the system. Interested native services
1013 // should monitor this value and act accordingly.
1014 boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001015 boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07001016 if (cameraDisabled != systemState) {
1017 long token = Binder.clearCallingIdentity();
1018 try {
1019 String value = cameraDisabled ? "1" : "0";
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001020 if (DBG) Slog.v(TAG, "Change in camera state ["
Ben Komalo2447edd2011-05-09 16:05:33 -07001021 + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
1022 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
1023 } finally {
1024 Binder.restoreCallingIdentity(token);
1025 }
1026 }
1027 }
1028
Dianne Hackbornd6847842010-01-12 18:14:19 -08001029 public void systemReady() {
1030 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001031 loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001032 loadDeviceOwner();
Dianne Hackbornd6847842010-01-12 18:14:19 -08001033 }
1034 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001035
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001036 private void handlePasswordExpirationNotification(DevicePolicyData policy) {
Jim Millera4e28d12010-11-08 16:15:47 -08001037 synchronized (this) {
1038 final long now = System.currentTimeMillis();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001039 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001040 if (N <= 0) {
1041 return;
1042 }
1043 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001044 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001045 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
1046 && admin.passwordExpirationTimeout > 0L
1047 && admin.passwordExpirationDate > 0L
Andy Stadler043116a2010-11-29 17:43:32 -08001048 && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
Jim Millera4e28d12010-11-08 16:15:47 -08001049 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
1050 }
1051 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001052 setExpirationAlarmCheckLocked(mContext, policy);
Jim Millera4e28d12010-11-08 16:15:47 -08001053 }
1054 }
1055
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001056 /**
1057 * @param adminReceiver The admin to add
1058 * @param refreshing true = update an active admin, no error
1059 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001060 public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08001061 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001062 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001063 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001064
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001065 DevicePolicyData policy = getUserData(userHandle);
1066 DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001067 if (info == null) {
1068 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
1069 }
1070 synchronized (this) {
1071 long ident = Binder.clearCallingIdentity();
1072 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001073 if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001074 throw new IllegalArgumentException("Admin is already added");
Dianne Hackbornd6847842010-01-12 18:14:19 -08001075 }
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001076 ActiveAdmin newAdmin = new ActiveAdmin(info);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001077 policy.mAdminMap.put(adminReceiver, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001078 int replaceIndex = -1;
1079 if (refreshing) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001080 final int N = policy.mAdminList.size();
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001081 for (int i=0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001082 ActiveAdmin oldAdmin = policy.mAdminList.get(i);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001083 if (oldAdmin.info.getComponent().equals(adminReceiver)) {
1084 replaceIndex = i;
1085 break;
1086 }
1087 }
1088 }
1089 if (replaceIndex == -1) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001090 policy.mAdminList.add(newAdmin);
Amith Yamasani71e6c692013-03-24 17:39:28 -07001091 enableIfNecessary(info.getPackageName(), userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001092 } else {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001093 policy.mAdminList.set(replaceIndex, newAdmin);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001094 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001095 saveSettingsLocked(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001096 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001097 } finally {
1098 Binder.restoreCallingIdentity(ident);
1099 }
1100 }
1101 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001102
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001103 public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
1104 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001105 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001106 return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001107 }
1108 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001109
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001110 public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
1111 enforceCrossUserPermission(userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001112 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001113 ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Andy Stadlerc25f70a2010-12-08 15:56:45 -08001114 if (administrator == null) {
1115 throw new SecurityException("No active admin " + adminReceiver);
1116 }
1117 return administrator.info.usesPolicy(policyId);
1118 }
1119 }
1120
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001121 public List<ComponentName> getActiveAdmins(int userHandle) {
1122 enforceCrossUserPermission(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001123 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001124 DevicePolicyData policy = getUserData(userHandle);
1125 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001126 if (N <= 0) {
1127 return null;
1128 }
1129 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
1130 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001131 res.add(policy.mAdminList.get(i).info.getComponent());
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001132 }
1133 return res;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001134 }
1135 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001136
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001137 public boolean packageHasActiveAdmins(String packageName, int userHandle) {
1138 enforceCrossUserPermission(userHandle);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001139 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001140 DevicePolicyData policy = getUserData(userHandle);
1141 final int N = policy.mAdminList.size();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001142 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001143 if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001144 return true;
1145 }
1146 }
1147 return false;
1148 }
1149 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001150
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001151 public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
1152 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001153 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001154 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001155 if (admin == null) {
1156 return;
1157 }
1158 if (admin.getUid() != Binder.getCallingUid()) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07001159 // If trying to remove device owner, refuse when the caller is not the owner.
1160 if (mDeviceOwner != null
1161 && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
1162 return;
1163 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08001164 mContext.enforceCallingOrSelfPermission(
Amith Yamasania418cf22013-07-19 12:39:17 -07001165 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001166 }
1167 long ident = Binder.clearCallingIdentity();
1168 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001169 removeActiveAdminLocked(adminReceiver, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001170 } finally {
1171 Binder.restoreCallingIdentity(ident);
1172 }
1173 }
1174 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001175
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001176 public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001177 validateQualityConstant(quality);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001178 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001179
Dianne Hackbornd6847842010-01-12 18:14:19 -08001180 synchronized (this) {
1181 if (who == null) {
1182 throw new NullPointerException("ComponentName is null");
1183 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001184 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1185 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001186 if (ap.passwordQuality != quality) {
1187 ap.passwordQuality = quality;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001188 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001189 }
1190 }
1191 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001192
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001193 public int getPasswordQuality(ComponentName who, int userHandle) {
1194 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001195 synchronized (this) {
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001196 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001197 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001198
Dianne Hackborn254cb442010-01-27 19:23:59 -08001199 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001200 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001201 return admin != null ? admin.passwordQuality : mode;
Dianne Hackborn254cb442010-01-27 19:23:59 -08001202 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001203
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001204 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001205 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001206 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001207 if (mode < admin.passwordQuality) {
1208 mode = admin.passwordQuality;
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001209 }
1210 }
1211 return mode;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001212 }
1213 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001214
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001215 public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
1216 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001217 synchronized (this) {
1218 if (who == null) {
1219 throw new NullPointerException("ComponentName is null");
1220 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001221 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1222 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001223 if (ap.minimumPasswordLength != length) {
1224 ap.minimumPasswordLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001225 saveSettingsLocked(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001226 }
1227 }
1228 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001229
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001230 public int getPasswordMinimumLength(ComponentName who, int userHandle) {
1231 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001232 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001233 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001234 int length = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001235
Dianne Hackborn254cb442010-01-27 19:23:59 -08001236 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001237 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001238 return admin != null ? admin.minimumPasswordLength : length;
1239 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001240
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001241 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001242 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001243 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001244 if (length < admin.minimumPasswordLength) {
1245 length = admin.minimumPasswordLength;
1246 }
1247 }
1248 return length;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001249 }
1250 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001251
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001252 public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
1253 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001254 synchronized (this) {
1255 if (who == null) {
1256 throw new NullPointerException("ComponentName is null");
1257 }
1258 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1259 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1260 if (ap.passwordHistoryLength != length) {
1261 ap.passwordHistoryLength = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001262 saveSettingsLocked(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001263 }
1264 }
1265 }
1266
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001267 public int getPasswordHistoryLength(ComponentName who, int userHandle) {
1268 enforceCrossUserPermission(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001269 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001270 DevicePolicyData policy = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001271 int length = 0;
1272
1273 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001274 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001275 return admin != null ? admin.passwordHistoryLength : length;
1276 }
1277
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001278 final int N = policy.mAdminList.size();
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001279 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001280 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001281 if (length < admin.passwordHistoryLength) {
1282 length = admin.passwordHistoryLength;
1283 }
1284 }
1285 return length;
1286 }
1287 }
1288
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001289 public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
1290 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001291 synchronized (this) {
1292 if (who == null) {
1293 throw new NullPointerException("ComponentName is null");
1294 }
Andy Stadler1f35d482010-11-19 15:39:41 -08001295 if (timeout < 0) {
1296 throw new IllegalArgumentException("Timeout must be >= 0 ms");
Jim Millera4e28d12010-11-08 16:15:47 -08001297 }
1298 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1299 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
1300 // Calling this API automatically bumps the expiration date
1301 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
1302 ap.passwordExpirationDate = expiration;
1303 ap.passwordExpirationTimeout = timeout;
1304 if (timeout > 0L) {
1305 Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1306 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1307 .format(new Date(expiration)));
1308 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001309 saveSettingsLocked(userHandle);
1310 // in case this is the first one
1311 setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
Jim Millera4e28d12010-11-08 16:15:47 -08001312 }
1313 }
1314
Andy Stadler043116a2010-11-29 17:43:32 -08001315 /**
1316 * Return a single admin's expiration cycle time, or the min of all cycle times.
1317 * Returns 0 if not configured.
1318 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001319 public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
1320 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001321 synchronized (this) {
Jim Millera4e28d12010-11-08 16:15:47 -08001322 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001323 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001324 return admin != null ? admin.passwordExpirationTimeout : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001325 }
1326
Andy Stadler043116a2010-11-29 17:43:32 -08001327 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001328 DevicePolicyData policy = getUserData(userHandle);
1329 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001330 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001331 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001332 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1333 && timeout > admin.passwordExpirationTimeout)) {
1334 timeout = admin.passwordExpirationTimeout;
1335 }
1336 }
1337 return timeout;
1338 }
1339 }
1340
Andy Stadler043116a2010-11-29 17:43:32 -08001341 /**
1342 * Return a single admin's expiration date/time, or the min (soonest) for all admins.
1343 * Returns 0 if not configured.
1344 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001345 private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
Jim Millera4e28d12010-11-08 16:15:47 -08001346 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001347 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadler043116a2010-11-29 17:43:32 -08001348 return admin != null ? admin.passwordExpirationDate : 0L;
Jim Millera4e28d12010-11-08 16:15:47 -08001349 }
1350
Andy Stadler043116a2010-11-29 17:43:32 -08001351 long timeout = 0L;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001352 DevicePolicyData policy = getUserData(userHandle);
1353 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08001354 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001355 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08001356 if (timeout == 0L || (admin.passwordExpirationDate != 0
1357 && timeout > admin.passwordExpirationDate)) {
1358 timeout = admin.passwordExpirationDate;
1359 }
1360 }
1361 return timeout;
1362 }
1363
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001364 public long getPasswordExpiration(ComponentName who, int userHandle) {
1365 enforceCrossUserPermission(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001366 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001367 return getPasswordExpirationLocked(who, userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08001368 }
1369 }
1370
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001371 public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
1372 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001373 synchronized (this) {
1374 if (who == null) {
1375 throw new NullPointerException("ComponentName is null");
1376 }
1377 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1378 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1379 if (ap.minimumPasswordUpperCase != length) {
1380 ap.minimumPasswordUpperCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001381 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001382 }
1383 }
1384 }
1385
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001386 public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
1387 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001388 synchronized (this) {
1389 int length = 0;
1390
1391 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001392 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001393 return admin != null ? admin.minimumPasswordUpperCase : length;
1394 }
1395
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001396 DevicePolicyData policy = getUserData(userHandle);
1397 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001398 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001399 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001400 if (length < admin.minimumPasswordUpperCase) {
1401 length = admin.minimumPasswordUpperCase;
1402 }
1403 }
1404 return length;
1405 }
1406 }
1407
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001408 public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
1409 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001410 synchronized (this) {
1411 if (who == null) {
1412 throw new NullPointerException("ComponentName is null");
1413 }
1414 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1415 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1416 if (ap.minimumPasswordLowerCase != length) {
1417 ap.minimumPasswordLowerCase = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001418 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001419 }
1420 }
1421 }
1422
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001423 public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
1424 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001425 synchronized (this) {
1426 int length = 0;
1427
1428 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001429 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001430 return admin != null ? admin.minimumPasswordLowerCase : length;
1431 }
1432
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001433 DevicePolicyData policy = getUserData(userHandle);
1434 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001435 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001436 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001437 if (length < admin.minimumPasswordLowerCase) {
1438 length = admin.minimumPasswordLowerCase;
1439 }
1440 }
1441 return length;
1442 }
1443 }
1444
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001445 public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
1446 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001447 synchronized (this) {
1448 if (who == null) {
1449 throw new NullPointerException("ComponentName is null");
1450 }
1451 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1452 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1453 if (ap.minimumPasswordLetters != length) {
1454 ap.minimumPasswordLetters = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001455 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001456 }
1457 }
1458 }
1459
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001460 public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
1461 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001462 synchronized (this) {
1463 int length = 0;
1464
1465 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001466 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001467 return admin != null ? admin.minimumPasswordLetters : length;
1468 }
1469
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001470 DevicePolicyData policy = getUserData(userHandle);
1471 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001472 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001473 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001474 if (length < admin.minimumPasswordLetters) {
1475 length = admin.minimumPasswordLetters;
1476 }
1477 }
1478 return length;
1479 }
1480 }
1481
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001482 public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
1483 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001484 synchronized (this) {
1485 if (who == null) {
1486 throw new NullPointerException("ComponentName is null");
1487 }
1488 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1489 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1490 if (ap.minimumPasswordNumeric != length) {
1491 ap.minimumPasswordNumeric = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001492 saveSettingsLocked(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001493 }
1494 }
1495 }
1496
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001497 public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
1498 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001499 synchronized (this) {
1500 int length = 0;
1501
1502 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001503 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001504 return admin != null ? admin.minimumPasswordNumeric : length;
1505 }
1506
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001507 DevicePolicyData policy = getUserData(userHandle);
1508 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001509 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001510 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001511 if (length < admin.minimumPasswordNumeric) {
1512 length = admin.minimumPasswordNumeric;
1513 }
1514 }
1515 return length;
1516 }
1517 }
1518
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001519 public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
1520 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.minimumPasswordSymbols != length) {
1528 ap.minimumPasswordSymbols = 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 getPasswordMinimumSymbols(ComponentName who, int userHandle) {
1535 enforceCrossUserPermission(userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001536 synchronized (this) {
1537 int length = 0;
1538
1539 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001540 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001541 return admin != null ? admin.minimumPasswordSymbols : length;
1542 }
1543
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001544 DevicePolicyData policy = getUserData(userHandle);
1545 final int N = policy.mAdminList.size();
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001546 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001547 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001548 if (length < admin.minimumPasswordSymbols) {
1549 length = admin.minimumPasswordSymbols;
1550 }
1551 }
1552 return length;
1553 }
1554 }
1555
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001556 public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
1557 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001558 synchronized (this) {
1559 if (who == null) {
1560 throw new NullPointerException("ComponentName is null");
1561 }
1562 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1563 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1564 if (ap.minimumPasswordNonLetter != length) {
1565 ap.minimumPasswordNonLetter = length;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001566 saveSettingsLocked(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001567 }
1568 }
1569 }
1570
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001571 public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
1572 enforceCrossUserPermission(userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001573 synchronized (this) {
1574 int length = 0;
1575
1576 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001577 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001578 return admin != null ? admin.minimumPasswordNonLetter : length;
1579 }
1580
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001581 DevicePolicyData policy = getUserData(userHandle);
1582 final int N = policy.mAdminList.size();
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001583 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001584 ActiveAdmin admin = policy.mAdminList.get(i);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001585 if (length < admin.minimumPasswordNonLetter) {
1586 length = admin.minimumPasswordNonLetter;
1587 }
1588 }
1589 return length;
1590 }
1591 }
1592
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001593 public boolean isActivePasswordSufficient(int userHandle) {
1594 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001595 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001596 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001597 // This API can only be called by an active device admin,
1598 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001599 getActiveAdminForCallerLocked(null,
1600 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001601 if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
1602 || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001603 return false;
1604 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001605 if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001606 return true;
1607 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001608 return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
1609 && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
1610 && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
1611 && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
1612 && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
1613 && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001614 }
1615 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001616
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001617 public int getCurrentFailedPasswordAttempts(int userHandle) {
1618 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001619 synchronized (this) {
1620 // This API can only be called by an active device admin,
1621 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001622 getActiveAdminForCallerLocked(null,
1623 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001624 return getUserData(userHandle).mFailedPasswordAttempts;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001625 }
1626 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001627
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001628 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
1629 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001630 synchronized (this) {
1631 // This API can only be called by an active device admin,
1632 // so try to retrieve it to check that the caller is one.
1633 getActiveAdminForCallerLocked(who,
1634 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1635 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1636 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1637 if (ap.maximumFailedPasswordsForWipe != num) {
1638 ap.maximumFailedPasswordsForWipe = num;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001639 saveSettingsLocked(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001640 }
1641 }
1642 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001643
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001644 public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
1645 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001646 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001647 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001648 int count = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001649
Dianne Hackborn254cb442010-01-27 19:23:59 -08001650 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001651 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001652 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1653 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001654
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001655 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001656 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001657 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001658 if (count == 0) {
1659 count = admin.maximumFailedPasswordsForWipe;
1660 } else if (admin.maximumFailedPasswordsForWipe != 0
1661 && count > admin.maximumFailedPasswordsForWipe) {
1662 count = admin.maximumFailedPasswordsForWipe;
1663 }
1664 }
1665 return count;
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001666 }
1667 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001668
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001669 public boolean resetPassword(String password, int flags, int userHandle) {
1670 enforceCrossUserPermission(userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001671 int quality;
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001672 synchronized (this) {
1673 // This API can only be called by an active device admin,
1674 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001675 getActiveAdminForCallerLocked(null,
1676 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001677 quality = getPasswordQuality(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001678 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001679 int realQuality = LockPatternUtils.computePasswordQuality(password);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001680 if (realQuality < quality
1681 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001682 Slog.w(TAG, "resetPassword: password quality 0x"
joonyoung.choad83c192013-04-18 13:51:08 +09001683 + Integer.toHexString(realQuality)
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001684 + " does not meet required quality 0x"
1685 + Integer.toHexString(quality));
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001686 return false;
1687 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001688 quality = Math.max(realQuality, quality);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001689 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001690 int length = getPasswordMinimumLength(null, userHandle);
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08001691 if (password.length() < length) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001692 Slog.w(TAG, "resetPassword: password length " + password.length()
1693 + " does not meet required length " + length);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001694 return false;
1695 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001696 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1697 int letters = 0;
1698 int uppercase = 0;
1699 int lowercase = 0;
1700 int numbers = 0;
1701 int symbols = 0;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001702 int nonletter = 0;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001703 for (int i = 0; i < password.length(); i++) {
1704 char c = password.charAt(i);
1705 if (c >= 'A' && c <= 'Z') {
1706 letters++;
1707 uppercase++;
1708 } else if (c >= 'a' && c <= 'z') {
1709 letters++;
1710 lowercase++;
1711 } else if (c >= '0' && c <= '9') {
1712 numbers++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001713 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001714 } else {
1715 symbols++;
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001716 nonletter++;
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001717 }
1718 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001719 int neededLetters = getPasswordMinimumLetters(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001720 if(letters < neededLetters) {
1721 Slog.w(TAG, "resetPassword: number of letters " + letters
1722 + " does not meet required number of letters " + neededLetters);
1723 return false;
1724 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001725 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001726 if (numbers < neededNumbers) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -08001727 Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
1728 + " does not meet required number of numerical digits "
1729 + neededNumbers);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001730 return false;
1731 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001732 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001733 if (lowercase < neededLowerCase) {
1734 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1735 + " does not meet required number of lowercase letters "
1736 + neededLowerCase);
1737 return false;
1738 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001739 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001740 if (uppercase < neededUpperCase) {
1741 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1742 + " does not meet required number of uppercase letters "
1743 + neededUpperCase);
1744 return false;
1745 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001746 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001747 if (symbols < neededSymbols) {
1748 Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1749 + " does not meet required number of special symbols " + neededSymbols);
1750 return false;
1751 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001752 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
Konstantin Lopyrevc8577402010-06-04 17:15:02 -07001753 if (nonletter < neededNonLetter) {
1754 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1755 + " does not meet required number of non-letter characters "
1756 + neededNonLetter);
1757 return false;
1758 }
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07001759 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001760 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001761
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001762 int callingUid = Binder.getCallingUid();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001763 DevicePolicyData policy = getUserData(userHandle);
1764 if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001765 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001766 return false;
1767 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001768
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001769 // Don't do this with the lock held, because it is going to call
1770 // back in to the service.
1771 long ident = Binder.clearCallingIdentity();
1772 try {
1773 LockPatternUtils utils = new LockPatternUtils(mContext);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001774 utils.saveLockPassword(password, quality, false, userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001775 synchronized (this) {
1776 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1777 != 0 ? callingUid : -1;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001778 if (policy.mPasswordOwner != newOwner) {
1779 policy.mPasswordOwner = newOwner;
1780 saveSettingsLocked(userHandle);
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07001781 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08001782 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001783 } finally {
1784 Binder.restoreCallingIdentity(ident);
1785 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001786
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001787 return true;
1788 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001789
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001790 public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
1791 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001792 synchronized (this) {
1793 if (who == null) {
1794 throw new NullPointerException("ComponentName is null");
1795 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001796 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Dianne Hackborn315ada72010-02-11 12:14:08 -08001797 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001798 if (ap.maximumTimeToUnlock != timeMs) {
1799 ap.maximumTimeToUnlock = timeMs;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001800 saveSettingsLocked(userHandle);
1801 updateMaximumTimeToLockLocked(getUserData(userHandle));
Dianne Hackbornd6847842010-01-12 18:14:19 -08001802 }
1803 }
1804 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001805
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001806 void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
1807 long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
1808 if (policy.mLastMaximumTimeToLock == timeMs) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001809 return;
1810 }
1811
1812 long ident = Binder.clearCallingIdentity();
1813 try {
1814 if (timeMs <= 0) {
1815 timeMs = Integer.MAX_VALUE;
1816 } else {
1817 // Make sure KEEP_SCREEN_ON is disabled, since that
1818 // would allow bypassing of the maximum time to lock.
Christopher Tate62df6eb52012-09-07 15:00:54 -07001819 Settings.Global.putInt(mContext.getContentResolver(),
1820 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001821 }
1822
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001823 policy.mLastMaximumTimeToLock = timeMs;
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001824
1825 try {
Jeff Brown96307042012-07-27 15:51:34 -07001826 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07001827 } catch (RemoteException e) {
1828 Slog.w(TAG, "Failure talking with power manager", e);
1829 }
1830 } finally {
1831 Binder.restoreCallingIdentity(ident);
1832 }
1833 }
1834
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001835 public long getMaximumTimeToLock(ComponentName who, int userHandle) {
1836 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001837 synchronized (this) {
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001838 long time = 0;
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001839
Dianne Hackborn254cb442010-01-27 19:23:59 -08001840 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001841 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Dianne Hackborn254cb442010-01-27 19:23:59 -08001842 return admin != null ? admin.maximumTimeToUnlock : time;
1843 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001844
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001845 DevicePolicyData policy = getUserData(userHandle);
1846 final int N = policy.mAdminList.size();
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001847 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001848 ActiveAdmin admin = policy.mAdminList.get(i);
Dianne Hackbornd47c6ed2010-01-27 16:21:20 -08001849 if (time == 0) {
1850 time = admin.maximumTimeToUnlock;
1851 } else if (admin.maximumTimeToUnlock != 0
1852 && time > admin.maximumTimeToUnlock) {
1853 time = admin.maximumTimeToUnlock;
1854 }
1855 }
1856 return time;
Dianne Hackbornd6847842010-01-12 18:14:19 -08001857 }
1858 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001859
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001860 public void lockNow() {
1861 synchronized (this) {
1862 // This API can only be called by an active device admin,
1863 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001864 getActiveAdminForCallerLocked(null,
1865 DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001866 lockNowUnchecked();
1867 }
1868 }
1869
1870 private void lockNowUnchecked() {
1871 long ident = Binder.clearCallingIdentity();
1872 try {
1873 // Power off the display
1874 getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
1875 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
1876 // Ensure the device is locked
Adam Cohenf7522022012-10-03 20:03:18 -07001877 getWindowManager().lockNow(null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001878 } catch (RemoteException e) {
1879 } finally {
1880 Binder.restoreCallingIdentity(ident);
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001881 }
1882 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001883
Ben Komaloed48c8b2011-10-17 17:30:21 -07001884 private boolean isExtStorageEncrypted() {
1885 String state = SystemProperties.get("vold.decrypt");
1886 return !"".equals(state);
1887 }
1888
Maggie Benthallda51e682013-08-08 22:35:44 -04001889 public boolean installCaCert(byte[] certBuffer) throws RemoteException {
1890 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
1891 KeyChainConnection keyChainConnection = null;
1892 byte[] pemCert;
1893 try {
1894 X509Certificate cert = parseCert(certBuffer);
1895 pemCert = Credentials.convertToPem(cert);
1896 } catch (CertificateException ce) {
1897 Log.e(TAG, "Problem converting cert", ce);
1898 return false;
1899 } catch (IOException ioe) {
1900 Log.e(TAG, "Problem reading cert", ioe);
1901 return false;
1902 }
1903 try {
1904 keyChainConnection = KeyChain.bind(mContext);
1905 try {
1906 keyChainConnection.getService().installCaCertificate(pemCert);
1907 return true;
1908 } finally {
1909 if (keyChainConnection != null) {
1910 keyChainConnection.close();
1911 keyChainConnection = null;
1912 }
1913 }
1914 } catch (InterruptedException e1) {
1915 Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
1916 Thread.currentThread().interrupt();
1917 }
1918 return false;
1919 }
1920
1921 private static X509Certificate parseCert(byte[] certBuffer)
1922 throws CertificateException, IOException {
1923 CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
1924 return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
1925 certBuffer));
1926 }
1927
1928 public void uninstallCaCert(final byte[] certBuffer) {
1929 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
1930 TrustedCertificateStore certStore = new TrustedCertificateStore();
1931 String alias = null;
1932 try {
1933 X509Certificate cert = parseCert(certBuffer);
1934 alias = certStore.getCertificateAlias(cert);
1935 } catch (CertificateException ce) {
1936 Log.e(TAG, "Problem creating X509Certificate", ce);
1937 return;
1938 } catch (IOException ioe) {
1939 Log.e(TAG, "Problem reading certificate", ioe);
1940 return;
1941 }
1942 try {
1943 KeyChainConnection keyChainConnection = KeyChain.bind(mContext);
1944 IKeyChainService service = keyChainConnection.getService();
1945 try {
1946 service.deleteCaCertificate(alias);
1947 } catch (RemoteException e) {
1948 Log.e(TAG, "from CaCertUninstaller: ", e);
1949 } finally {
1950 keyChainConnection.close();
1951 keyChainConnection = null;
1952 }
1953 } catch (InterruptedException ie) {
1954 Log.w(TAG, "CaCertUninstaller: ", ie);
1955 Thread.currentThread().interrupt();
1956 }
1957 }
1958
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001959 void wipeDataLocked(int flags) {
Ben Komaloed48c8b2011-10-17 17:30:21 -07001960 // If the SD card is encrypted and non-removable, we have to force a wipe.
1961 boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
1962 boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
1963
1964 // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
1965 if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Dianne Hackborn42499172010-10-15 18:45:07 -07001966 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
Masanori Oginof535cb042012-02-15 19:25:50 +09001967 intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
Dianne Hackborn42499172010-10-15 18:45:07 -07001968 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1969 mWakeLock.acquire(10000);
1970 mContext.startService(intent);
1971 } else {
1972 try {
1973 RecoverySystem.rebootWipeUserData(mContext);
1974 } catch (IOException e) {
1975 Slog.w(TAG, "Failed requesting data wipe", e);
1976 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001977 }
1978 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001979
Amith Yamasani599dd7c2012-09-14 23:20:08 -07001980 public void wipeData(int flags, final int userHandle) {
1981 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08001982 synchronized (this) {
1983 // This API can only be called by an active device admin,
1984 // so try to retrieve it to check that the caller is one.
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08001985 getActiveAdminForCallerLocked(null,
1986 DeviceAdminInfo.USES_POLICY_WIPE_DATA);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001987 long ident = Binder.clearCallingIdentity();
1988 try {
Amith Yamasani32f07422012-11-16 15:09:13 -08001989 wipeDeviceOrUserLocked(flags, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001990 } finally {
1991 Binder.restoreCallingIdentity(ident);
1992 }
Dianne Hackborndf83afa2010-01-20 13:37:26 -08001993 }
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08001994 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07001995
Amith Yamasani32f07422012-11-16 15:09:13 -08001996 private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
1997 if (userHandle == UserHandle.USER_OWNER) {
1998 wipeDataLocked(flags);
1999 } else {
2000 lockNowUnchecked();
2001 mHandler.post(new Runnable() {
2002 public void run() {
2003 try {
Amith Yamasanie4cf7342012-12-17 11:12:09 -08002004 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
Amith Yamasani32f07422012-11-16 15:09:13 -08002005 ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
2006 .removeUser(userHandle);
2007 } catch (RemoteException re) {
2008 // Shouldn't happen
2009 }
2010 }
2011 });
2012 }
2013 }
2014
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002015 public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
2016 enforceCrossUserPermission(userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002017 mContext.enforceCallingOrSelfPermission(
2018 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002019
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002020 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002021 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002022 if (admin == null) {
2023 try {
2024 result.sendResult(null);
2025 } catch (RemoteException e) {
2026 }
2027 return;
2028 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002029 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002030 intent.setComponent(admin.info.getComponent());
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002031 mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002032 null, new BroadcastReceiver() {
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002033 @Override
2034 public void onReceive(Context context, Intent intent) {
2035 try {
2036 result.sendResult(getResultExtras(false));
2037 } catch (RemoteException e) {
2038 }
2039 }
2040 }, null, Activity.RESULT_OK, null, null);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002041 }
2042 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002043
Konstantin Lopyreva15dcfa2010-05-24 17:10:56 -07002044 public void setActivePasswordState(int quality, int length, int letters, int uppercase,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002045 int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
2046 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002047 mContext.enforceCallingOrSelfPermission(
2048 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002049 DevicePolicyData p = getUserData(userHandle);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002050
Dianne Hackborn85f2c9c2010-03-22 11:12:48 -07002051 validateQualityConstant(quality);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002052
Dianne Hackbornd6847842010-01-12 18:14:19 -08002053 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002054 if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
2055 || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
2056 || p.mActivePasswordUpperCase != uppercase
2057 || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
2058 || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002059 long ident = Binder.clearCallingIdentity();
2060 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002061 p.mActivePasswordQuality = quality;
2062 p.mActivePasswordLength = length;
2063 p.mActivePasswordLetters = letters;
2064 p.mActivePasswordLowerCase = lowercase;
2065 p.mActivePasswordUpperCase = uppercase;
2066 p.mActivePasswordNumeric = numbers;
2067 p.mActivePasswordSymbols = symbols;
2068 p.mActivePasswordNonLetter = nonletter;
2069 p.mFailedPasswordAttempts = 0;
2070 saveSettingsLocked(userHandle);
2071 updatePasswordExpirationsLocked(userHandle);
2072 setExpirationAlarmCheckLocked(mContext, p);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002073 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002074 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002075 } finally {
2076 Binder.restoreCallingIdentity(ident);
2077 }
2078 }
2079 }
2080 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002081
Andy Stadler043116a2010-11-29 17:43:32 -08002082 /**
2083 * Called any time the device password is updated. Resets all password expiration clocks.
2084 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002085 private void updatePasswordExpirationsLocked(int userHandle) {
2086 DevicePolicyData policy = getUserData(userHandle);
2087 final int N = policy.mAdminList.size();
Jim Millera4e28d12010-11-08 16:15:47 -08002088 if (N > 0) {
2089 for (int i=0; i<N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002090 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Millera4e28d12010-11-08 16:15:47 -08002091 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
Andy Stadler043116a2010-11-29 17:43:32 -08002092 long timeout = admin.passwordExpirationTimeout;
2093 long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
2094 admin.passwordExpirationDate = expiration;
Jim Millera4e28d12010-11-08 16:15:47 -08002095 }
2096 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002097 saveSettingsLocked(userHandle);
Jim Millera4e28d12010-11-08 16:15:47 -08002098 }
2099 }
2100
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002101 public void reportFailedPasswordAttempt(int userHandle) {
2102 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002103 mContext.enforceCallingOrSelfPermission(
2104 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002105
Dianne Hackbornd6847842010-01-12 18:14:19 -08002106 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002107 DevicePolicyData policy = getUserData(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002108 long ident = Binder.clearCallingIdentity();
2109 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002110 policy.mFailedPasswordAttempts++;
2111 saveSettingsLocked(userHandle);
2112 int max = getMaximumFailedPasswordsForWipe(null, userHandle);
2113 if (max > 0 && policy.mFailedPasswordAttempts >= max) {
Amith Yamasani32f07422012-11-16 15:09:13 -08002114 wipeDeviceOrUserLocked(0, userHandle);
Dianne Hackborn8ea138c2010-01-26 18:01:04 -08002115 }
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002116 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002117 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002118 } finally {
2119 Binder.restoreCallingIdentity(ident);
2120 }
2121 }
2122 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002123
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002124 public void reportSuccessfulPasswordAttempt(int userHandle) {
2125 enforceCrossUserPermission(userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002126 mContext.enforceCallingOrSelfPermission(
2127 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002128
Dianne Hackbornd6847842010-01-12 18:14:19 -08002129 synchronized (this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002130 DevicePolicyData policy = getUserData(userHandle);
2131 if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
Dianne Hackbornd6847842010-01-12 18:14:19 -08002132 long ident = Binder.clearCallingIdentity();
2133 try {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002134 policy.mFailedPasswordAttempts = 0;
2135 policy.mPasswordOwner = -1;
2136 saveSettingsLocked(userHandle);
Dianne Hackbornef6b22f2010-02-16 20:38:49 -08002137 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002138 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
Dianne Hackbornd6847842010-01-12 18:14:19 -08002139 } finally {
2140 Binder.restoreCallingIdentity(ident);
2141 }
2142 }
2143 }
2144 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002145
Oscar Montemayor69238c62010-08-03 10:51:06 -07002146 public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002147 String exclusionList, int userHandle) {
2148 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002149 synchronized(this) {
2150 if (who == null) {
2151 throw new NullPointerException("ComponentName is null");
2152 }
2153
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002154 // Only check if owner has set global proxy. We don't allow other users to set it.
2155 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002156 ActiveAdmin admin = getActiveAdminForCallerLocked(who,
2157 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
2158
2159 // Scan through active admins and find if anyone has already
2160 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002161 Set<ComponentName> compSet = policy.mAdminMap.keySet();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002162 for (ComponentName component : compSet) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002163 ActiveAdmin ap = policy.mAdminMap.get(component);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002164 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
2165 // Another admin already sets the global proxy
2166 // Return it to the caller.
2167 return component;
2168 }
2169 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002170
2171 // If the user is not the owner, don't set the global proxy. Fail silently.
2172 if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2173 Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
2174 + userHandle + " is not permitted.");
2175 return null;
2176 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002177 if (proxySpec == null) {
2178 admin.specifiesGlobalProxy = false;
2179 admin.globalProxySpec = null;
2180 admin.globalProxyExclusionList = null;
2181 } else {
2182
2183 admin.specifiesGlobalProxy = true;
2184 admin.globalProxySpec = proxySpec;
2185 admin.globalProxyExclusionList = exclusionList;
2186 }
2187
2188 // Reset the global proxy accordingly
2189 // Do this using system permissions, as apps cannot write to secure settings
2190 long origId = Binder.clearCallingIdentity();
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002191 resetGlobalProxyLocked(policy);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002192 Binder.restoreCallingIdentity(origId);
2193 return null;
2194 }
2195 }
2196
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002197 public ComponentName getGlobalProxyAdmin(int userHandle) {
2198 enforceCrossUserPermission(userHandle);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002199 synchronized(this) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002200 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002201 // Scan through active admins and find if anyone has already
2202 // set the global proxy.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002203 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002204 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002205 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002206 if (ap.specifiesGlobalProxy) {
2207 // Device admin sets the global proxy
2208 // Return it to the caller.
2209 return ap.info.getComponent();
2210 }
2211 }
2212 }
2213 // No device admin sets the global proxy.
2214 return null;
2215 }
2216
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002217 private void resetGlobalProxyLocked(DevicePolicyData policy) {
2218 final int N = policy.mAdminList.size();
Oscar Montemayor69238c62010-08-03 10:51:06 -07002219 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002220 ActiveAdmin ap = policy.mAdminList.get(i);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002221 if (ap.specifiesGlobalProxy) {
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002222 saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002223 return;
2224 }
2225 }
2226 // No device admins defining global proxies - reset global proxy settings to none
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002227 saveGlobalProxyLocked(null, null);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002228 }
2229
Dianne Hackborn2fe8fb22012-06-15 17:05:25 -07002230 private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
Oscar Montemayor69238c62010-08-03 10:51:06 -07002231 if (exclusionList == null) {
2232 exclusionList = "";
2233 }
2234 if (proxySpec == null) {
2235 proxySpec = "";
2236 }
2237 // Remove white spaces
2238 proxySpec = proxySpec.trim();
Robert Greenwalt434203a2010-10-11 16:00:27 -07002239 String data[] = proxySpec.split(":");
2240 int proxyPort = 8080;
2241 if (data.length > 1) {
2242 try {
2243 proxyPort = Integer.parseInt(data[1]);
2244 } catch (NumberFormatException e) {}
2245 }
Oscar Montemayor69238c62010-08-03 10:51:06 -07002246 exclusionList = exclusionList.trim();
2247 ContentResolver res = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -07002248 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
2249 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
2250 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
Robert Greenwalt434203a2010-10-11 16:00:27 -07002251 exclusionList);
Oscar Montemayor69238c62010-08-03 10:51:06 -07002252 }
2253
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002254 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002255 * Set the storage encryption request for a single admin. Returns the new total request
2256 * status (for all admins).
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002257 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002258 public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
2259 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002260 synchronized (this) {
2261 // Check for permissions
2262 if (who == null) {
2263 throw new NullPointerException("ComponentName is null");
2264 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002265 // Only owner can set storage encryption
2266 if (userHandle != UserHandle.USER_OWNER
2267 || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
2268 Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
2269 + UserHandle.getCallingUserId() + " is not permitted.");
2270 return 0;
2271 }
2272
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002273 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2274 DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
2275
Andy Stadler22dbfda2011-01-17 12:47:31 -08002276 // Quick exit: If the filesystem does not support encryption, we can exit early.
2277 if (!isEncryptionSupported()) {
2278 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2279 }
2280
2281 // (1) Record the value for the admin so it's sticky
2282 if (ap.encryptionRequested != encrypt) {
2283 ap.encryptionRequested = encrypt;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002284 saveSettingsLocked(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002285 }
2286
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002287 DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002288 // (2) Compute "max" for all admins
2289 boolean newRequested = false;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002290 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002291 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002292 newRequested |= policy.mAdminList.get(i).encryptionRequested;
Andy Stadler22dbfda2011-01-17 12:47:31 -08002293 }
2294
2295 // Notify OS of new request
2296 setEncryptionRequested(newRequested);
2297
2298 // Return the new global request status
2299 return newRequested
2300 ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
2301 : DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002302 }
2303 }
2304
2305 /**
Andy Stadler22dbfda2011-01-17 12:47:31 -08002306 * Get the current storage encryption request status for a given admin, or aggregate of all
2307 * active admins.
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002308 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002309 public boolean getStorageEncryption(ComponentName who, int userHandle) {
2310 enforceCrossUserPermission(userHandle);
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002311 synchronized (this) {
2312 // Check for permissions if a particular caller is specified
2313 if (who != null) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002314 // When checking for a single caller, status is based on caller's request
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002315 ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
Andy Stadlerc994d692011-06-01 15:30:54 -07002316 return ap != null ? ap.encryptionRequested : false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002317 }
2318
Andy Stadler22dbfda2011-01-17 12:47:31 -08002319 // If no particular caller is specified, return the aggregate set of requests.
2320 // This is short circuited by returning true on the first hit.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002321 DevicePolicyData policy = getUserData(userHandle);
2322 final int N = policy.mAdminList.size();
Andy Stadler22dbfda2011-01-17 12:47:31 -08002323 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002324 if (policy.mAdminList.get(i).encryptionRequested) {
Andy Stadler22dbfda2011-01-17 12:47:31 -08002325 return true;
2326 }
2327 }
2328 return false;
Andy Stadler7b0f8f02011-01-12 14:59:52 -08002329 }
2330 }
2331
Andy Stadler22dbfda2011-01-17 12:47:31 -08002332 /**
2333 * Get the current encryption status of the device.
2334 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002335 public int getStorageEncryptionStatus(int userHandle) {
2336 enforceCrossUserPermission(userHandle);
Andy Stadler22dbfda2011-01-17 12:47:31 -08002337 return getEncryptionStatus();
2338 }
2339
2340 /**
2341 * Hook to low-levels: This should report if the filesystem supports encrypted storage.
2342 */
2343 private boolean isEncryptionSupported() {
2344 // Note, this can be implemented as
2345 // return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2346 // But is provided as a separate internal method if there's a faster way to do a
2347 // simple check for supported-or-not.
2348 return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2349 }
2350
2351 /**
2352 * Hook to low-levels: Reporting the current status of encryption.
2353 * @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
2354 * {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
2355 * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
2356 */
2357 private int getEncryptionStatus() {
Andy Stadler0fe45de2011-01-20 16:35:09 -08002358 String status = SystemProperties.get("ro.crypto.state", "unsupported");
2359 if ("encrypted".equalsIgnoreCase(status)) {
2360 return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
2361 } else if ("unencrypted".equalsIgnoreCase(status)) {
2362 return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
2363 } else {
2364 return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
2365 }
Andy Stadler22dbfda2011-01-17 12:47:31 -08002366 }
2367
2368 /**
2369 * Hook to low-levels: If needed, record the new admin setting for encryption.
2370 */
2371 private void setEncryptionRequested(boolean encrypt) {
2372 }
2373
Ben Komalo2447edd2011-05-09 16:05:33 -07002374 /**
2375 * The system property used to share the state of the camera. The native camera service
2376 * is expected to read this property and act accordingly.
2377 */
2378 public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
2379
2380 /**
2381 * Disables all device cameras according to the specified admin.
2382 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002383 public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
2384 enforceCrossUserPermission(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002385 synchronized (this) {
2386 if (who == null) {
2387 throw new NullPointerException("ComponentName is null");
2388 }
2389 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
2390 DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
2391 if (ap.disableCamera != disabled) {
2392 ap.disableCamera = disabled;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002393 saveSettingsLocked(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002394 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002395 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Ben Komalo2447edd2011-05-09 16:05:33 -07002396 }
2397 }
2398
2399 /**
2400 * Gets whether or not all device cameras are disabled for a given admin, or disabled for any
2401 * active admins.
2402 */
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002403 public boolean getCameraDisabled(ComponentName who, int userHandle) {
Ben Komalo2447edd2011-05-09 16:05:33 -07002404 synchronized (this) {
2405 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002406 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002407 return (admin != null) ? admin.disableCamera : false;
2408 }
2409
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002410 DevicePolicyData policy = getUserData(userHandle);
Ben Komalo2447edd2011-05-09 16:05:33 -07002411 // Determine whether or not the device camera is disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002412 final int N = policy.mAdminList.size();
Ben Komalo2447edd2011-05-09 16:05:33 -07002413 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002414 ActiveAdmin admin = policy.mAdminList.get(i);
Ben Komalo2447edd2011-05-09 16:05:33 -07002415 if (admin.disableCamera) {
2416 return true;
2417 }
2418 }
2419 return false;
2420 }
2421 }
2422
Jim Millerb8ec4702012-08-31 17:19:10 -07002423 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002424 * Selectively disable keyguard features.
Jim Millerb8ec4702012-08-31 17:19:10 -07002425 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002426 public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002427 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002428 synchronized (this) {
2429 if (who == null) {
2430 throw new NullPointerException("ComponentName is null");
2431 }
2432 ActiveAdmin ap = getActiveAdminForCallerLocked(who,
Jim Miller48b9b0d2012-09-19 23:16:50 -07002433 DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
2434 if (ap.disabledKeyguardFeatures != which) {
2435 ap.disabledKeyguardFeatures = which;
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002436 saveSettingsLocked(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002437 }
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002438 syncDeviceCapabilitiesLocked(getUserData(userHandle));
Jim Millerb8ec4702012-08-31 17:19:10 -07002439 }
2440 }
2441
2442 /**
Jim Miller48b9b0d2012-09-19 23:16:50 -07002443 * Gets the disabled state for features in keyguard for the given admin,
Jim Millerb8ec4702012-08-31 17:19:10 -07002444 * or the aggregate of all active admins if who is null.
2445 */
Jim Miller48b9b0d2012-09-19 23:16:50 -07002446 public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002447 enforceCrossUserPermission(userHandle);
Jim Millerb8ec4702012-08-31 17:19:10 -07002448 synchronized (this) {
2449 if (who != null) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002450 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002451 return (admin != null) ? admin.disabledKeyguardFeatures : 0;
Jim Millerb8ec4702012-08-31 17:19:10 -07002452 }
2453
Jim Miller48b9b0d2012-09-19 23:16:50 -07002454 // Determine which keyguard features are disabled for any active admins.
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002455 DevicePolicyData policy = getUserData(userHandle);
2456 final int N = policy.mAdminList.size();
Jim Millerb8ec4702012-08-31 17:19:10 -07002457 int which = 0;
2458 for (int i = 0; i < N; i++) {
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002459 ActiveAdmin admin = policy.mAdminList.get(i);
Jim Miller48b9b0d2012-09-19 23:16:50 -07002460 which |= admin.disabledKeyguardFeatures;
Jim Millerb8ec4702012-08-31 17:19:10 -07002461 }
2462 return which;
2463 }
2464 }
2465
Amith Yamasani71e6c692013-03-24 17:39:28 -07002466 @Override
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002467 public boolean setDeviceOwner(String packageName, String ownerName) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07002468 if (packageName == null
2469 || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
2470 throw new IllegalArgumentException("Invalid package name " + packageName
2471 + " for device owner");
2472 }
2473 synchronized (this) {
2474 if (mDeviceOwner == null && !isDeviceProvisioned()) {
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002475 mDeviceOwner = new DeviceOwner(packageName, ownerName);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002476 mDeviceOwner.writeOwnerFile();
2477 return true;
2478 } else {
2479 throw new IllegalStateException("Trying to set device owner to " + packageName
2480 + ", owner=" + mDeviceOwner.getPackageName()
2481 + ", device_provisioned=" + isDeviceProvisioned());
2482 }
2483 }
2484 }
2485
2486 @Override
2487 public boolean isDeviceOwner(String packageName) {
2488 synchronized (this) {
2489 return mDeviceOwner != null
2490 && mDeviceOwner.getPackageName().equals(packageName);
2491 }
2492 }
2493
2494 @Override
2495 public String getDeviceOwner() {
2496 synchronized (this) {
2497 if (mDeviceOwner != null) {
2498 return mDeviceOwner.getPackageName();
2499 }
2500 }
2501 return null;
2502 }
2503
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002504 @Override
2505 public String getDeviceOwnerName() {
2506 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
2507 synchronized (this) {
2508 if (mDeviceOwner != null) {
2509 return mDeviceOwner.getName();
2510 }
2511 }
2512 return null;
2513 }
2514
Amith Yamasani71e6c692013-03-24 17:39:28 -07002515 private boolean isDeviceProvisioned() {
2516 return Settings.Global.getInt(mContext.getContentResolver(),
2517 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
2518 }
2519
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002520 private void enforceCrossUserPermission(int userHandle) {
2521 if (userHandle < 0) {
2522 throw new IllegalArgumentException("Invalid userId " + userHandle);
2523 }
2524 final int callingUid = Binder.getCallingUid();
2525 if (userHandle == UserHandle.getUserId(callingUid)) return;
2526 if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
2527 mContext.enforceCallingOrSelfPermission(
2528 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
2529 + " INTERACT_ACROSS_USERS_FULL permission");
2530 }
2531 }
2532
Amith Yamasani71e6c692013-03-24 17:39:28 -07002533 private void enableIfNecessary(String packageName, int userId) {
2534 try {
2535 IPackageManager ipm = AppGlobals.getPackageManager();
2536 ApplicationInfo ai = ipm.getApplicationInfo(packageName,
2537 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2538 userId);
2539 if (ai.enabledSetting
2540 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
2541 ipm.setApplicationEnabledSetting(packageName,
2542 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002543 PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
Amith Yamasani71e6c692013-03-24 17:39:28 -07002544 }
2545 } catch (RemoteException e) {
2546 }
2547 }
2548
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002549 @Override
2550 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2551 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2552 != PackageManager.PERMISSION_GRANTED) {
2553
2554 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
2555 + Binder.getCallingPid()
2556 + ", uid=" + Binder.getCallingUid());
2557 return;
2558 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002559
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002560 final Printer p = new PrintWriterPrinter(pw);
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002561
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002562 synchronized (this) {
2563 p.println("Current Device Policy Manager state:");
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002564
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002565 int userCount = mUserData.size();
2566 for (int u = 0; u < userCount; u++) {
2567 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
2568 p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
2569 final int N = policy.mAdminList.size();
2570 for (int i=0; i<N; i++) {
2571 ActiveAdmin ap = policy.mAdminList.get(i);
2572 if (ap != null) {
2573 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
2574 pw.println(":");
2575 ap.dump(" ", pw);
2576 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002577 }
Konstantin Lopyrev32558232010-05-20 16:18:05 -07002578
Amith Yamasani599dd7c2012-09-14 23:20:08 -07002579 pw.println(" ");
2580 pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
2581 }
Dianne Hackborn87bba1e2010-02-26 17:25:54 -08002582 }
2583 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002584
2585 static class DeviceOwner {
2586 private static final String DEVICE_OWNER_XML = "device_owner.xml";
2587 private static final String TAG_DEVICE_OWNER = "device-owner";
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002588 private static final String ATTR_NAME = "name";
Amith Yamasani71e6c692013-03-24 17:39:28 -07002589 private static final String ATTR_PACKAGE = "package";
2590 private String mPackageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002591 private String mOwnerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002592
2593 DeviceOwner() {
2594 readOwnerFile();
2595 }
2596
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002597 DeviceOwner(String packageName, String ownerName) {
Amith Yamasani71e6c692013-03-24 17:39:28 -07002598 this.mPackageName = packageName;
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002599 this.mOwnerName = ownerName;
Amith Yamasani71e6c692013-03-24 17:39:28 -07002600 }
2601
2602 static boolean isRegistered() {
2603 return new File(Environment.getSystemSecureDirectory(),
2604 DEVICE_OWNER_XML).exists();
2605 }
2606
2607 String getPackageName() {
2608 return mPackageName;
2609 }
2610
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002611 String getName() {
2612 return mOwnerName;
2613 }
2614
Amith Yamasani71e6c692013-03-24 17:39:28 -07002615 static boolean isInstalled(String packageName, PackageManager pm) {
2616 try {
2617 PackageInfo pi;
2618 if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
2619 if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
2620 return true;
2621 }
2622 }
2623 } catch (NameNotFoundException nnfe) {
2624 Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
2625 }
2626 return false;
2627 }
2628
2629 void readOwnerFile() {
2630 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2631 DEVICE_OWNER_XML));
2632 try {
2633 FileInputStream input = file.openRead();
2634 XmlPullParser parser = Xml.newPullParser();
2635 parser.setInput(input, null);
2636 int type;
2637 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2638 && type != XmlPullParser.START_TAG) {
2639 }
2640 String tag = parser.getName();
2641 if (!TAG_DEVICE_OWNER.equals(tag)) {
2642 throw new XmlPullParserException(
2643 "Device Owner file does not start with device-owner tag: found " + tag);
2644 }
2645 mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002646 mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
Amith Yamasani71e6c692013-03-24 17:39:28 -07002647 input.close();
2648 } catch (XmlPullParserException xppe) {
2649 Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
2650 } catch (IOException ioe) {
2651 Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
2652 }
2653 }
2654
2655 void writeOwnerFile() {
2656 synchronized (this) {
2657 writeOwnerFileLocked();
2658 }
2659 }
2660
2661 private void writeOwnerFileLocked() {
2662 AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
2663 DEVICE_OWNER_XML));
2664 try {
2665 FileOutputStream output = file.startWrite();
2666 XmlSerializer out = new FastXmlSerializer();
2667 out.setOutput(output, "utf-8");
2668 out.startDocument(null, true);
2669 out.startTag(null, TAG_DEVICE_OWNER);
2670 out.attribute(null, ATTR_PACKAGE, mPackageName);
Geoffrey Borggaard334c7e32013-08-08 14:31:36 -04002671 if (mOwnerName != null) {
2672 out.attribute(null, ATTR_NAME, mOwnerName);
2673 }
Amith Yamasani71e6c692013-03-24 17:39:28 -07002674 out.endTag(null, TAG_DEVICE_OWNER);
2675 out.endDocument();
2676 out.flush();
2677 file.finishWrite(output);
2678 } catch (IOException ioe) {
2679 Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
2680 }
2681 }
2682 }
Dianne Hackbornd6847842010-01-12 18:14:19 -08002683}