DevicePolicyManagerService.java revision df83afaf299666e99c519aa86e7e082b7c116e95
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.common.FastXmlSerializer; 20import com.android.internal.widget.LockPatternUtils; 21 22import org.xmlpull.v1.XmlPullParser; 23import org.xmlpull.v1.XmlPullParserException; 24import org.xmlpull.v1.XmlSerializer; 25 26import android.app.DeviceAdmin; 27import android.app.DeviceAdminInfo; 28import android.app.DevicePolicyManager; 29import android.app.IDevicePolicyManager; 30import android.content.ComponentName; 31import android.content.ContentResolver; 32import android.content.Context; 33import android.content.Intent; 34import android.content.pm.PackageManager; 35import android.content.pm.ResolveInfo; 36import android.os.Binder; 37import android.os.IBinder; 38import android.os.IPowerManager; 39import android.os.PowerManager; 40import android.os.RecoverySystem; 41import android.os.RemoteException; 42import android.os.ServiceManager; 43import android.provider.Settings; 44import android.util.Log; 45import android.util.Xml; 46 47import java.io.File; 48import java.io.FileInputStream; 49import java.io.FileOutputStream; 50import java.io.IOException; 51import java.util.List; 52 53/** 54 * Implementation of the device policy APIs. 55 */ 56public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 57 private static final String TAG = "DevicePolicyManagerService"; 58 59 private final Context mContext; 60 61 IPowerManager mIPowerManager; 62 63 int mActivePasswordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED; 64 int mActivePasswordLength = 0; 65 int mFailedPasswordAttempts = 0; 66 67 ActiveAdmin mActiveAdmin; 68 69 static class ActiveAdmin { 70 ActiveAdmin(DeviceAdminInfo _info) { 71 info = _info; 72 } 73 74 final DeviceAdminInfo info; 75 int getUid() { return info.getActivityInfo().applicationInfo.uid; } 76 77 int passwordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED; 78 int minimumPasswordLength = 0; 79 long maximumTimeToUnlock = 0; 80 } 81 82 /** 83 * Instantiates the service. 84 */ 85 public DevicePolicyManagerService(Context context) { 86 mContext = context; 87 } 88 89 private IPowerManager getIPowerManager() { 90 if (mIPowerManager == null) { 91 IBinder b = ServiceManager.getService(Context.POWER_SERVICE); 92 mIPowerManager = IPowerManager.Stub.asInterface(b); 93 } 94 return mIPowerManager; 95 } 96 97 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException { 98 if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingUid()) { 99 if (who != null) { 100 if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName) 101 || !who.getClassName().equals(mActiveAdmin.info.getActivityInfo().name)) { 102 throw new SecurityException("Current admin is not " + who); 103 } 104 } 105 return mActiveAdmin; 106 } 107 throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid()); 108 } 109 110 111 void sendAdminCommandLocked(ActiveAdmin policy, String action) { 112 Intent intent = new Intent(action); 113 intent.setComponent(policy.info.getComponent()); 114 mContext.sendBroadcast(intent); 115 } 116 117 ComponentName getActiveAdminLocked() { 118 if (mActiveAdmin != null) { 119 return mActiveAdmin.info.getComponent(); 120 } 121 return null; 122 } 123 124 void removeActiveAdminLocked(ComponentName adminReceiver) { 125 ComponentName cur = getActiveAdminLocked(); 126 if (cur != null && cur.equals(adminReceiver)) { 127 sendAdminCommandLocked(mActiveAdmin, 128 DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLED); 129 // XXX need to wait for it to complete. 130 mActiveAdmin = null; 131 } 132 } 133 134 public DeviceAdminInfo findAdmin(ComponentName adminName) { 135 Intent resolveIntent = new Intent(); 136 resolveIntent.setComponent(adminName); 137 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers( 138 resolveIntent, PackageManager.GET_META_DATA); 139 if (infos == null || infos.size() <= 0) { 140 throw new IllegalArgumentException("Unknown admin: " + adminName); 141 } 142 143 try { 144 return new DeviceAdminInfo(mContext, infos.get(0)); 145 } catch (XmlPullParserException e) { 146 Log.w(TAG, "Bad device admin requested: " + adminName, e); 147 return null; 148 } catch (IOException e) { 149 Log.w(TAG, "Bad device admin requested: " + adminName, e); 150 return null; 151 } 152 } 153 154 private static JournaledFile makeJournaledFile() { 155 final String base = "/data/system/device_policies.xml"; 156 return new JournaledFile(new File(base), new File(base + ".tmp")); 157 } 158 159 private void saveSettingsLocked() { 160 JournaledFile journal = makeJournaledFile(); 161 FileOutputStream stream = null; 162 try { 163 stream = new FileOutputStream(journal.chooseForWrite(), false); 164 XmlSerializer out = new FastXmlSerializer(); 165 out.setOutput(stream, "utf-8"); 166 out.startDocument(null, true); 167 168 out.startTag(null, "policies"); 169 170 ActiveAdmin ap = mActiveAdmin; 171 if (ap != null) { 172 out.startTag(null, "admin"); 173 out.attribute(null, "name", ap.info.getComponent().flattenToString()); 174 if (ap.passwordMode != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) { 175 out.startTag(null, "password-mode"); 176 out.attribute(null, "value", Integer.toString(ap.passwordMode)); 177 out.endTag(null, "password-mode"); 178 if (ap.minimumPasswordLength > 0) { 179 out.startTag(null, "min-password-length"); 180 out.attribute(null, "value", Integer.toString(ap.minimumPasswordLength)); 181 out.endTag(null, "mn-password-length"); 182 } 183 } 184 if (ap.maximumTimeToUnlock != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) { 185 out.startTag(null, "max-time-to-unlock"); 186 out.attribute(null, "value", Long.toString(ap.maximumTimeToUnlock)); 187 out.endTag(null, "max-time-to-unlock"); 188 } 189 out.endTag(null, "admin"); 190 } 191 out.endTag(null, "policies"); 192 193 out.endDocument(); 194 stream.close(); 195 journal.commit(); 196 } catch (IOException e) { 197 try { 198 if (stream != null) { 199 stream.close(); 200 } 201 } catch (IOException ex) { 202 // Ignore 203 } 204 journal.rollback(); 205 } 206 } 207 208 private void loadSettingsLocked() { 209 JournaledFile journal = makeJournaledFile(); 210 FileInputStream stream = null; 211 File file = journal.chooseForRead(); 212 boolean success = false; 213 try { 214 stream = new FileInputStream(file); 215 XmlPullParser parser = Xml.newPullParser(); 216 parser.setInput(stream, null); 217 218 int type = parser.next(); 219 while (type != XmlPullParser.START_TAG) { 220 type = parser.next(); 221 } 222 String tag = parser.getName(); 223 if ("policies".equals(tag)) { 224 ActiveAdmin ap = null; 225 do { 226 type = parser.next(); 227 if (type == XmlPullParser.START_TAG) { 228 tag = parser.getName(); 229 if (ap == null) { 230 if ("admin".equals(tag)) { 231 DeviceAdminInfo dai = findAdmin( 232 ComponentName.unflattenFromString( 233 parser.getAttributeValue(null, "name"))); 234 if (dai != null) { 235 ap = new ActiveAdmin(dai); 236 } 237 } 238 } else if ("password-mode".equals(tag)) { 239 ap.passwordMode = Integer.parseInt( 240 parser.getAttributeValue(null, "value")); 241 } else if ("min-password-length".equals(tag)) { 242 ap.minimumPasswordLength = Integer.parseInt( 243 parser.getAttributeValue(null, "value")); 244 } else if ("max-time-to-unlock".equals(tag)) { 245 ap.maximumTimeToUnlock = Long.parseLong( 246 parser.getAttributeValue(null, "value")); 247 } 248 } else if (type == XmlPullParser.END_TAG) { 249 tag = parser.getName(); 250 if (ap != null && "admin".equals(tag)) { 251 mActiveAdmin = ap; 252 ap = null; 253 } 254 } 255 } while (type != XmlPullParser.END_DOCUMENT); 256 success = true; 257 } 258 } catch (NullPointerException e) { 259 Log.w(TAG, "failed parsing " + file + " " + e); 260 } catch (NumberFormatException e) { 261 Log.w(TAG, "failed parsing " + file + " " + e); 262 } catch (XmlPullParserException e) { 263 Log.w(TAG, "failed parsing " + file + " " + e); 264 } catch (IOException e) { 265 Log.w(TAG, "failed parsing " + file + " " + e); 266 } catch (IndexOutOfBoundsException e) { 267 Log.w(TAG, "failed parsing " + file + " " + e); 268 } 269 try { 270 if (stream != null) { 271 stream.close(); 272 } 273 } catch (IOException e) { 274 // Ignore 275 } 276 277 if (!success) { 278 Log.w(TAG, "No valid start tag found in policies file"); 279 } 280 281 long timeMs = getMaximumTimeToLock(); 282 if (timeMs <= 0) { 283 timeMs = Integer.MAX_VALUE; 284 } 285 try { 286 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs); 287 } catch (RemoteException e) { 288 Log.w(TAG, "Failure talking with power manager", e); 289 } 290 291 } 292 293 public void systemReady() { 294 synchronized (this) { 295 loadSettingsLocked(); 296 } 297 } 298 299 public void setActiveAdmin(ComponentName adminReceiver) { 300 mContext.enforceCallingOrSelfPermission( 301 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 302 303 DeviceAdminInfo info = findAdmin(adminReceiver); 304 if (info == null) { 305 throw new IllegalArgumentException("Bad admin: " + adminReceiver); 306 } 307 synchronized (this) { 308 long ident = Binder.clearCallingIdentity(); 309 try { 310 ComponentName cur = getActiveAdminLocked(); 311 if (cur != null && cur.equals(adminReceiver)) { 312 throw new IllegalStateException("An admin is already set"); 313 } 314 if (cur != null) { 315 removeActiveAdminLocked(adminReceiver); 316 } 317 mActiveAdmin = new ActiveAdmin(info); 318 saveSettingsLocked(); 319 sendAdminCommandLocked(mActiveAdmin, 320 DeviceAdmin.ACTION_DEVICE_ADMIN_ENABLED); 321 } finally { 322 Binder.restoreCallingIdentity(ident); 323 } 324 } 325 } 326 327 public ComponentName getActiveAdmin() { 328 synchronized (this) { 329 return getActiveAdminLocked(); 330 } 331 } 332 333 public void removeActiveAdmin(ComponentName adminReceiver) { 334 synchronized (this) { 335 if (mActiveAdmin == null || mActiveAdmin.getUid() != Binder.getCallingUid()) { 336 mContext.enforceCallingOrSelfPermission( 337 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 338 } 339 long ident = Binder.clearCallingIdentity(); 340 try { 341 removeActiveAdminLocked(adminReceiver); 342 } finally { 343 Binder.restoreCallingIdentity(ident); 344 } 345 } 346 } 347 348 public void setPasswordMode(ComponentName who, int mode) { 349 synchronized (this) { 350 if (who == null) { 351 throw new NullPointerException("ComponentName is null"); 352 } 353 ActiveAdmin ap = getActiveAdminForCallerLocked(who); 354 if (ap.passwordMode != mode) { 355 ap.passwordMode = mode; 356 saveSettingsLocked(); 357 } 358 } 359 } 360 361 public int getPasswordMode() { 362 synchronized (this) { 363 return mActiveAdmin != null ? mActiveAdmin.passwordMode 364 : DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED; 365 } 366 } 367 368 public void setMinimumPasswordLength(ComponentName who, int length) { 369 synchronized (this) { 370 if (who == null) { 371 throw new NullPointerException("ComponentName is null"); 372 } 373 ActiveAdmin ap = getActiveAdminForCallerLocked(who); 374 if (ap.minimumPasswordLength != length) { 375 ap.minimumPasswordLength = length; 376 saveSettingsLocked(); 377 } 378 } 379 } 380 381 public int getMinimumPasswordLength() { 382 synchronized (this) { 383 return mActiveAdmin != null ? mActiveAdmin.minimumPasswordLength : 0; 384 } 385 } 386 387 public boolean isActivePasswordSufficient() { 388 synchronized (this) { 389 // This API can only be called by an active device admin, 390 // so try to retrieve it to check that the caller is one. 391 getActiveAdminForCallerLocked(null); 392 return mActivePasswordMode >= getPasswordMode() 393 && mActivePasswordLength >= getMinimumPasswordLength(); 394 } 395 } 396 397 public int getCurrentFailedPasswordAttempts() { 398 synchronized (this) { 399 // This API can only be called by an active device admin, 400 // so try to retrieve it to check that the caller is one. 401 getActiveAdminForCallerLocked(null); 402 return mFailedPasswordAttempts; 403 } 404 } 405 406 public boolean resetPassword(String password) { 407 int mode; 408 synchronized (this) { 409 // This API can only be called by an active device admin, 410 // so try to retrieve it to check that the caller is one. 411 getActiveAdminForCallerLocked(null); 412 mode = getPasswordMode(); 413 if (password.length() < getMinimumPasswordLength()) { 414 return false; 415 } 416 } 417 418 // Don't do this with the lock held, because it is going to call 419 // back in to the service. 420 long ident = Binder.clearCallingIdentity(); 421 try { 422 LockPatternUtils utils = new LockPatternUtils(mContext); 423 utils.saveLockPassword(password, mode); 424 } finally { 425 Binder.restoreCallingIdentity(ident); 426 } 427 428 return true; 429 } 430 431 public void setMaximumTimeToLock(ComponentName who, long timeMs) { 432 synchronized (this) { 433 if (who == null) { 434 throw new NullPointerException("ComponentName is null"); 435 } 436 ActiveAdmin ap = getActiveAdminForCallerLocked(who); 437 if (ap.maximumTimeToUnlock != timeMs) { 438 ap.maximumTimeToUnlock = timeMs; 439 440 long ident = Binder.clearCallingIdentity(); 441 try { 442 saveSettingsLocked(); 443 if (timeMs <= 0) { 444 timeMs = Integer.MAX_VALUE; 445 } 446 try { 447 getIPowerManager().setMaximumScreenOffTimeount((int)timeMs); 448 } catch (RemoteException e) { 449 Log.w(TAG, "Failure talking with power manager", e); 450 } 451 } finally { 452 Binder.restoreCallingIdentity(ident); 453 } 454 } 455 } 456 } 457 458 public long getMaximumTimeToLock() { 459 synchronized (this) { 460 return mActiveAdmin != null ? mActiveAdmin.maximumTimeToUnlock : 0; 461 } 462 } 463 464 public void lockNow() { 465 synchronized (this) { 466 // This API can only be called by an active device admin, 467 // so try to retrieve it to check that the caller is one. 468 getActiveAdminForCallerLocked(null); 469 // STOPSHIP need to implement. 470 } 471 } 472 473 public void wipeData(int flags) { 474 synchronized (this) { 475 // This API can only be called by an active device admin, 476 // so try to retrieve it to check that the caller is one. 477 getActiveAdminForCallerLocked(null); 478 } 479 long ident = Binder.clearCallingIdentity(); 480 try { 481 RecoverySystem.rebootWipeUserData(mContext); 482 } catch (IOException e) { 483 Log.w(TAG, "Failed requesting data wipe", e); 484 } finally { 485 Binder.restoreCallingIdentity(ident); 486 } 487 } 488 489 public void setActivePasswordState(int mode, int length) { 490 mContext.enforceCallingOrSelfPermission( 491 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 492 493 synchronized (this) { 494 if (mActivePasswordMode != mode || mActivePasswordLength != length 495 || mFailedPasswordAttempts != 0) { 496 long ident = Binder.clearCallingIdentity(); 497 try { 498 mActivePasswordMode = mode; 499 mActivePasswordLength = length; 500 mFailedPasswordAttempts = 0; 501 sendAdminCommandLocked(mActiveAdmin, 502 DeviceAdmin.ACTION_PASSWORD_CHANGED); 503 } finally { 504 Binder.restoreCallingIdentity(ident); 505 } 506 } 507 } 508 } 509 510 public void reportFailedPasswordAttempt() { 511 mContext.enforceCallingOrSelfPermission( 512 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 513 514 synchronized (this) { 515 long ident = Binder.clearCallingIdentity(); 516 try { 517 mFailedPasswordAttempts++; 518 sendAdminCommandLocked(mActiveAdmin, 519 DeviceAdmin.ACTION_PASSWORD_FAILED); 520 } finally { 521 Binder.restoreCallingIdentity(ident); 522 } 523 } 524 } 525 526 public void reportSuccessfulPasswordAttempt() { 527 mContext.enforceCallingOrSelfPermission( 528 android.Manifest.permission.BIND_DEVICE_ADMIN, null); 529 530 synchronized (this) { 531 if (mFailedPasswordAttempts != 0) { 532 long ident = Binder.clearCallingIdentity(); 533 try { 534 mFailedPasswordAttempts = 0; 535 sendAdminCommandLocked(mActiveAdmin, 536 DeviceAdmin.ACTION_PASSWORD_SUCCEEDED); 537 } finally { 538 Binder.restoreCallingIdentity(ident); 539 } 540 } 541 } 542 } 543} 544