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