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