Home | History | Annotate | Download | only in dreams
      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 
     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
    103     public void onStart() {
    104         publishBinderService(DreamService.DREAM_SERVICE, new BinderService());
    105         publishLocalService(DreamManagerInternal.class, new LocalService());
    106     }
    107 
    108     @Override
    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 
    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 
    154     private boolean isDreamingInternal() {
    155         synchronized (mLock) {
    156             return mCurrentDreamToken != null && !mCurrentDreamIsTest
    157                     && !mCurrentDreamIsWaking;
    158         }
    159     }
    160 
    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 
    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 
    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 
    199     private void testDreamInternal(ComponentName dream, int userId) {
    200         synchronized (mLock) {
    201             startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
    202         }
    203     }
    204 
    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 
    215     private void stopDreamInternal(boolean immediate) {
    216         synchronized (mLock) {
    217             stopDreamLocked(immediate);
    218         }
    219     }
    220 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    324     private ComponentName getDozeComponent() {
    325         return getDozeComponent(ActivityManager.getCurrentUser());
    326     }
    327 
    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 
    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 
    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 
    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 
    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 
    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 
    425     private void writePulseGestureEnabled() {
    426         ComponentName name = getDozeComponent();
    427         boolean dozeEnabled = validateDream(name);
    428         LocalServices.getService(InputManagerInternal.class).setPulseGestureEnabled(dozeEnabled);
    429     }
    430 
    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 
    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 {
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    650         public void startDream(boolean doze) {
    651             startDreamInternal(doze);
    652         }
    653 
    654         @Override
    655         public void stopDream(boolean immediate) {
    656             stopDreamInternal(immediate);
    657         }
    658 
    659         @Override
    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