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