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