DevicePolicyManagerService.java revision 1f35d487ba1a5208e66bc960f35f6e1d874fbd1e
1/* 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 19import com.android.internal.content.PackageMonitor; 20import com.android.internal.os.storage.ExternalStorageFormatter; 21import com.android.internal.util.FastXmlSerializer; 22import com.android.internal.util.JournaledFile; 23import com.android.internal.util.XmlUtils; 24import com.android.internal.widget.LockPatternUtils; 25 26import org.xmlpull.v1.XmlPullParser; 27import org.xmlpull.v1.XmlPullParserException; 28import org.xmlpull.v1.XmlSerializer; 29 30import android.app.Activity; 31import android.app.AlarmManager; 32import android.app.PendingIntent; 33import android.app.admin.DeviceAdminInfo; 34import android.app.admin.DeviceAdminReceiver; 35import android.app.admin.DevicePolicyManager; 36import android.app.admin.IDevicePolicyManager; 37import android.content.BroadcastReceiver; 38import android.content.ComponentName; 39import android.content.ContentResolver; 40import android.content.Context; 41import android.content.Intent; 42import android.content.IntentFilter; 43import android.content.pm.PackageManager; 44import android.content.pm.PackageManager.NameNotFoundException; 45import android.content.pm.ResolveInfo; 46import android.os.Binder; 47import android.os.Handler; 48import android.os.IBinder; 49import android.os.IPowerManager; 50import android.os.PowerManager; 51import android.os.RecoverySystem; 52import android.os.RemoteCallback; 53import android.os.RemoteException; 54import android.os.ServiceManager; 55import android.os.SystemClock; 56import android.provider.Settings; 57import android.util.PrintWriterPrinter; 58import android.util.Printer; 59import android.util.Slog; 60import android.util.Xml; 61import android.view.WindowManagerPolicy; 62 63import java.io.File; 64import java.io.FileDescriptor; 65import java.io.FileInputStream; 66import java.io.FileNotFoundException; 67import java.io.FileOutputStream; 68import java.io.IOException; 69import java.io.PrintWriter; 70import java.text.DateFormat; 71import java.util.ArrayList; 72import java.util.Date; 73import java.util.HashMap; 74import java.util.List; 75import java.util.Set; 76 77/** 78 * Implementation of the device policy APIs. 79 */ 80public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 81 private static final int REQUEST_EXPIRE_PASSWORD = 5571; 82 83 static final String TAG = "DevicePolicyManagerService"; 84 85 private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms 86 87 protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION 88 = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; 89 90 private static final long MS_PER_DAY = 86400 * 1000; 91 92 final Context mContext; 93 final MyPackageMonitor mMonitor; 94 final PowerManager.WakeLock mWakeLock; 95 96 IPowerManager mIPowerManager; 97 98 int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 99 int mActivePasswordLength = 0; 100 int mActivePasswordUpperCase = 0; 101 int mActivePasswordLowerCase = 0; 102 int mActivePasswordLetters = 0; 103 int mActivePasswordNumeric = 0; 104 int mActivePasswordSymbols = 0; 105 int mActivePasswordNonLetter = 0; 106 int mFailedPasswordAttempts = 0; 107 108 int mPasswordOwner = -1; 109 Handler mHandler = new Handler(); 110 111 final HashMap<ComponentName, ActiveAdmin> mAdminMap 112 = new HashMap<ComponentName, ActiveAdmin>(); 113 final ArrayList<ActiveAdmin> mAdminList 114 = new ArrayList<ActiveAdmin>(); 115 116 BroadcastReceiver mReceiver = new BroadcastReceiver() { 117 @Override 118 public void onReceive(Context context, Intent intent) { 119 String action = intent.getAction(); 120 if (Intent.ACTION_BOOT_COMPLETED.equals(action) 121 || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) { 122 Slog.v(TAG, "Sending password expiration notifications for action " + action); 123 mHandler.post(new Runnable() { 124 public void run() { 125 handlePasswordExpirationNotification(); 126 } 127 }); 128 } 129 } 130 }; 131 132 static class ActiveAdmin { 133 final DeviceAdminInfo info; 134 135 int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 136 int minimumPasswordLength = 0; 137 int passwordHistoryLength = 0; 138 int minimumPasswordUpperCase = 0; 139 int minimumPasswordLowerCase = 0; 140 int minimumPasswordLetters = 1; 141 int minimumPasswordNumeric = 1; 142 int minimumPasswordSymbols = 1; 143 int minimumPasswordNonLetter = 0; 144 long maximumTimeToUnlock = 0; 145 int maximumFailedPasswordsForWipe = 0; 146 long passwordExpirationTimeout = 0L; 147 long passwordExpirationDate = 0L; 148 149 // TODO: review implementation decisions with frameworks team 150 boolean specifiesGlobalProxy = false; 151 String globalProxySpec = null; 152 String globalProxyExclusionList = null; 153 154 ActiveAdmin(DeviceAdminInfo _info) { 155 info = _info; 156 } 157 158 int getUid() { return info.getActivityInfo().applicationInfo.uid; } 159 160 void writeToXml(XmlSerializer out) 161 throws IllegalArgumentException, IllegalStateException, IOException { 162 out.startTag(null, "policies"); 163 info.writePoliciesToXml(out); 164 out.endTag(null, "policies"); 165 if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 166 out.startTag(null, "password-quality"); 167 out.attribute(null, "value", Integer.toString(passwordQuality)); 168 out.endTag(null, "password-quality"); 169 if (minimumPasswordLength > 0) { 170 out.startTag(null, "min-password-length"); 171 out.attribute(null, "value", Integer.toString(minimumPasswordLength)); 172 out.endTag(null, "min-password-length"); 173 } 174 if(passwordHistoryLength > 0) { 175 out.startTag(null, "password-history-length"); 176 out.attribute(null, "value", Integer.toString(passwordHistoryLength)); 177 out.endTag(null, "password-history-length"); 178 } 179 if (minimumPasswordUpperCase > 0) { 180 out.startTag(null, "min-password-uppercase"); 181 out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase)); 182 out.endTag(null, "min-password-uppercase"); 183 } 184 if (minimumPasswordLowerCase > 0) { 185 out.startTag(null, "min-password-lowercase"); 186 out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase)); 187 out.endTag(null, "min-password-lowercase"); 188 } 189 if (minimumPasswordLetters > 0) { 190 out.startTag(null, "min-password-letters"); 191 out.attribute(null, "value", Integer.toString(minimumPasswordLetters)); 192 out.endTag(null, "min-password-letters"); 193 } 194 if (minimumPasswordNumeric > 0) { 195 out.startTag(null, "min-password-numeric"); 196 out.attribute(null, "value", Integer.toString(minimumPasswordNumeric)); 197 out.endTag(null, "min-password-numeric"); 198 } 199 if (minimumPasswordSymbols > 0) { 200 out.startTag(null, "min-password-symbols"); 201 out.attribute(null, "value", Integer.toString(minimumPasswordSymbols)); 202 out.endTag(null, "min-password-symbols"); 203 } 204 if (minimumPasswordNonLetter > 0) { 205 out.startTag(null, "min-password-nonletter"); 206 out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter)); 207 out.endTag(null, "min-password-nonletter"); 208 } 209 } 210 if (maximumTimeToUnlock != 0) { 211 out.startTag(null, "max-time-to-unlock"); 212 out.attribute(null, "value", Long.toString(maximumTimeToUnlock)); 213 out.endTag(null, "max-time-to-unlock"); 214 } 215 if (maximumFailedPasswordsForWipe != 0) { 216 out.startTag(null, "max-failed-password-wipe"); 217 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe)); 218 out.endTag(null, "max-failed-password-wipe"); 219 } 220 if (specifiesGlobalProxy) { 221 out.startTag(null, "specifies-global-proxy"); 222 out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy)); 223 out.endTag(null, "specifies_global_proxy"); 224 if (globalProxySpec != null) { 225 out.startTag(null, "global-proxy-spec"); 226 out.attribute(null, "value", globalProxySpec); 227 out.endTag(null, "global-proxy-spec"); 228 } 229 if (globalProxyExclusionList != null) { 230 out.startTag(null, "global-proxy-exclusion-list"); 231 out.attribute(null, "value", globalProxyExclusionList); 232 out.endTag(null, "global-proxy-exclusion-list"); 233 } 234 } 235 if (passwordExpirationTimeout != 0L) { 236 out.startTag(null, "password-expiration-timeout"); 237 out.attribute(null, "value", Long.toString(passwordExpirationTimeout)); 238 out.endTag(null, "password-expiration-timeout"); 239 } 240 if (passwordExpirationDate != 0L) { 241 out.startTag(null, "password-expiration-date"); 242 out.attribute(null, "value", Long.toString(passwordExpirationDate)); 243 out.endTag(null, "password-expiration-date"); 244 } 245 } 246 247 void readFromXml(XmlPullParser parser) 248 throws XmlPullParserException, IOException { 249 int outerDepth = parser.getDepth(); 250 int type; 251 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 252 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 253 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 254 continue; 255 } 256 String tag = parser.getName(); 257 if ("policies".equals(tag)) { 258 info.readPoliciesFromXml(parser); 259 } else if ("password-quality".equals(tag)) { 260 passwordQuality = Integer.parseInt( 261 parser.getAttributeValue(null, "value")); 262 } else if ("min-password-length".equals(tag)) { 263 minimumPasswordLength = Integer.parseInt( 264 parser.getAttributeValue(null, "value")); 265 } else if ("password-history-length".equals(tag)) { 266 passwordHistoryLength = Integer.parseInt( 267 parser.getAttributeValue(null, "value")); 268 } else if ("min-password-uppercase".equals(tag)) { 269 minimumPasswordUpperCase = Integer.parseInt( 270 parser.getAttributeValue(null, "value")); 271 } else if ("min-password-lowercase".equals(tag)) { 272 minimumPasswordLowerCase = Integer.parseInt( 273 parser.getAttributeValue(null, "value")); 274 } else if ("min-password-letters".equals(tag)) { 275 minimumPasswordLetters = Integer.parseInt( 276 parser.getAttributeValue(null, "value")); 277 } else if ("min-password-numeric".equals(tag)) { 278 minimumPasswordNumeric = Integer.parseInt( 279 parser.getAttributeValue(null, "value")); 280 } else if ("min-password-symbols".equals(tag)) { 281 minimumPasswordSymbols = Integer.parseInt( 282 parser.getAttributeValue(null, "value")); 283 } else if ("min-password-nonletter".equals(tag)) { 284 minimumPasswordNonLetter = Integer.parseInt( 285 parser.getAttributeValue(null, "value")); 286 } else if ("max-time-to-unlock".equals(tag)) { 287 maximumTimeToUnlock = Long.parseLong( 288 parser.getAttributeValue(null, "value")); 289 } else if ("max-failed-password-wipe".equals(tag)) { 290 maximumFailedPasswordsForWipe = Integer.parseInt( 291 parser.getAttributeValue(null, "value")); 292 } else if ("specifies-global-proxy".equals(tag)) { 293 specifiesGlobalProxy = Boolean.getBoolean( 294 parser.getAttributeValue(null, "value")); 295 } else if ("global-proxy-spec".equals(tag)) { 296 globalProxySpec = 297 parser.getAttributeValue(null, "value"); 298 } else if ("global-proxy-exclusion-list".equals(tag)) { 299 globalProxyExclusionList = 300 parser.getAttributeValue(null, "value"); 301 } else if ("password-expiration-timeout".equals(tag)) { 302 passwordExpirationTimeout = Long.parseLong( 303 parser.getAttributeValue(null, "value")); 304 } else if ("password-expiration-date".equals(tag)) { 305 passwordExpirationDate = Long.parseLong( 306 parser.getAttributeValue(null, "value")); 307 } else { 308 Slog.w(TAG, "Unknown admin tag: " + tag); 309 } 310 XmlUtils.skipCurrentTag(parser); 311 } 312 } 313 314 void dump(String prefix, PrintWriter pw) { 315 pw.print(prefix); pw.print("uid="); pw.println(getUid()); 316 pw.print(prefix); pw.println("policies:"); 317 ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies(); 318 if (pols != null) { 319 for (int i=0; i<pols.size(); i++) { 320 pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag); 321 } 322 } 323 pw.print(prefix); pw.print("passwordQuality=0x"); 324 pw.println(Integer.toHexString(passwordQuality)); 325 pw.print(prefix); pw.print("minimumPasswordLength="); 326 pw.println(minimumPasswordLength); 327 pw.print(prefix); pw.print("passwordHistoryLength="); 328 pw.println(passwordHistoryLength); 329 pw.print(prefix); pw.print("minimumPasswordUpperCase="); 330 pw.println(minimumPasswordUpperCase); 331 pw.print(prefix); pw.print("minimumPasswordLowerCase="); 332 pw.println(minimumPasswordLowerCase); 333 pw.print(prefix); pw.print("minimumPasswordLetters="); 334 pw.println(minimumPasswordLetters); 335 pw.print(prefix); pw.print("minimumPasswordNumeric="); 336 pw.println(minimumPasswordNumeric); 337 pw.print(prefix); pw.print("minimumPasswordSymbols="); 338 pw.println(minimumPasswordSymbols); 339 pw.print(prefix); pw.print("minimumPasswordNonLetter="); 340 pw.println(minimumPasswordNonLetter); 341 pw.print(prefix); pw.print("maximumTimeToUnlock="); 342 pw.println(maximumTimeToUnlock); 343 pw.print(prefix); pw.print("maximumFailedPasswordsForWipe="); 344 pw.println(maximumFailedPasswordsForWipe); 345 pw.print(prefix); pw.print("specifiesGlobalProxy="); 346 pw.println(specifiesGlobalProxy); 347 pw.print(prefix); pw.print("passwordExpirationTimeout="); 348 pw.println(passwordExpirationTimeout); 349 pw.print(prefix); pw.print("passwordExpirationDate="); 350 pw.println(passwordExpirationDate); 351 if (globalProxySpec != null) { 352 pw.print(prefix); pw.print("globalProxySpec="); 353 pw.println(globalProxySpec); 354 } 355 if (globalProxyExclusionList != null) { 356 pw.print(prefix); pw.print("globalProxyEclusionList="); 357 pw.println(globalProxyExclusionList); 358 } 359 } 360 } 361 362 class MyPackageMonitor extends PackageMonitor { 363 @Override 364 public void onSomePackagesChanged() { 365 synchronized (DevicePolicyManagerService.this) { 366 boolean removed = false; 367 for (int i=mAdminList.size()-1; i>=0; i--) { 368 ActiveAdmin aa = mAdminList.get(i); 369 int change = isPackageDisappearing(aa.info.getPackageName()); 370 if (change == PACKAGE_PERMANENT_CHANGE 371 || change == PACKAGE_TEMPORARY_CHANGE) { 372 Slog.w(TAG, "Admin unexpectedly uninstalled: " 373 + aa.info.getComponent()); 374 removed = true; 375 mAdminList.remove(i); 376 } else if (isPackageModified(aa.info.getPackageName())) { 377 try { 378 mContext.getPackageManager().getReceiverInfo( 379 aa.info.getComponent(), 0); 380 } catch (NameNotFoundException e) { 381 Slog.w(TAG, "Admin package change removed component: " 382 + aa.info.getComponent()); 383 removed = true; 384 mAdminList.remove(i); 385 } 386 } 387 } 388 if (removed) { 389 validatePasswordOwnerLocked(); 390 } 391 } 392 } 393 } 394 395 /** 396 * Instantiates the service. 397 */ 398 public DevicePolicyManagerService(Context context) { 399 mContext = context; 400 mMonitor = new MyPackageMonitor(); 401 mMonitor.register(context, true); 402 mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)) 403 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM"); 404 IntentFilter filter = new IntentFilter(); 405 filter.addAction(Intent.ACTION_BOOT_COMPLETED); 406 filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); 407 context.registerReceiver(mReceiver, filter); 408 } 409 410 protected void setExpirationAlarmCheckLocked(Context context) { 411 final long expiration = getPasswordExpirationLocked(null); 412 final long now = System.currentTimeMillis(); 413 final long timeToExpire = expiration - now; 414 final long alarmTime; 415 if (timeToExpire > 0L && timeToExpire < MS_PER_DAY) { 416 // Next expiration is less than a day, set alarm for exact expiration time 417 alarmTime = now + timeToExpire; 418 } else { 419 // Check again in 24 hours... 420 alarmTime = now + MS_PER_DAY; 421 } 422 423 long token = Binder.clearCallingIdentity(); 424 try { 425 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 426 PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD, 427 new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION), 428 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); 429 am.cancel(pi); 430 am.set(AlarmManager.RTC, alarmTime, pi); 431 } finally { 432 Binder.restoreCallingIdentity(token); 433 } 434 } 435 436 private IPowerManager getIPowerManager() { 437 if (mIPowerManager == null) { 438 IBinder b = ServiceManager.getService(Context.POWER_SERVICE); 439 mIPowerManager = IPowerManager.Stub.asInterface(b); 440 } 441 return mIPowerManager; 442 } 443 444 ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) { 445 ActiveAdmin admin = mAdminMap.get(who); 446 if (admin != null 447 && who.getPackageName().equals(admin.info.getActivityInfo().packageName) 448 && who.getClassName().equals(admin.info.getActivityInfo().name)) { 449 return admin; 450 } 451 return null; 452 } 453 454 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) 455 throws SecurityException { 456 final int callingUid = Binder.getCallingUid(); 457 if (who != null) { 458 ActiveAdmin admin = mAdminMap.get(who); 459 if (admin == null) { 460 throw new SecurityException("No active admin " + who); 461 } 462 if (admin.getUid() != callingUid) { 463 throw new SecurityException("Admin " + who + " is not owned by uid " 464 + Binder.getCallingUid()); 465 } 466 if (!admin.info.usesPolicy(reqPolicy)) { 467 throw new SecurityException("Admin " + admin.info.getComponent() 468 + " did not specify uses-policy for: " 469 + admin.info.getTagForPolicy(reqPolicy)); 470 } 471 return admin; 472 } else { 473 final int N = mAdminList.size(); 474 for (int i=0; i<N; i++) { 475 ActiveAdmin admin = mAdminList.get(i); 476 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) { 477 return admin; 478 } 479 } 480 throw new SecurityException("No active admin owned by uid " 481 + Binder.getCallingUid() + " for policy #" + reqPolicy); 482 } 483 } 484 485 void sendAdminCommandLocked(ActiveAdmin admin, String action) { 486 Intent intent = new Intent(action); 487 intent.setComponent(admin.info.getComponent()); 488 if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) { 489 intent.putExtra("expiration", admin.passwordExpirationDate); 490 } 491 mContext.sendBroadcast(intent); 492 } 493 494 void sendAdminCommandLocked(String action, int reqPolicy) { 495 final int N = mAdminList.size(); 496 if (N > 0) { 497 for (int i=0; i<N; i++) { 498 ActiveAdmin admin = mAdminList.get(i); 499 if (admin.info.usesPolicy(reqPolicy)) { 500 sendAdminCommandLocked(admin, action); 501 } 502 } 503 } 504 } 505 506 void removeActiveAdminLocked(ComponentName adminReceiver) { 507 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); 508 if (admin != null) { 509 boolean doProxyCleanup = 510 admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); 511 sendAdminCommandLocked(admin, 512 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED); 513 // XXX need to wait for it to complete. 514 mAdminList.remove(admin); 515 mAdminMap.remove(adminReceiver); 516 validatePasswordOwnerLocked(); 517 if (doProxyCleanup) { 518 resetGlobalProxy(); 519 } 520 } 521 } 522 523 public DeviceAdminInfo findAdmin(ComponentName adminName) { 524 Intent resolveIntent = new Intent(); 525 resolveIntent.setComponent(adminName); 526 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers( 527 resolveIntent, PackageManager.GET_META_DATA); 528 if (infos == null || infos.size() <= 0) { 529 throw new IllegalArgumentException("Unknown admin: " + adminName); 530 } 531 532 try { 533 return new DeviceAdminInfo(mContext, infos.get(0)); 534 } catch (XmlPullParserException e) { 535 Slog.w(TAG, "Bad device admin requested: " + adminName, e); 536 return null; 537 } catch (IOException e) { 538 Slog.w(TAG, "Bad device admin requested: " + adminName, e); 539 return null; 540 } 541 } 542 543 private static JournaledFile makeJournaledFile() { 544 final String base = "/data/system/device_policies.xml"; 545 return new JournaledFile(new File(base), new File(base + ".tmp")); 546 } 547 548 private void saveSettingsLocked() { 549 JournaledFile journal = makeJournaledFile(); 550 FileOutputStream stream = null; 551 try { 552 stream = new FileOutputStream(journal.chooseForWrite(), false); 553 XmlSerializer out = new FastXmlSerializer(); 554 out.setOutput(stream, "utf-8"); 555 out.startDocument(null, true); 556 557 out.startTag(null, "policies"); 558 559 final int N = mAdminList.size(); 560 for (int i=0; i<N; i++) { 561 ActiveAdmin ap = mAdminList.get(i); 562 if (ap != null) { 563 out.startTag(null, "admin"); 564 out.attribute(null, "name", ap.info.getComponent().flattenToString()); 565 ap.writeToXml(out); 566 out.endTag(null, "admin"); 567 } 568 } 569 570 if (mPasswordOwner >= 0) { 571 out.startTag(null, "password-owner"); 572 out.attribute(null, "value", Integer.toString(mPasswordOwner)); 573 out.endTag(null, "password-owner"); 574 } 575 576 if (mFailedPasswordAttempts != 0) { 577 out.startTag(null, "failed-password-attempts"); 578 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts)); 579 out.endTag(null, "failed-password-attempts"); 580 } 581 582 if (mActivePasswordQuality != 0 || mActivePasswordLength != 0 583 || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0 584 || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0 585 || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) { 586 out.startTag(null, "active-password"); 587 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality)); 588 out.attribute(null, "length", Integer.toString(mActivePasswordLength)); 589 out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase)); 590 out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase)); 591 out.attribute(null, "letters", Integer.toString(mActivePasswordLetters)); 592 out.attribute(null, "numeric", Integer 593 .toString(mActivePasswordNumeric)); 594 out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols)); 595 out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter)); 596 out.endTag(null, "active-password"); 597 } 598 599 out.endTag(null, "policies"); 600 601 out.endDocument(); 602 stream.close(); 603 journal.commit(); 604 sendChangedNotification(); 605 } catch (IOException e) { 606 try { 607 if (stream != null) { 608 stream.close(); 609 } 610 } catch (IOException ex) { 611 // Ignore 612 } 613 journal.rollback(); 614 } 615 } 616 617 private void sendChangedNotification() { 618 Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 619 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 620 mContext.sendBroadcast(intent); 621 } 622 623 private void loadSettingsLocked() { 624 JournaledFile journal = makeJournaledFile(); 625 FileInputStream stream = null; 626 File file = journal.chooseForRead(); 627 try { 628 stream = new FileInputStream(file); 629 XmlPullParser parser = Xml.newPullParser(); 630 parser.setInput(stream, null); 631 632 int type; 633 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 634 && type != XmlPullParser.START_TAG) { 635 } 636 String tag = parser.getName(); 637 if (!"policies".equals(tag)) { 638 throw new XmlPullParserException( 639 "Settings do not start with policies tag: found " + tag); 640 } 641 type = parser.next(); 642 int outerDepth = parser.getDepth(); 643 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 644 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 645 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 646 continue; 647 } 648 tag = parser.getName(); 649 if ("admin".equals(tag)) { 650 String name = parser.getAttributeValue(null, "name"); 651 try { 652 DeviceAdminInfo dai = findAdmin( 653 ComponentName.unflattenFromString(name)); 654 if (dai != null) { 655 ActiveAdmin ap = new ActiveAdmin(dai); 656 ap.readFromXml(parser); 657 mAdminMap.put(ap.info.getComponent(), ap); 658 mAdminList.add(ap); 659 } 660 } catch (RuntimeException e) { 661 Slog.w(TAG, "Failed loading admin " + name, e); 662 } 663 } else if ("failed-password-attempts".equals(tag)) { 664 mFailedPasswordAttempts = Integer.parseInt( 665 parser.getAttributeValue(null, "value")); 666 XmlUtils.skipCurrentTag(parser); 667 } else if ("password-owner".equals(tag)) { 668 mPasswordOwner = Integer.parseInt( 669 parser.getAttributeValue(null, "value")); 670 XmlUtils.skipCurrentTag(parser); 671 } else if ("active-password".equals(tag)) { 672 mActivePasswordQuality = Integer.parseInt( 673 parser.getAttributeValue(null, "quality")); 674 mActivePasswordLength = Integer.parseInt( 675 parser.getAttributeValue(null, "length")); 676 mActivePasswordUpperCase = Integer.parseInt( 677 parser.getAttributeValue(null, "uppercase")); 678 mActivePasswordLowerCase = Integer.parseInt( 679 parser.getAttributeValue(null, "lowercase")); 680 mActivePasswordLetters = Integer.parseInt( 681 parser.getAttributeValue(null, "letters")); 682 mActivePasswordNumeric = Integer.parseInt( 683 parser.getAttributeValue(null, "numeric")); 684 mActivePasswordSymbols = Integer.parseInt( 685 parser.getAttributeValue(null, "symbols")); 686 mActivePasswordNonLetter = Integer.parseInt( 687 parser.getAttributeValue(null, "nonletter")); 688 XmlUtils.skipCurrentTag(parser); 689 } else { 690 Slog.w(TAG, "Unknown tag: " + tag); 691 XmlUtils.skipCurrentTag(parser); 692 } 693 } 694 } catch (NullPointerException e) { 695 Slog.w(TAG, "failed parsing " + file + " " + e); 696 } catch (NumberFormatException e) { 697 Slog.w(TAG, "failed parsing " + file + " " + e); 698 } catch (XmlPullParserException e) { 699 Slog.w(TAG, "failed parsing " + file + " " + e); 700 } catch (FileNotFoundException e) { 701 // Don't be noisy, this is normal if we haven't defined any policies. 702 } catch (IOException e) { 703 Slog.w(TAG, "failed parsing " + file + " " + e); 704 } catch (IndexOutOfBoundsException e) { 705 Slog.w(TAG, "failed parsing " + file + " " + e); 706 } 707 try { 708 if (stream != null) { 709 stream.close(); 710 } 711 } catch (IOException e) { 712 // Ignore 713 } 714 715 // Validate that what we stored for the password quality matches 716 // sufficiently what is currently set. Note that this is only 717 // a sanity check in case the two get out of sync; this should 718 // never normally happen. 719 LockPatternUtils utils = new LockPatternUtils(mContext); 720 if (utils.getActivePasswordQuality() < mActivePasswordQuality) { 721 Slog.w(TAG, "Active password quality 0x" 722 + Integer.toHexString(mActivePasswordQuality) 723 + " does not match actual quality 0x" 724 + Integer.toHexString(utils.getActivePasswordQuality())); 725 mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 726 mActivePasswordLength = 0; 727 mActivePasswordUpperCase = 0; 728 mActivePasswordLowerCase = 0; 729 mActivePasswordLetters = 0; 730 mActivePasswordNumeric = 0; 731 mActivePasswordSymbols = 0; 732 mActivePasswordNonLetter = 0; 733 } 734 735 validatePasswordOwnerLocked(); 736 737 long timeMs = getMaximumTimeToLock(null); 738 if (timeMs <= 0) { 739 timeMs = Integer.MAX_VALUE; 740 } 741 try { 742 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs); 743 } catch (RemoteException e) { 744 Slog.w(TAG, "Failure talking with power manager", e); 745 } 746 } 747 748 static void validateQualityConstant(int quality) { 749 switch (quality) { 750 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED: 751 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 752 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 753 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 754 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 755 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 756 return; 757 } 758 throw new IllegalArgumentException("Invalid quality constant: 0x" 759 + Integer.toHexString(quality)); 760 } 761 762 void validatePasswordOwnerLocked() { 763 if (mPasswordOwner >= 0) { 764 boolean haveOwner = false; 765 for (int i=mAdminList.size()-1; i>=0; i--) { 766 if (mAdminList.get(i).getUid() == mPasswordOwner) { 767 haveOwner = true; 768 break; 769 } 770 } 771 if (!haveOwner) { 772 Slog.w(TAG, "Previous password owner " + mPasswordOwner 773 + " no longer active; disabling"); 774 mPasswordOwner = -1; 775 } 776 } 777 } 778 779 public void systemReady() { 780 synchronized (this) { 781 loadSettingsLocked(); 782 } 783 } 784 785 private void handlePasswordExpirationNotification() { 786 synchronized (this) { 787 final long now = System.currentTimeMillis(); 788 final int N = mAdminList.size(); 789 if (N <= 0) { 790 return; 791 } 792 for (int i=0; i < N; i++) { 793 ActiveAdmin admin = mAdminList.get(i); 794 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) 795 && admin.passwordExpirationTimeout > 0L 796 && admin.passwordExpirationDate > 0L 797 && now > admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) { 798 sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); 799 } 800 } 801 setExpirationAlarmCheckLocked(mContext); 802 } 803 } 804 805 public void setActiveAdmin(ComponentName adminReceiver) { 806 mContext.enforceCallingOrSelfPermission( 807 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 808 809 DeviceAdminInfo info = findAdmin(adminReceiver); 810 if (info == null) { 811 throw new IllegalArgumentException("Bad admin: " + adminReceiver); 812 } 813 synchronized (this) { 814 long ident = Binder.clearCallingIdentity(); 815 try { 816 if (getActiveAdminUncheckedLocked(adminReceiver) != null) { 817 throw new IllegalArgumentException("Admin is already added"); 818 } 819 ActiveAdmin admin = new ActiveAdmin(info); 820 mAdminMap.put(adminReceiver, admin); 821 mAdminList.add(admin); 822 saveSettingsLocked(); 823 sendAdminCommandLocked(admin, 824 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED); 825 } finally { 826 Binder.restoreCallingIdentity(ident); 827 } 828 } 829 } 830 831 public boolean isAdminActive(ComponentName adminReceiver) { 832 synchronized (this) { 833 return getActiveAdminUncheckedLocked(adminReceiver) != null; 834 } 835 } 836 837 public List<ComponentName> getActiveAdmins() { 838 synchronized (this) { 839 final int N = mAdminList.size(); 840 if (N <= 0) { 841 return null; 842 } 843 ArrayList<ComponentName> res = new ArrayList<ComponentName>(N); 844 for (int i=0; i<N; i++) { 845 res.add(mAdminList.get(i).info.getComponent()); 846 } 847 return res; 848 } 849 } 850 851 public boolean packageHasActiveAdmins(String packageName) { 852 synchronized (this) { 853 final int N = mAdminList.size(); 854 for (int i=0; i<N; i++) { 855 if (mAdminList.get(i).info.getPackageName().equals(packageName)) { 856 return true; 857 } 858 } 859 return false; 860 } 861 } 862 863 public void removeActiveAdmin(ComponentName adminReceiver) { 864 synchronized (this) { 865 ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); 866 if (admin == null) { 867 return; 868 } 869 if (admin.getUid() != Binder.getCallingUid()) { 870 mContext.enforceCallingOrSelfPermission( 871 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 872 } 873 long ident = Binder.clearCallingIdentity(); 874 try { 875 removeActiveAdminLocked(adminReceiver); 876 } finally { 877 Binder.restoreCallingIdentity(ident); 878 } 879 } 880 } 881 882 public void setPasswordQuality(ComponentName who, int quality) { 883 validateQualityConstant(quality); 884 885 synchronized (this) { 886 if (who == null) { 887 throw new NullPointerException("ComponentName is null"); 888 } 889 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 890 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 891 if (ap.passwordQuality != quality) { 892 ap.passwordQuality = quality; 893 saveSettingsLocked(); 894 } 895 } 896 } 897 898 public int getPasswordQuality(ComponentName who) { 899 synchronized (this) { 900 int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 901 902 if (who != null) { 903 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 904 return admin != null ? admin.passwordQuality : mode; 905 } 906 907 final int N = mAdminList.size(); 908 for (int i=0; i<N; i++) { 909 ActiveAdmin admin = mAdminList.get(i); 910 if (mode < admin.passwordQuality) { 911 mode = admin.passwordQuality; 912 } 913 } 914 return mode; 915 } 916 } 917 918 public void setPasswordMinimumLength(ComponentName who, int length) { 919 synchronized (this) { 920 if (who == null) { 921 throw new NullPointerException("ComponentName is null"); 922 } 923 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 924 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 925 if (ap.minimumPasswordLength != length) { 926 ap.minimumPasswordLength = length; 927 saveSettingsLocked(); 928 } 929 } 930 } 931 932 public int getPasswordMinimumLength(ComponentName who) { 933 synchronized (this) { 934 int length = 0; 935 936 if (who != null) { 937 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 938 return admin != null ? admin.minimumPasswordLength : length; 939 } 940 941 final int N = mAdminList.size(); 942 for (int i=0; i<N; i++) { 943 ActiveAdmin admin = mAdminList.get(i); 944 if (length < admin.minimumPasswordLength) { 945 length = admin.minimumPasswordLength; 946 } 947 } 948 return length; 949 } 950 } 951 952 public void setPasswordHistoryLength(ComponentName who, int length) { 953 synchronized (this) { 954 if (who == null) { 955 throw new NullPointerException("ComponentName is null"); 956 } 957 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 958 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 959 if (ap.passwordHistoryLength != length) { 960 ap.passwordHistoryLength = length; 961 saveSettingsLocked(); 962 } 963 } 964 } 965 966 public int getPasswordHistoryLength(ComponentName who) { 967 synchronized (this) { 968 int length = 0; 969 970 if (who != null) { 971 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 972 return admin != null ? admin.passwordHistoryLength : length; 973 } 974 975 final int N = mAdminList.size(); 976 for (int i = 0; i < N; i++) { 977 ActiveAdmin admin = mAdminList.get(i); 978 if (length < admin.passwordHistoryLength) { 979 length = admin.passwordHistoryLength; 980 } 981 } 982 return length; 983 } 984 } 985 986 public void setPasswordExpirationTimeout(ComponentName who, long timeout) { 987 synchronized (this) { 988 if (who == null) { 989 throw new NullPointerException("ComponentName is null"); 990 } 991 if (timeout < 0) { 992 throw new IllegalArgumentException("Timeout must be >= 0 ms"); 993 } 994 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 995 DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD); 996 // Calling this API automatically bumps the expiration date 997 final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L; 998 ap.passwordExpirationDate = expiration; 999 ap.passwordExpirationTimeout = timeout; 1000 if (timeout > 0L) { 1001 Slog.w(TAG, "setPasswordExpiration(): password will expire on " 1002 + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT) 1003 .format(new Date(expiration))); 1004 } 1005 saveSettingsLocked(); 1006 setExpirationAlarmCheckLocked(mContext); // in case this is the first one 1007 } 1008 } 1009 1010 public long getPasswordExpirationTimeout(ComponentName who) { 1011 synchronized (this) { 1012 long timeout = 0L; 1013 if (who != null) { 1014 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1015 return admin != null ? admin.passwordExpirationTimeout : timeout; 1016 } 1017 1018 final int N = mAdminList.size(); 1019 for (int i = 0; i < N; i++) { 1020 ActiveAdmin admin = mAdminList.get(i); 1021 if (timeout == 0L || (admin.passwordExpirationTimeout != 0L 1022 && timeout > admin.passwordExpirationTimeout)) { 1023 timeout = admin.passwordExpirationTimeout; 1024 } 1025 } 1026 return timeout; 1027 } 1028 } 1029 1030 private long getPasswordExpirationLocked(ComponentName who) { 1031 long timeout = 0L; 1032 if (who != null) { 1033 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1034 return admin != null ? admin.passwordExpirationDate : timeout; 1035 } 1036 1037 final int N = mAdminList.size(); 1038 for (int i = 0; i < N; i++) { 1039 ActiveAdmin admin = mAdminList.get(i); 1040 if (timeout == 0L || (admin.passwordExpirationDate != 0 1041 && timeout > admin.passwordExpirationDate)) { 1042 timeout = admin.passwordExpirationDate; 1043 } 1044 } 1045 return timeout; 1046 } 1047 1048 public long getPasswordExpiration(ComponentName who) { 1049 synchronized (this) { 1050 return getPasswordExpirationLocked(who); 1051 } 1052 } 1053 1054 public void setPasswordMinimumUpperCase(ComponentName who, int length) { 1055 synchronized (this) { 1056 if (who == null) { 1057 throw new NullPointerException("ComponentName is null"); 1058 } 1059 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1060 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1061 if (ap.minimumPasswordUpperCase != length) { 1062 ap.minimumPasswordUpperCase = length; 1063 saveSettingsLocked(); 1064 } 1065 } 1066 } 1067 1068 public int getPasswordMinimumUpperCase(ComponentName who) { 1069 synchronized (this) { 1070 int length = 0; 1071 1072 if (who != null) { 1073 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1074 return admin != null ? admin.minimumPasswordUpperCase : length; 1075 } 1076 1077 final int N = mAdminList.size(); 1078 for (int i=0; i<N; i++) { 1079 ActiveAdmin admin = mAdminList.get(i); 1080 if (length < admin.minimumPasswordUpperCase) { 1081 length = admin.minimumPasswordUpperCase; 1082 } 1083 } 1084 return length; 1085 } 1086 } 1087 1088 public void setPasswordMinimumLowerCase(ComponentName who, int length) { 1089 synchronized (this) { 1090 if (who == null) { 1091 throw new NullPointerException("ComponentName is null"); 1092 } 1093 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1094 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1095 if (ap.minimumPasswordLowerCase != length) { 1096 ap.minimumPasswordLowerCase = length; 1097 saveSettingsLocked(); 1098 } 1099 } 1100 } 1101 1102 public int getPasswordMinimumLowerCase(ComponentName who) { 1103 synchronized (this) { 1104 int length = 0; 1105 1106 if (who != null) { 1107 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1108 return admin != null ? admin.minimumPasswordLowerCase : length; 1109 } 1110 1111 final int N = mAdminList.size(); 1112 for (int i=0; i<N; i++) { 1113 ActiveAdmin admin = mAdminList.get(i); 1114 if (length < admin.minimumPasswordLowerCase) { 1115 length = admin.minimumPasswordLowerCase; 1116 } 1117 } 1118 return length; 1119 } 1120 } 1121 1122 public void setPasswordMinimumLetters(ComponentName who, int length) { 1123 synchronized (this) { 1124 if (who == null) { 1125 throw new NullPointerException("ComponentName is null"); 1126 } 1127 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1128 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1129 if (ap.minimumPasswordLetters != length) { 1130 ap.minimumPasswordLetters = length; 1131 saveSettingsLocked(); 1132 } 1133 } 1134 } 1135 1136 public int getPasswordMinimumLetters(ComponentName who) { 1137 synchronized (this) { 1138 int length = 0; 1139 1140 if (who != null) { 1141 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1142 return admin != null ? admin.minimumPasswordLetters : length; 1143 } 1144 1145 final int N = mAdminList.size(); 1146 for (int i=0; i<N; i++) { 1147 ActiveAdmin admin = mAdminList.get(i); 1148 if (length < admin.minimumPasswordLetters) { 1149 length = admin.minimumPasswordLetters; 1150 } 1151 } 1152 return length; 1153 } 1154 } 1155 1156 public void setPasswordMinimumNumeric(ComponentName who, int length) { 1157 synchronized (this) { 1158 if (who == null) { 1159 throw new NullPointerException("ComponentName is null"); 1160 } 1161 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1162 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1163 if (ap.minimumPasswordNumeric != length) { 1164 ap.minimumPasswordNumeric = length; 1165 saveSettingsLocked(); 1166 } 1167 } 1168 } 1169 1170 public int getPasswordMinimumNumeric(ComponentName who) { 1171 synchronized (this) { 1172 int length = 0; 1173 1174 if (who != null) { 1175 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1176 return admin != null ? admin.minimumPasswordNumeric : length; 1177 } 1178 1179 final int N = mAdminList.size(); 1180 for (int i = 0; i < N; i++) { 1181 ActiveAdmin admin = mAdminList.get(i); 1182 if (length < admin.minimumPasswordNumeric) { 1183 length = admin.minimumPasswordNumeric; 1184 } 1185 } 1186 return length; 1187 } 1188 } 1189 1190 public void setPasswordMinimumSymbols(ComponentName who, int length) { 1191 synchronized (this) { 1192 if (who == null) { 1193 throw new NullPointerException("ComponentName is null"); 1194 } 1195 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1196 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1197 if (ap.minimumPasswordSymbols != length) { 1198 ap.minimumPasswordSymbols = length; 1199 saveSettingsLocked(); 1200 } 1201 } 1202 } 1203 1204 public int getPasswordMinimumSymbols(ComponentName who) { 1205 synchronized (this) { 1206 int length = 0; 1207 1208 if (who != null) { 1209 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1210 return admin != null ? admin.minimumPasswordSymbols : length; 1211 } 1212 1213 final int N = mAdminList.size(); 1214 for (int i=0; i<N; i++) { 1215 ActiveAdmin admin = mAdminList.get(i); 1216 if (length < admin.minimumPasswordSymbols) { 1217 length = admin.minimumPasswordSymbols; 1218 } 1219 } 1220 return length; 1221 } 1222 } 1223 1224 public void setPasswordMinimumNonLetter(ComponentName who, int length) { 1225 synchronized (this) { 1226 if (who == null) { 1227 throw new NullPointerException("ComponentName is null"); 1228 } 1229 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1230 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1231 if (ap.minimumPasswordNonLetter != length) { 1232 ap.minimumPasswordNonLetter = length; 1233 saveSettingsLocked(); 1234 } 1235 } 1236 } 1237 1238 public int getPasswordMinimumNonLetter(ComponentName who) { 1239 synchronized (this) { 1240 int length = 0; 1241 1242 if (who != null) { 1243 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1244 return admin != null ? admin.minimumPasswordNonLetter : length; 1245 } 1246 1247 final int N = mAdminList.size(); 1248 for (int i=0; i<N; i++) { 1249 ActiveAdmin admin = mAdminList.get(i); 1250 if (length < admin.minimumPasswordNonLetter) { 1251 length = admin.minimumPasswordNonLetter; 1252 } 1253 } 1254 return length; 1255 } 1256 } 1257 1258 public boolean isActivePasswordSufficient() { 1259 synchronized (this) { 1260 // This API can only be called by an active device admin, 1261 // so try to retrieve it to check that the caller is one. 1262 getActiveAdminForCallerLocked(null, 1263 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1264 if (mActivePasswordQuality < getPasswordQuality(null) 1265 || mActivePasswordLength < getPasswordMinimumLength(null)) { 1266 return false; 1267 } 1268 if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { 1269 return true; 1270 } 1271 return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null) 1272 && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null) 1273 && mActivePasswordLetters >= getPasswordMinimumLetters(null) 1274 && mActivePasswordNumeric >= getPasswordMinimumNumeric(null) 1275 && mActivePasswordSymbols >= getPasswordMinimumSymbols(null) 1276 && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null); 1277 } 1278 } 1279 1280 public int getCurrentFailedPasswordAttempts() { 1281 synchronized (this) { 1282 // This API can only be called by an active device admin, 1283 // so try to retrieve it to check that the caller is one. 1284 getActiveAdminForCallerLocked(null, 1285 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); 1286 return mFailedPasswordAttempts; 1287 } 1288 } 1289 1290 public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) { 1291 synchronized (this) { 1292 // This API can only be called by an active device admin, 1293 // so try to retrieve it to check that the caller is one. 1294 getActiveAdminForCallerLocked(who, 1295 DeviceAdminInfo.USES_POLICY_WIPE_DATA); 1296 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1297 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); 1298 if (ap.maximumFailedPasswordsForWipe != num) { 1299 ap.maximumFailedPasswordsForWipe = num; 1300 saveSettingsLocked(); 1301 } 1302 } 1303 } 1304 1305 public int getMaximumFailedPasswordsForWipe(ComponentName who) { 1306 synchronized (this) { 1307 int count = 0; 1308 1309 if (who != null) { 1310 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1311 return admin != null ? admin.maximumFailedPasswordsForWipe : count; 1312 } 1313 1314 final int N = mAdminList.size(); 1315 for (int i=0; i<N; i++) { 1316 ActiveAdmin admin = mAdminList.get(i); 1317 if (count == 0) { 1318 count = admin.maximumFailedPasswordsForWipe; 1319 } else if (admin.maximumFailedPasswordsForWipe != 0 1320 && count > admin.maximumFailedPasswordsForWipe) { 1321 count = admin.maximumFailedPasswordsForWipe; 1322 } 1323 } 1324 return count; 1325 } 1326 } 1327 1328 public boolean resetPassword(String password, int flags) { 1329 int quality; 1330 synchronized (this) { 1331 // This API can only be called by an active device admin, 1332 // so try to retrieve it to check that the caller is one. 1333 getActiveAdminForCallerLocked(null, 1334 DeviceAdminInfo.USES_POLICY_RESET_PASSWORD); 1335 quality = getPasswordQuality(null); 1336 if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 1337 int realQuality = LockPatternUtils.computePasswordQuality(password); 1338 if (realQuality < quality 1339 && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { 1340 Slog.w(TAG, "resetPassword: password quality 0x" 1341 + Integer.toHexString(quality) 1342 + " does not meet required quality 0x" 1343 + Integer.toHexString(quality)); 1344 return false; 1345 } 1346 quality = Math.max(realQuality, quality); 1347 } 1348 int length = getPasswordMinimumLength(null); 1349 if (password.length() < length) { 1350 Slog.w(TAG, "resetPassword: password length " + password.length() 1351 + " does not meet required length " + length); 1352 return false; 1353 } 1354 if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { 1355 int letters = 0; 1356 int uppercase = 0; 1357 int lowercase = 0; 1358 int numbers = 0; 1359 int symbols = 0; 1360 int nonletter = 0; 1361 for (int i = 0; i < password.length(); i++) { 1362 char c = password.charAt(i); 1363 if (c >= 'A' && c <= 'Z') { 1364 letters++; 1365 uppercase++; 1366 } else if (c >= 'a' && c <= 'z') { 1367 letters++; 1368 lowercase++; 1369 } else if (c >= '0' && c <= '9') { 1370 numbers++; 1371 nonletter++; 1372 } else { 1373 symbols++; 1374 nonletter++; 1375 } 1376 } 1377 int neededLetters = getPasswordMinimumLetters(null); 1378 if(letters < neededLetters) { 1379 Slog.w(TAG, "resetPassword: number of letters " + letters 1380 + " does not meet required number of letters " + neededLetters); 1381 return false; 1382 } 1383 int neededNumbers = getPasswordMinimumNumeric(null); 1384 if (numbers < neededNumbers) { 1385 Slog 1386 .w(TAG, "resetPassword: number of numerical digits " + numbers 1387 + " does not meet required number of numerical digits " 1388 + neededNumbers); 1389 return false; 1390 } 1391 int neededLowerCase = getPasswordMinimumLowerCase(null); 1392 if (lowercase < neededLowerCase) { 1393 Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase 1394 + " does not meet required number of lowercase letters " 1395 + neededLowerCase); 1396 return false; 1397 } 1398 int neededUpperCase = getPasswordMinimumUpperCase(null); 1399 if (uppercase < neededUpperCase) { 1400 Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase 1401 + " does not meet required number of uppercase letters " 1402 + neededUpperCase); 1403 return false; 1404 } 1405 int neededSymbols = getPasswordMinimumSymbols(null); 1406 if (symbols < neededSymbols) { 1407 Slog.w(TAG, "resetPassword: number of special symbols " + symbols 1408 + " does not meet required number of special symbols " + neededSymbols); 1409 return false; 1410 } 1411 int neededNonLetter = getPasswordMinimumNonLetter(null); 1412 if (nonletter < neededNonLetter) { 1413 Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter 1414 + " does not meet required number of non-letter characters " 1415 + neededNonLetter); 1416 return false; 1417 } 1418 } 1419 1420 LockPatternUtils utils = new LockPatternUtils(mContext); 1421 if(utils.checkPasswordHistory(password)) { 1422 Slog.w(TAG, "resetPassword: password is the same as one of the last " 1423 + getPasswordHistoryLength(null) + " passwords"); 1424 return false; 1425 } 1426 } 1427 1428 int callingUid = Binder.getCallingUid(); 1429 if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) { 1430 Slog.w(TAG, "resetPassword: already set by another uid and not entered by user"); 1431 return false; 1432 } 1433 1434 // Don't do this with the lock held, because it is going to call 1435 // back in to the service. 1436 long ident = Binder.clearCallingIdentity(); 1437 try { 1438 LockPatternUtils utils = new LockPatternUtils(mContext); 1439 utils.saveLockPassword(password, quality); 1440 synchronized (this) { 1441 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) 1442 != 0 ? callingUid : -1; 1443 if (mPasswordOwner != newOwner) { 1444 mPasswordOwner = newOwner; 1445 saveSettingsLocked(); 1446 } 1447 } 1448 } finally { 1449 Binder.restoreCallingIdentity(ident); 1450 } 1451 1452 return true; 1453 } 1454 1455 public void setMaximumTimeToLock(ComponentName who, long timeMs) { 1456 synchronized (this) { 1457 if (who == null) { 1458 throw new NullPointerException("ComponentName is null"); 1459 } 1460 ActiveAdmin ap = getActiveAdminForCallerLocked(who, 1461 DeviceAdminInfo.USES_POLICY_FORCE_LOCK); 1462 if (ap.maximumTimeToUnlock != timeMs) { 1463 ap.maximumTimeToUnlock = timeMs; 1464 1465 long ident = Binder.clearCallingIdentity(); 1466 try { 1467 saveSettingsLocked(); 1468 1469 timeMs = getMaximumTimeToLock(null); 1470 if (timeMs <= 0) { 1471 timeMs = Integer.MAX_VALUE; 1472 } 1473 1474 try { 1475 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs); 1476 } catch (RemoteException e) { 1477 Slog.w(TAG, "Failure talking with power manager", e); 1478 } 1479 } finally { 1480 Binder.restoreCallingIdentity(ident); 1481 } 1482 } 1483 } 1484 } 1485 1486 public long getMaximumTimeToLock(ComponentName who) { 1487 synchronized (this) { 1488 long time = 0; 1489 1490 if (who != null) { 1491 ActiveAdmin admin = getActiveAdminUncheckedLocked(who); 1492 return admin != null ? admin.maximumTimeToUnlock : time; 1493 } 1494 1495 final int N = mAdminList.size(); 1496 for (int i=0; i<N; i++) { 1497 ActiveAdmin admin = mAdminList.get(i); 1498 if (time == 0) { 1499 time = admin.maximumTimeToUnlock; 1500 } else if (admin.maximumTimeToUnlock != 0 1501 && time > admin.maximumTimeToUnlock) { 1502 time = admin.maximumTimeToUnlock; 1503 } 1504 } 1505 return time; 1506 } 1507 } 1508 1509 public void lockNow() { 1510 synchronized (this) { 1511 // This API can only be called by an active device admin, 1512 // so try to retrieve it to check that the caller is one. 1513 getActiveAdminForCallerLocked(null, 1514 DeviceAdminInfo.USES_POLICY_FORCE_LOCK); 1515 long ident = Binder.clearCallingIdentity(); 1516 try { 1517 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(), 1518 WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN); 1519 } catch (RemoteException e) { 1520 } finally { 1521 Binder.restoreCallingIdentity(ident); 1522 } 1523 } 1524 } 1525 1526 void wipeDataLocked(int flags) { 1527 if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) { 1528 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET); 1529 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME); 1530 mWakeLock.acquire(10000); 1531 mContext.startService(intent); 1532 } else { 1533 try { 1534 RecoverySystem.rebootWipeUserData(mContext); 1535 } catch (IOException e) { 1536 Slog.w(TAG, "Failed requesting data wipe", e); 1537 } 1538 } 1539 } 1540 1541 public void wipeData(int flags) { 1542 synchronized (this) { 1543 // This API can only be called by an active device admin, 1544 // so try to retrieve it to check that the caller is one. 1545 getActiveAdminForCallerLocked(null, 1546 DeviceAdminInfo.USES_POLICY_WIPE_DATA); 1547 long ident = Binder.clearCallingIdentity(); 1548 try { 1549 wipeDataLocked(flags); 1550 } finally { 1551 Binder.restoreCallingIdentity(ident); 1552 } 1553 } 1554 } 1555 1556 public void getRemoveWarning(ComponentName comp, final RemoteCallback result) { 1557 mContext.enforceCallingOrSelfPermission( 1558 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 1559 1560 synchronized (this) { 1561 ActiveAdmin admin = getActiveAdminUncheckedLocked(comp); 1562 if (admin == null) { 1563 try { 1564 result.sendResult(null); 1565 } catch (RemoteException e) { 1566 } 1567 return; 1568 } 1569 Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED); 1570 intent.setComponent(admin.info.getComponent()); 1571 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { 1572 @Override 1573 public void onReceive(Context context, Intent intent) { 1574 try { 1575 result.sendResult(getResultExtras(false)); 1576 } catch (RemoteException e) { 1577 } 1578 } 1579 }, null, Activity.RESULT_OK, null, null); 1580 } 1581 } 1582 1583 public void setActivePasswordState(int quality, int length, int letters, int uppercase, 1584 int lowercase, int numbers, int symbols, int nonletter) { 1585 mContext.enforceCallingOrSelfPermission( 1586 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 1587 1588 validateQualityConstant(quality); 1589 1590 synchronized (this) { 1591 if (mActivePasswordQuality != quality || mActivePasswordLength != length 1592 || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters 1593 || mActivePasswordUpperCase != uppercase 1594 || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers 1595 || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) { 1596 long ident = Binder.clearCallingIdentity(); 1597 try { 1598 mActivePasswordQuality = quality; 1599 mActivePasswordLength = length; 1600 mActivePasswordLetters = letters; 1601 mActivePasswordLowerCase = lowercase; 1602 mActivePasswordUpperCase = uppercase; 1603 mActivePasswordNumeric = numbers; 1604 mActivePasswordSymbols = symbols; 1605 mActivePasswordNonLetter = nonletter; 1606 mFailedPasswordAttempts = 0; 1607 saveSettingsLocked(); 1608 updatePasswordExpirationsLocked(); 1609 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, 1610 DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); 1611 } finally { 1612 Binder.restoreCallingIdentity(ident); 1613 } 1614 } 1615 } 1616 } 1617 1618 private void updatePasswordExpirationsLocked() { 1619 final int N = mAdminList.size(); 1620 if (N > 0) { 1621 for (int i=0; i<N; i++) { 1622 ActiveAdmin admin = mAdminList.get(i); 1623 if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) { 1624 admin.passwordExpirationDate = System.currentTimeMillis() 1625 + admin.passwordExpirationTimeout; 1626 } 1627 } 1628 saveSettingsLocked(); 1629 } 1630 } 1631 1632 public void reportFailedPasswordAttempt() { 1633 mContext.enforceCallingOrSelfPermission( 1634 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 1635 1636 synchronized (this) { 1637 long ident = Binder.clearCallingIdentity(); 1638 try { 1639 mFailedPasswordAttempts++; 1640 saveSettingsLocked(); 1641 int max = getMaximumFailedPasswordsForWipe(null); 1642 if (max > 0 && mFailedPasswordAttempts >= max) { 1643 wipeDataLocked(0); 1644 } 1645 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED, 1646 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); 1647 } finally { 1648 Binder.restoreCallingIdentity(ident); 1649 } 1650 } 1651 } 1652 1653 public void reportSuccessfulPasswordAttempt() { 1654 mContext.enforceCallingOrSelfPermission( 1655 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 1656 1657 synchronized (this) { 1658 if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) { 1659 long ident = Binder.clearCallingIdentity(); 1660 try { 1661 mFailedPasswordAttempts = 0; 1662 mPasswordOwner = -1; 1663 saveSettingsLocked(); 1664 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, 1665 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); 1666 } finally { 1667 Binder.restoreCallingIdentity(ident); 1668 } 1669 } 1670 } 1671 } 1672 1673 public ComponentName setGlobalProxy(ComponentName who, String proxySpec, 1674 String exclusionList) { 1675 synchronized(this) { 1676 if (who == null) { 1677 throw new NullPointerException("ComponentName is null"); 1678 } 1679 1680 ActiveAdmin admin = getActiveAdminForCallerLocked(who, 1681 DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); 1682 1683 // Scan through active admins and find if anyone has already 1684 // set the global proxy. 1685 final int N = mAdminList.size(); 1686 Set<ComponentName> compSet = mAdminMap.keySet(); 1687 for (ComponentName component : compSet) { 1688 ActiveAdmin ap = mAdminMap.get(component); 1689 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) { 1690 // Another admin already sets the global proxy 1691 // Return it to the caller. 1692 return component; 1693 } 1694 } 1695 if (proxySpec == null) { 1696 admin.specifiesGlobalProxy = false; 1697 admin.globalProxySpec = null; 1698 admin.globalProxyExclusionList = null; 1699 } else { 1700 1701 admin.specifiesGlobalProxy = true; 1702 admin.globalProxySpec = proxySpec; 1703 admin.globalProxyExclusionList = exclusionList; 1704 } 1705 1706 // Reset the global proxy accordingly 1707 // Do this using system permissions, as apps cannot write to secure settings 1708 long origId = Binder.clearCallingIdentity(); 1709 resetGlobalProxy(); 1710 Binder.restoreCallingIdentity(origId); 1711 return null; 1712 } 1713 } 1714 1715 public ComponentName getGlobalProxyAdmin() { 1716 synchronized(this) { 1717 // Scan through active admins and find if anyone has already 1718 // set the global proxy. 1719 final int N = mAdminList.size(); 1720 for (int i = 0; i < N; i++) { 1721 ActiveAdmin ap = mAdminList.get(i); 1722 if (ap.specifiesGlobalProxy) { 1723 // Device admin sets the global proxy 1724 // Return it to the caller. 1725 return ap.info.getComponent(); 1726 } 1727 } 1728 } 1729 // No device admin sets the global proxy. 1730 return null; 1731 } 1732 1733 private void resetGlobalProxy() { 1734 final int N = mAdminList.size(); 1735 for (int i = 0; i < N; i++) { 1736 ActiveAdmin ap = mAdminList.get(i); 1737 if (ap.specifiesGlobalProxy) { 1738 saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList); 1739 return; 1740 } 1741 } 1742 // No device admins defining global proxies - reset global proxy settings to none 1743 saveGlobalProxy(null, null); 1744 } 1745 1746 private void saveGlobalProxy(String proxySpec, String exclusionList) { 1747 if (exclusionList == null) { 1748 exclusionList = ""; 1749 } 1750 if (proxySpec == null) { 1751 proxySpec = ""; 1752 } 1753 // Remove white spaces 1754 proxySpec = proxySpec.trim(); 1755 String data[] = proxySpec.split(":"); 1756 int proxyPort = 8080; 1757 if (data.length > 1) { 1758 try { 1759 proxyPort = Integer.parseInt(data[1]); 1760 } catch (NumberFormatException e) {} 1761 } 1762 exclusionList = exclusionList.trim(); 1763 ContentResolver res = mContext.getContentResolver(); 1764 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]); 1765 Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort); 1766 Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, 1767 exclusionList); 1768 } 1769 1770 @Override 1771 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1772 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1773 != PackageManager.PERMISSION_GRANTED) { 1774 1775 pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid=" 1776 + Binder.getCallingPid() 1777 + ", uid=" + Binder.getCallingUid()); 1778 return; 1779 } 1780 1781 final Printer p = new PrintWriterPrinter(pw); 1782 1783 synchronized (this) { 1784 p.println("Current Device Policy Manager state:"); 1785 1786 p.println(" Enabled Device Admins:"); 1787 final int N = mAdminList.size(); 1788 for (int i=0; i<N; i++) { 1789 ActiveAdmin ap = mAdminList.get(i); 1790 if (ap != null) { 1791 pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString()); 1792 pw.println(":"); 1793 ap.dump(" ", pw); 1794 } 1795 } 1796 1797 pw.println(" "); 1798 pw.print(" mActivePasswordQuality=0x"); 1799 pw.println(Integer.toHexString(mActivePasswordQuality)); 1800 pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength); 1801 pw.print(" mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase); 1802 pw.print(" mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase); 1803 pw.print(" mActivePasswordLetters="); pw.println(mActivePasswordLetters); 1804 pw.print(" mActivePasswordNumeric="); pw.println(mActivePasswordNumeric); 1805 pw.print(" mActivePasswordSymbols="); pw.println(mActivePasswordSymbols); 1806 pw.print(" mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter); 1807 pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts); 1808 pw.print(" mPasswordOwner="); pw.println(mPasswordOwner); 1809 } 1810 } 1811} 1812