2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.dreams;
19 import static android.Manifest.permission.BIND_DREAM_SERVICE;
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;
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;
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.util.ArrayList;
60 import java.util.List;
62 import libcore.util.Objects;
65 * Service api for managing dreams.
69 public final class DreamManagerService extends SystemService {
70 private static final boolean DEBUG = false;
71 private static final String TAG = "DreamManagerService";
73 private final Object mLock = new Object();
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;
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;
92 private AmbientDisplayConfiguration mDozeConfig;
94 public DreamManagerService(Context context) {
97 mHandler = new DreamHandler(FgThread.get().getLooper());
98 mController = new DreamController(context, mHandler, mControllerListener);
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);
107 public void onStart() {
108 publishBinderService(DreamService.DREAM_SERVICE, new BinderService());
109 publishLocalService(DreamManagerInternal.class, new LocalService());
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);
118 mContext.registerReceiver(new BroadcastReceiver() {
120 public void onReceive(Context context, Intent intent) {
121 writePulseGestureEnabled();
122 synchronized (mLock) {
123 stopDreamLocked(false /*immediate*/);
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();
134 private void dumpInternal(PrintWriter pw) {
135 pw.println("DREAM MANAGER (dumpsys dreams)");
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());
150 DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
152 public void dump(PrintWriter pw, String prefix) {
153 mController.dump(pw);
158 private boolean isDreamingInternal() {
159 synchronized (mLock) {
160 return mCurrentDreamToken != null && !mCurrentDreamIsTest
161 && !mCurrentDreamIsWaking;
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);
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*/);
184 private void finishSelfInternal(IBinder token, boolean immediate) {
186 Slog.d(TAG, "Dream finished: " + token + ", immediate=" + immediate);
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);
203 private void testDreamInternal(ComponentName dream, int userId) {
204 synchronized (mLock) {
205 startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
209 private void startDreamInternal(boolean doze) {
210 final int userId = ActivityManager.getCurrentUser();
211 final ComponentName dream = chooseDreamForUser(doze, userId);
213 synchronized (mLock) {
214 startDreamLocked(dream, false /*isTest*/, doze, userId);
219 private void stopDreamInternal(boolean immediate) {
220 synchronized (mLock) {
221 stopDreamLocked(immediate);
225 private void startDozingInternal(IBinder token, int screenState,
226 int screenBrightness) {
228 Slog.d(TAG, "Dream requested to start dozing: " + token
229 + ", screenState=" + screenState
230 + ", screenBrightness=" + screenBrightness);
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();
247 private void stopDozingInternal(IBinder token) {
249 Slog.d(TAG, "Dream requested to stop dozing: " + token);
252 synchronized (mLock) {
253 if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
254 mCurrentDreamIsDozing = false;
255 mDozeWakeLock.release();
256 mPowerManagerInternal.setDozeOverrideFromDreamManager(
257 Display.STATE_UNKNOWN, PowerManager.BRIGHTNESS_DEFAULT);
262 private ComponentName chooseDreamForUser(boolean doze, int userId) {
264 ComponentName dozeComponent = getDozeComponent(userId);
265 return validateDream(dozeComponent) ? dozeComponent : null;
267 ComponentName[] dreams = getDreamComponentsForUser(userId);
268 return dreams != null && dreams.length != 0 ? dreams[0] : null;
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");
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.");
287 private ComponentName[] getDreamComponentsForUser(int userId) {
288 String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
289 Settings.Secure.SCREENSAVER_COMPONENTS,
291 ComponentName[] components = componentsFromString(names);
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);
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);
311 return validComponents.toArray(new ComponentName[validComponents.size()]);
314 private void setDreamComponentsForUser(int userId, ComponentName[] componentNames) {
315 Settings.Secure.putStringForUser(mContext.getContentResolver(),
316 Settings.Secure.SCREENSAVER_COMPONENTS,
317 componentsToString(componentNames),
321 private ComponentName getDefaultDreamComponentForUser(int userId) {
322 String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
323 Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
325 return name == null ? null : ComponentName.unflattenFromString(name);
328 private ComponentName getDozeComponent() {
329 return getDozeComponent(ActivityManager.getCurrentUser());
332 private ComponentName getDozeComponent(int userId) {
333 if (mDozeConfig.enabled(userId)) {
334 return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent());
341 private ServiceInfo getServiceInfo(ComponentName name) {
343 return name != null ? mContext.getPackageManager().getServiceInfo(name,
344 PackageManager.MATCH_DEBUG_TRIAGED_MISSING) : null;
345 } catch (NameNotFoundException e) {
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.");
360 stopDreamLocked(true /*immediate*/);
362 Slog.i(TAG, "Entering dreamland.");
364 final Binder newToken = new Binder();
365 mCurrentDreamToken = newToken;
366 mCurrentDreamName = name;
367 mCurrentDreamIsTest = isTest;
368 mCurrentDreamCanDoze = canDoze;
369 mCurrentDreamUserId = userId;
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)));
377 private void stopDreamLocked(final boolean immediate) {
378 if (mCurrentDreamToken != null) {
380 Slog.i(TAG, "Leaving dreamland.");
381 cleanupDreamLocked();
382 } else if (mCurrentDreamIsWaking) {
383 return; // already waking
385 Slog.i(TAG, "Gently waking up from dream.");
386 mCurrentDreamIsWaking = true;
389 mHandler.post(new Runnable() {
392 Slog.i(TAG, "Performing gentle wake from dream.");
393 mController.stopDream(immediate);
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();
410 mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
411 mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
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);
422 private void writePulseGestureEnabled() {
423 ComponentName name = getDozeComponent();
424 boolean dozeEnabled = validateDream(name);
425 LocalServices.getService(InputManagerInternal.class).setPulseGestureEnabled(dozeEnabled);
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) {
435 names.append(componentName.flattenToString());
438 return names.toString();
441 private static ComponentName[] componentsFromString(String names) {
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]);
450 return componentNames;
453 private final DreamController.Listener mControllerListener = new DreamController.Listener() {
455 public void onDreamStopped(Binder token) {
456 synchronized (mLock) {
457 if (mCurrentDreamToken == token) {
458 cleanupDreamLocked();
464 private final ContentObserver mDozeEnabledObserver = new ContentObserver(null) {
466 public void onChange(boolean selfChange) {
467 writePulseGestureEnabled();
472 * Handler for asynchronous operations performed by the dream manager.
473 * Ensures operations to {@link DreamController} are single-threaded.
475 private final class DreamHandler extends Handler {
476 public DreamHandler(Looper looper) {
477 super(looper, null, true /*async*/);
481 private final class BinderService extends IDreamManager.Stub {
482 @Override // Binder call
483 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
484 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
485 != PackageManager.PERMISSION_GRANTED) {
486 pw.println("Permission Denial: can't dump DreamManager from from pid="
487 + Binder.getCallingPid()
488 + ", uid=" + Binder.getCallingUid());
492 final long ident = Binder.clearCallingIdentity();
496 Binder.restoreCallingIdentity(ident);
500 @Override // Binder call
501 public ComponentName[] getDreamComponents() {
502 checkPermission(android.Manifest.permission.READ_DREAM_STATE);
504 final int userId = UserHandle.getCallingUserId();
505 final long ident = Binder.clearCallingIdentity();
507 return getDreamComponentsForUser(userId);
509 Binder.restoreCallingIdentity(ident);
513 @Override // Binder call
514 public void setDreamComponents(ComponentName[] componentNames) {
515 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
517 final int userId = UserHandle.getCallingUserId();
518 final long ident = Binder.clearCallingIdentity();
520 setDreamComponentsForUser(userId, componentNames);
522 Binder.restoreCallingIdentity(ident);
526 @Override // Binder call
527 public ComponentName getDefaultDreamComponent() {
528 checkPermission(android.Manifest.permission.READ_DREAM_STATE);
530 final int userId = UserHandle.getCallingUserId();
531 final long ident = Binder.clearCallingIdentity();
533 return getDefaultDreamComponentForUser(userId);
535 Binder.restoreCallingIdentity(ident);
539 @Override // Binder call
540 public boolean isDreaming() {
541 checkPermission(android.Manifest.permission.READ_DREAM_STATE);
543 final long ident = Binder.clearCallingIdentity();
545 return isDreamingInternal();
547 Binder.restoreCallingIdentity(ident);
551 @Override // Binder call
552 public void dream() {
553 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
555 final long ident = Binder.clearCallingIdentity();
557 requestDreamInternal();
559 Binder.restoreCallingIdentity(ident);
563 @Override // Binder call
564 public void testDream(ComponentName dream) {
566 throw new IllegalArgumentException("dream must not be null");
568 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
570 final int callingUserId = UserHandle.getCallingUserId();
571 final int currentUserId = ActivityManager.getCurrentUser();
572 if (callingUserId != currentUserId) {
573 // This check is inherently prone to races but at least it's something.
574 Slog.w(TAG, "Aborted attempt to start a test dream while a different "
575 + " user is active: callingUserId=" + callingUserId
576 + ", currentUserId=" + currentUserId);
579 final long ident = Binder.clearCallingIdentity();
581 testDreamInternal(dream, callingUserId);
583 Binder.restoreCallingIdentity(ident);
587 @Override // Binder call
588 public void awaken() {
589 checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
591 final long ident = Binder.clearCallingIdentity();
593 requestAwakenInternal();
595 Binder.restoreCallingIdentity(ident);
599 @Override // Binder call
600 public void finishSelf(IBinder token, boolean immediate) {
601 // Requires no permission, called by Dream from an arbitrary process.
603 throw new IllegalArgumentException("token must not be null");
606 final long ident = Binder.clearCallingIdentity();
608 finishSelfInternal(token, immediate);
610 Binder.restoreCallingIdentity(ident);
614 @Override // Binder call
615 public void startDozing(IBinder token, int screenState, int screenBrightness) {
616 // Requires no permission, called by Dream from an arbitrary process.
618 throw new IllegalArgumentException("token must not be null");
621 final long ident = Binder.clearCallingIdentity();
623 startDozingInternal(token, screenState, screenBrightness);
625 Binder.restoreCallingIdentity(ident);
629 @Override // Binder call
630 public void stopDozing(IBinder token) {
631 // Requires no permission, called by Dream from an arbitrary process.
633 throw new IllegalArgumentException("token must not be null");
636 final long ident = Binder.clearCallingIdentity();
638 stopDozingInternal(token);
640 Binder.restoreCallingIdentity(ident);
645 private final class LocalService extends DreamManagerInternal {
647 public void startDream(boolean doze) {
648 startDreamInternal(doze);
652 public void stopDream(boolean immediate) {
653 stopDreamInternal(immediate);
657 public boolean isDreaming() {
658 return isDreamingInternal();
662 private final Runnable mSystemPropertiesChanged = new Runnable() {
665 if (DEBUG) Slog.d(TAG, "System properties changed");
666 synchronized (mLock) {
667 if (mCurrentDreamName != null && mCurrentDreamCanDoze
668 && !mCurrentDreamName.equals(getDozeComponent())) {
669 // May have updated the doze component, wake up
670 mPowerManager.wakeUp(SystemClock.uptimeMillis(),
671 "android.server.dreams:SYSPROP");