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