DreamManagerService.java revision 69515b2261335be4bd8510ed5a40a6bed3d7b48f
1/* 2 * Copyright (C) 2012 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.dreams; 18 19import static android.Manifest.permission.BIND_DREAM_SERVICE; 20 21import com.android.internal.hardware.AmbientDisplayConfiguration; 22import com.android.internal.util.DumpUtils; 23import com.android.server.FgThread; 24import com.android.server.LocalServices; 25import com.android.server.SystemService; 26 27import android.Manifest; 28import android.app.ActivityManager; 29import android.content.BroadcastReceiver; 30import android.content.ComponentName; 31import android.content.Context; 32import android.content.Intent; 33import android.content.IntentFilter; 34import android.content.pm.PackageManager; 35import android.content.pm.PackageManager.NameNotFoundException; 36import android.content.pm.ServiceInfo; 37import android.database.ContentObserver; 38import android.hardware.input.InputManagerInternal; 39import android.os.Binder; 40import android.os.Build; 41import android.os.Handler; 42import android.os.IBinder; 43import android.os.Looper; 44import android.os.PowerManager; 45import android.os.PowerManagerInternal; 46import android.os.SystemClock; 47import android.os.SystemProperties; 48import android.os.UserHandle; 49import android.provider.Settings; 50import android.service.dreams.DreamManagerInternal; 51import android.service.dreams.DreamService; 52import android.service.dreams.IDreamManager; 53import android.text.TextUtils; 54import android.util.Slog; 55import android.view.Display; 56 57import java.io.FileDescriptor; 58import java.io.PrintWriter; 59import java.util.ArrayList; 60import java.util.List; 61 62import libcore.util.Objects; 63 64/** 65 * Service api for managing dreams. 66 * 67 * @hide 68 */ 69public final class DreamManagerService extends SystemService { 70 private static final boolean DEBUG = false; 71 private static final String TAG = "DreamManagerService"; 72 73 private final Object mLock = new Object(); 74 75 private final Context mContext; 76 private final DreamHandler mHandler; 77 private final DreamController mController; 78 private final PowerManager mPowerManager; 79 private final PowerManagerInternal mPowerManagerInternal; 80 private final PowerManager.WakeLock mDozeWakeLock; 81 82 private Binder mCurrentDreamToken; 83 private ComponentName mCurrentDreamName; 84 private int mCurrentDreamUserId; 85 private boolean mCurrentDreamIsTest; 86 private boolean mCurrentDreamCanDoze; 87 private boolean mCurrentDreamIsDozing; 88 private boolean mCurrentDreamIsWaking; 89 private Runnable mStopDreamRunnable; 90 private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN; 91 private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; 92 93 private AmbientDisplayConfiguration mDozeConfig; 94 95 public DreamManagerService(Context context) { 96 super(context); 97 mContext = context; 98 mHandler = new DreamHandler(FgThread.get().getLooper()); 99 mController = new DreamController(context, mHandler, mControllerListener); 100 101 mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 102 mPowerManagerInternal = getLocalService(PowerManagerInternal.class); 103 mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG); 104 mDozeConfig = new AmbientDisplayConfiguration(mContext); 105 } 106 107 @Override 108 public void onStart() { 109 publishBinderService(DreamService.DREAM_SERVICE, new BinderService()); 110 publishLocalService(DreamManagerInternal.class, new LocalService()); 111 } 112 113 @Override 114 public void onBootPhase(int phase) { 115 if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 116 if (Build.IS_DEBUGGABLE) { 117 SystemProperties.addChangeCallback(mSystemPropertiesChanged); 118 } 119 mContext.registerReceiver(new BroadcastReceiver() { 120 @Override 121 public void onReceive(Context context, Intent intent) { 122 writePulseGestureEnabled(); 123 synchronized (mLock) { 124 stopDreamLocked(false /*immediate*/); 125 } 126 } 127 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); 128 mContext.getContentResolver().registerContentObserver( 129 Settings.Secure.getUriFor(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP), false, 130 mDozeEnabledObserver, UserHandle.USER_ALL); 131 writePulseGestureEnabled(); 132 } 133 } 134 135 private void dumpInternal(PrintWriter pw) { 136 pw.println("DREAM MANAGER (dumpsys dreams)"); 137 pw.println(); 138 pw.println("mCurrentDreamToken=" + mCurrentDreamToken); 139 pw.println("mCurrentDreamName=" + mCurrentDreamName); 140 pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId); 141 pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest); 142 pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze); 143 pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing); 144 pw.println("mCurrentDreamIsWaking=" + mCurrentDreamIsWaking); 145 pw.println("mCurrentDreamDozeScreenState=" 146 + Display.stateToString(mCurrentDreamDozeScreenState)); 147 pw.println("mCurrentDreamDozeScreenBrightness=" + mCurrentDreamDozeScreenBrightness); 148 pw.println("getDozeComponent()=" + getDozeComponent()); 149 pw.println(); 150 151 DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() { 152 @Override 153 public void dump(PrintWriter pw, String prefix) { 154 mController.dump(pw); 155 } 156 }, pw, "", 200); 157 } 158 159 private boolean isDreamingInternal() { 160 synchronized (mLock) { 161 return mCurrentDreamToken != null && !mCurrentDreamIsTest 162 && !mCurrentDreamIsWaking; 163 } 164 } 165 166 private void requestDreamInternal() { 167 // Ask the power manager to nap. It will eventually call back into 168 // startDream() if/when it is appropriate to start dreaming. 169 // Because napping could cause the screen to turn off immediately if the dream 170 // cannot be started, we keep one eye open and gently poke user activity. 171 long time = SystemClock.uptimeMillis(); 172 mPowerManager.userActivity(time, true /*noChangeLights*/); 173 mPowerManager.nap(time); 174 } 175 176 private void requestAwakenInternal() { 177 // Treat an explicit request to awaken as user activity so that the 178 // device doesn't immediately go to sleep if the timeout expired, 179 // for example when being undocked. 180 long time = SystemClock.uptimeMillis(); 181 mPowerManager.userActivity(time, false /*noChangeLights*/); 182 stopDreamInternal(false /*immediate*/); 183 } 184 185 private void finishSelfInternal(IBinder token, boolean immediate) { 186 if (DEBUG) { 187 Slog.d(TAG, "Dream finished: " + token + ", immediate=" + immediate); 188 } 189 190 // Note that a dream finishing and self-terminating is not 191 // itself considered user activity. If the dream is ending because 192 // the user interacted with the device then user activity will already 193 // have been poked so the device will stay awake a bit longer. 194 // If the dream is ending on its own for other reasons and no wake 195 // locks are held and the user activity timeout has expired then the 196 // device may simply go to sleep. 197 synchronized (mLock) { 198 if (mCurrentDreamToken == token) { 199 stopDreamLocked(immediate); 200 } 201 } 202 } 203 204 private void testDreamInternal(ComponentName dream, int userId) { 205 synchronized (mLock) { 206 startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId); 207 } 208 } 209 210 private void startDreamInternal(boolean doze) { 211 final int userId = ActivityManager.getCurrentUser(); 212 final ComponentName dream = chooseDreamForUser(doze, userId); 213 if (dream != null) { 214 synchronized (mLock) { 215 startDreamLocked(dream, false /*isTest*/, doze, userId); 216 } 217 } 218 } 219 220 private void stopDreamInternal(boolean immediate) { 221 synchronized (mLock) { 222 stopDreamLocked(immediate); 223 } 224 } 225 226 private void startDozingInternal(IBinder token, int screenState, 227 int screenBrightness) { 228 if (DEBUG) { 229 Slog.d(TAG, "Dream requested to start dozing: " + token 230 + ", screenState=" + screenState 231 + ", screenBrightness=" + screenBrightness); 232 } 233 234 synchronized (mLock) { 235 if (mCurrentDreamToken == token && mCurrentDreamCanDoze) { 236 mCurrentDreamDozeScreenState = screenState; 237 mCurrentDreamDozeScreenBrightness = screenBrightness; 238 mPowerManagerInternal.setDozeOverrideFromDreamManager( 239 screenState, screenBrightness); 240 if (!mCurrentDreamIsDozing) { 241 mCurrentDreamIsDozing = true; 242 mDozeWakeLock.acquire(); 243 } 244 } 245 } 246 } 247 248 private void stopDozingInternal(IBinder token) { 249 if (DEBUG) { 250 Slog.d(TAG, "Dream requested to stop dozing: " + token); 251 } 252 253 synchronized (mLock) { 254 if (mCurrentDreamToken == token && mCurrentDreamIsDozing) { 255 mCurrentDreamIsDozing = false; 256 mDozeWakeLock.release(); 257 mPowerManagerInternal.setDozeOverrideFromDreamManager( 258 Display.STATE_UNKNOWN, PowerManager.BRIGHTNESS_DEFAULT); 259 } 260 } 261 } 262 263 private ComponentName chooseDreamForUser(boolean doze, int userId) { 264 if (doze) { 265 ComponentName dozeComponent = getDozeComponent(userId); 266 return validateDream(dozeComponent) ? dozeComponent : null; 267 } 268 ComponentName[] dreams = getDreamComponentsForUser(userId); 269 return dreams != null && dreams.length != 0 ? dreams[0] : null; 270 } 271 272 private boolean validateDream(ComponentName component) { 273 if (component == null) return false; 274 final ServiceInfo serviceInfo = getServiceInfo(component); 275 if (serviceInfo == null) { 276 Slog.w(TAG, "Dream " + component + " does not exist"); 277 return false; 278 } else if (serviceInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP 279 && !BIND_DREAM_SERVICE.equals(serviceInfo.permission)) { 280 Slog.w(TAG, "Dream " + component 281 + " is not available because its manifest is missing the " + BIND_DREAM_SERVICE 282 + " permission on the dream service declaration."); 283 return false; 284 } 285 return true; 286 } 287 288 private ComponentName[] getDreamComponentsForUser(int userId) { 289 String names = Settings.Secure.getStringForUser(mContext.getContentResolver(), 290 Settings.Secure.SCREENSAVER_COMPONENTS, 291 userId); 292 ComponentName[] components = componentsFromString(names); 293 294 // first, ensure components point to valid services 295 List<ComponentName> validComponents = new ArrayList<ComponentName>(); 296 if (components != null) { 297 for (ComponentName component : components) { 298 if (validateDream(component)) { 299 validComponents.add(component); 300 } 301 } 302 } 303 304 // fallback to the default dream component if necessary 305 if (validComponents.isEmpty()) { 306 ComponentName defaultDream = getDefaultDreamComponentForUser(userId); 307 if (defaultDream != null) { 308 Slog.w(TAG, "Falling back to default dream " + defaultDream); 309 validComponents.add(defaultDream); 310 } 311 } 312 return validComponents.toArray(new ComponentName[validComponents.size()]); 313 } 314 315 private void setDreamComponentsForUser(int userId, ComponentName[] componentNames) { 316 Settings.Secure.putStringForUser(mContext.getContentResolver(), 317 Settings.Secure.SCREENSAVER_COMPONENTS, 318 componentsToString(componentNames), 319 userId); 320 } 321 322 private ComponentName getDefaultDreamComponentForUser(int userId) { 323 String name = Settings.Secure.getStringForUser(mContext.getContentResolver(), 324 Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT, 325 userId); 326 return name == null ? null : ComponentName.unflattenFromString(name); 327 } 328 329 private ComponentName getDozeComponent() { 330 return getDozeComponent(ActivityManager.getCurrentUser()); 331 } 332 333 private ComponentName getDozeComponent(int userId) { 334 if (mDozeConfig.enabled(userId)) { 335 return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent()); 336 } else { 337 return null; 338 } 339 340 } 341 342 private ServiceInfo getServiceInfo(ComponentName name) { 343 try { 344 return name != null ? mContext.getPackageManager().getServiceInfo(name, 345 PackageManager.MATCH_DEBUG_TRIAGED_MISSING) : null; 346 } catch (NameNotFoundException e) { 347 return null; 348 } 349 } 350 351 private void startDreamLocked(final ComponentName name, 352 final boolean isTest, final boolean canDoze, final int userId) { 353 if (mStopDreamRunnable != null) { 354 mHandler.removeCallbacks(mStopDreamRunnable); 355 mStopDreamRunnable = null; 356 } 357 358 if (Objects.equal(mCurrentDreamName, name) 359 && mCurrentDreamIsTest == isTest 360 && mCurrentDreamCanDoze == canDoze 361 && mCurrentDreamUserId == userId) { 362 Slog.i(TAG, "Already in target dream."); 363 return; 364 } 365 366 stopDreamLocked(true /*immediate*/); 367 368 Slog.i(TAG, "Entering dreamland."); 369 370 final Binder newToken = new Binder(); 371 mCurrentDreamToken = newToken; 372 mCurrentDreamName = name; 373 mCurrentDreamIsTest = isTest; 374 mCurrentDreamCanDoze = canDoze; 375 mCurrentDreamUserId = userId; 376 377 PowerManager.WakeLock wakeLock = mPowerManager 378 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream"); 379 mHandler.post(wakeLock.wrap( 380 () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock))); 381 } 382 383 private void stopDreamLocked(final boolean immediate) { 384 if (mCurrentDreamToken != null) { 385 if (immediate) { 386 Slog.i(TAG, "Leaving dreamland."); 387 cleanupDreamLocked(); 388 } else if (mCurrentDreamIsWaking) { 389 return; // already waking 390 } else { 391 Slog.i(TAG, "Gently waking up from dream."); 392 mCurrentDreamIsWaking = true; 393 } 394 395 mStopDreamRunnable = new Runnable() { 396 @Override 397 public void run() { 398 Slog.i(TAG, "Performing gentle wake from dream."); 399 mController.stopDream(immediate); 400 mStopDreamRunnable = null; 401 } 402 }; 403 mHandler.post(mStopDreamRunnable); 404 } 405 } 406 407 private void cleanupDreamLocked() { 408 mCurrentDreamToken = null; 409 mCurrentDreamName = null; 410 mCurrentDreamIsTest = false; 411 mCurrentDreamCanDoze = false; 412 mCurrentDreamUserId = 0; 413 mCurrentDreamIsWaking = false; 414 if (mCurrentDreamIsDozing) { 415 mCurrentDreamIsDozing = false; 416 mDozeWakeLock.release(); 417 } 418 mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN; 419 mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; 420 } 421 422 private void checkPermission(String permission) { 423 if (mContext.checkCallingOrSelfPermission(permission) 424 != PackageManager.PERMISSION_GRANTED) { 425 throw new SecurityException("Access denied to process: " + Binder.getCallingPid() 426 + ", must have permission " + permission); 427 } 428 } 429 430 private void writePulseGestureEnabled() { 431 ComponentName name = getDozeComponent(); 432 boolean dozeEnabled = validateDream(name); 433 LocalServices.getService(InputManagerInternal.class).setPulseGestureEnabled(dozeEnabled); 434 } 435 436 private static String componentsToString(ComponentName[] componentNames) { 437 StringBuilder names = new StringBuilder(); 438 if (componentNames != null) { 439 for (ComponentName componentName : componentNames) { 440 if (names.length() > 0) { 441 names.append(','); 442 } 443 names.append(componentName.flattenToString()); 444 } 445 } 446 return names.toString(); 447 } 448 449 private static ComponentName[] componentsFromString(String names) { 450 if (names == null) { 451 return null; 452 } 453 String[] namesArray = names.split(","); 454 ComponentName[] componentNames = new ComponentName[namesArray.length]; 455 for (int i = 0; i < namesArray.length; i++) { 456 componentNames[i] = ComponentName.unflattenFromString(namesArray[i]); 457 } 458 return componentNames; 459 } 460 461 private final DreamController.Listener mControllerListener = new DreamController.Listener() { 462 @Override 463 public void onDreamStopped(Binder token) { 464 synchronized (mLock) { 465 if (mCurrentDreamToken == token) { 466 cleanupDreamLocked(); 467 } 468 } 469 } 470 }; 471 472 private final ContentObserver mDozeEnabledObserver = new ContentObserver(null) { 473 @Override 474 public void onChange(boolean selfChange) { 475 writePulseGestureEnabled(); 476 } 477 }; 478 479 /** 480 * Handler for asynchronous operations performed by the dream manager. 481 * Ensures operations to {@link DreamController} are single-threaded. 482 */ 483 private final class DreamHandler extends Handler { 484 public DreamHandler(Looper looper) { 485 super(looper, null, true /*async*/); 486 } 487 } 488 489 private final class BinderService extends IDreamManager.Stub { 490 @Override // Binder call 491 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 492 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 493 != PackageManager.PERMISSION_GRANTED) { 494 pw.println("Permission Denial: can't dump DreamManager from from pid=" 495 + Binder.getCallingPid() 496 + ", uid=" + Binder.getCallingUid()); 497 return; 498 } 499 500 final long ident = Binder.clearCallingIdentity(); 501 try { 502 dumpInternal(pw); 503 } finally { 504 Binder.restoreCallingIdentity(ident); 505 } 506 } 507 508 @Override // Binder call 509 public ComponentName[] getDreamComponents() { 510 checkPermission(android.Manifest.permission.READ_DREAM_STATE); 511 512 final int userId = UserHandle.getCallingUserId(); 513 final long ident = Binder.clearCallingIdentity(); 514 try { 515 return getDreamComponentsForUser(userId); 516 } finally { 517 Binder.restoreCallingIdentity(ident); 518 } 519 } 520 521 @Override // Binder call 522 public void setDreamComponents(ComponentName[] componentNames) { 523 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); 524 525 final int userId = UserHandle.getCallingUserId(); 526 final long ident = Binder.clearCallingIdentity(); 527 try { 528 setDreamComponentsForUser(userId, componentNames); 529 } finally { 530 Binder.restoreCallingIdentity(ident); 531 } 532 } 533 534 @Override // Binder call 535 public ComponentName getDefaultDreamComponent() { 536 checkPermission(android.Manifest.permission.READ_DREAM_STATE); 537 538 final int userId = UserHandle.getCallingUserId(); 539 final long ident = Binder.clearCallingIdentity(); 540 try { 541 return getDefaultDreamComponentForUser(userId); 542 } finally { 543 Binder.restoreCallingIdentity(ident); 544 } 545 } 546 547 @Override // Binder call 548 public boolean isDreaming() { 549 checkPermission(android.Manifest.permission.READ_DREAM_STATE); 550 551 final long ident = Binder.clearCallingIdentity(); 552 try { 553 return isDreamingInternal(); 554 } finally { 555 Binder.restoreCallingIdentity(ident); 556 } 557 } 558 559 @Override // Binder call 560 public void dream() { 561 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); 562 563 final long ident = Binder.clearCallingIdentity(); 564 try { 565 requestDreamInternal(); 566 } finally { 567 Binder.restoreCallingIdentity(ident); 568 } 569 } 570 571 @Override // Binder call 572 public void testDream(ComponentName dream) { 573 if (dream == null) { 574 throw new IllegalArgumentException("dream must not be null"); 575 } 576 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); 577 578 final int callingUserId = UserHandle.getCallingUserId(); 579 final int currentUserId = ActivityManager.getCurrentUser(); 580 if (callingUserId != currentUserId) { 581 // This check is inherently prone to races but at least it's something. 582 Slog.w(TAG, "Aborted attempt to start a test dream while a different " 583 + " user is active: callingUserId=" + callingUserId 584 + ", currentUserId=" + currentUserId); 585 return; 586 } 587 final long ident = Binder.clearCallingIdentity(); 588 try { 589 testDreamInternal(dream, callingUserId); 590 } finally { 591 Binder.restoreCallingIdentity(ident); 592 } 593 } 594 595 @Override // Binder call 596 public void awaken() { 597 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); 598 599 final long ident = Binder.clearCallingIdentity(); 600 try { 601 requestAwakenInternal(); 602 } finally { 603 Binder.restoreCallingIdentity(ident); 604 } 605 } 606 607 @Override // Binder call 608 public void finishSelf(IBinder token, boolean immediate) { 609 // Requires no permission, called by Dream from an arbitrary process. 610 if (token == null) { 611 throw new IllegalArgumentException("token must not be null"); 612 } 613 614 final long ident = Binder.clearCallingIdentity(); 615 try { 616 finishSelfInternal(token, immediate); 617 } finally { 618 Binder.restoreCallingIdentity(ident); 619 } 620 } 621 622 @Override // Binder call 623 public void startDozing(IBinder token, int screenState, int screenBrightness) { 624 // Requires no permission, called by Dream from an arbitrary process. 625 if (token == null) { 626 throw new IllegalArgumentException("token must not be null"); 627 } 628 629 final long ident = Binder.clearCallingIdentity(); 630 try { 631 startDozingInternal(token, screenState, screenBrightness); 632 } finally { 633 Binder.restoreCallingIdentity(ident); 634 } 635 } 636 637 @Override // Binder call 638 public void stopDozing(IBinder token) { 639 // Requires no permission, called by Dream from an arbitrary process. 640 if (token == null) { 641 throw new IllegalArgumentException("token must not be null"); 642 } 643 644 final long ident = Binder.clearCallingIdentity(); 645 try { 646 stopDozingInternal(token); 647 } finally { 648 Binder.restoreCallingIdentity(ident); 649 } 650 } 651 } 652 653 private final class LocalService extends DreamManagerInternal { 654 @Override 655 public void startDream(boolean doze) { 656 startDreamInternal(doze); 657 } 658 659 @Override 660 public void stopDream(boolean immediate) { 661 stopDreamInternal(immediate); 662 } 663 664 @Override 665 public boolean isDreaming() { 666 return isDreamingInternal(); 667 } 668 } 669 670 private final Runnable mSystemPropertiesChanged = new Runnable() { 671 @Override 672 public void run() { 673 if (DEBUG) Slog.d(TAG, "System properties changed"); 674 synchronized (mLock) { 675 if (mCurrentDreamName != null && mCurrentDreamCanDoze 676 && !mCurrentDreamName.equals(getDozeComponent())) { 677 // May have updated the doze component, wake up 678 mPowerManager.wakeUp(SystemClock.uptimeMillis(), 679 "android.server.dreams:SYSPROP"); 680 } 681 } 682 } 683 }; 684} 685