OSDN Git Service

79a4deebc3da930fe54934209fed867ccb291a36
[android-x86/frameworks-base.git] / services / core / java / com / android / server / dreams / DreamManagerService.java
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.server.dreams;
18
19 import static android.Manifest.permission.BIND_DREAM_SERVICE;
20
21 import com.android.internal.hardware.AmbientDisplayConfiguration;
22 import com.android.internal.util.DumpUtils;
23 import com.android.server.FgThread;
24 import com.android.server.LocalServices;
25 import com.android.server.SystemService;
26
27 import android.Manifest;
28 import android.app.ActivityManager;
29 import android.content.BroadcastReceiver;
30 import android.content.ComponentName;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.pm.PackageManager;
35 import android.content.pm.PackageManager.NameNotFoundException;
36 import android.content.pm.ServiceInfo;
37 import android.database.ContentObserver;
38 import android.hardware.input.InputManagerInternal;
39 import android.os.Binder;
40 import android.os.Build;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.Looper;
44 import android.os.PowerManager;
45 import android.os.PowerManagerInternal;
46 import android.os.SystemClock;
47 import android.os.SystemProperties;
48 import android.os.UserHandle;
49 import android.provider.Settings;
50 import android.service.dreams.DreamManagerInternal;
51 import android.service.dreams.DreamService;
52 import android.service.dreams.IDreamManager;
53 import android.text.TextUtils;
54 import android.util.Slog;
55 import android.view.Display;
56
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.util.ArrayList;
60 import java.util.List;
61
62 import libcore.util.Objects;
63
64 /**
65  * Service api for managing dreams.
66  *
67  * @hide
68  */
69 public final class DreamManagerService extends SystemService {
70     private static final boolean DEBUG = false;
71     private static final String TAG = "DreamManagerService";
72
73     private final Object mLock = new Object();
74
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;
81
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;
91
92     private AmbientDisplayConfiguration mDozeConfig;
93
94     public DreamManagerService(Context context) {
95         super(context);
96         mContext = context;
97         mHandler = new DreamHandler(FgThread.get().getLooper());
98         mController = new DreamController(context, mHandler, mControllerListener);
99
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);
104     }
105
106     @Override
107     public void onStart() {
108         publishBinderService(DreamService.DREAM_SERVICE, new BinderService());
109         publishLocalService(DreamManagerInternal.class, new LocalService());
110     }
111
112     @Override
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);
117             }
118             mContext.registerReceiver(new BroadcastReceiver() {
119                 @Override
120                 public void onReceive(Context context, Intent intent) {
121                     writePulseGestureEnabled();
122                     synchronized (mLock) {
123                         stopDreamLocked(false /*immediate*/);
124                     }
125                 }
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();
131         }
132     }
133
134     private void dumpInternal(PrintWriter pw) {
135         pw.println("DREAM MANAGER (dumpsys dreams)");
136         pw.println();
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());
148         pw.println();
149
150         DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
151             @Override
152             public void dump(PrintWriter pw, String prefix) {
153                 mController.dump(pw);
154             }
155         }, pw, "", 200);
156     }
157
158     private boolean isDreamingInternal() {
159         synchronized (mLock) {
160             return mCurrentDreamToken != null && !mCurrentDreamIsTest
161                     && !mCurrentDreamIsWaking;
162         }
163     }
164
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);
173     }
174
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*/);
182     }
183
184     private void finishSelfInternal(IBinder token, boolean immediate) {
185         if (DEBUG) {
186             Slog.d(TAG, "Dream finished: " + token + ", immediate=" + immediate);
187         }
188
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);
199             }
200         }
201     }
202
203     private void testDreamInternal(ComponentName dream, int userId) {
204         synchronized (mLock) {
205             startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
206         }
207     }
208
209     private void startDreamInternal(boolean doze) {
210         final int userId = ActivityManager.getCurrentUser();
211         final ComponentName dream = chooseDreamForUser(doze, userId);
212         if (dream != null) {
213             synchronized (mLock) {
214                 startDreamLocked(dream, false /*isTest*/, doze, userId);
215             }
216         }
217     }
218
219     private void stopDreamInternal(boolean immediate) {
220         synchronized (mLock) {
221             stopDreamLocked(immediate);
222         }
223     }
224
225     private void startDozingInternal(IBinder token, int screenState,
226             int screenBrightness) {
227         if (DEBUG) {
228             Slog.d(TAG, "Dream requested to start dozing: " + token
229                     + ", screenState=" + screenState
230                     + ", screenBrightness=" + screenBrightness);
231         }
232
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();
242                 }
243             }
244         }
245     }
246
247     private void stopDozingInternal(IBinder token) {
248         if (DEBUG) {
249             Slog.d(TAG, "Dream requested to stop dozing: " + token);
250         }
251
252         synchronized (mLock) {
253             if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
254                 mCurrentDreamIsDozing = false;
255                 mDozeWakeLock.release();
256                 mPowerManagerInternal.setDozeOverrideFromDreamManager(
257                         Display.STATE_UNKNOWN, PowerManager.BRIGHTNESS_DEFAULT);
258             }
259         }
260     }
261
262     private ComponentName chooseDreamForUser(boolean doze, int userId) {
263         if (doze) {
264             ComponentName dozeComponent = getDozeComponent(userId);
265             return validateDream(dozeComponent) ? dozeComponent : null;
266         }
267         ComponentName[] dreams = getDreamComponentsForUser(userId);
268         return dreams != null && dreams.length != 0 ? dreams[0] : null;
269     }
270
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");
276             return false;
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.");
282             return false;
283         }
284         return true;
285     }
286
287     private ComponentName[] getDreamComponentsForUser(int userId) {
288         String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
289                 Settings.Secure.SCREENSAVER_COMPONENTS,
290                 userId);
291         ComponentName[] components = componentsFromString(names);
292
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);
299                 }
300             }
301         }
302
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);
309             }
310         }
311         return validComponents.toArray(new ComponentName[validComponents.size()]);
312     }
313
314     private void setDreamComponentsForUser(int userId, ComponentName[] componentNames) {
315         Settings.Secure.putStringForUser(mContext.getContentResolver(),
316                 Settings.Secure.SCREENSAVER_COMPONENTS,
317                 componentsToString(componentNames),
318                 userId);
319     }
320
321     private ComponentName getDefaultDreamComponentForUser(int userId) {
322         String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
323                 Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
324                 userId);
325         return name == null ? null : ComponentName.unflattenFromString(name);
326     }
327
328     private ComponentName getDozeComponent() {
329         return getDozeComponent(ActivityManager.getCurrentUser());
330     }
331
332     private ComponentName getDozeComponent(int userId) {
333         if (mDozeConfig.enabled(userId)) {
334             return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent());
335         } else {
336             return null;
337         }
338
339     }
340
341     private ServiceInfo getServiceInfo(ComponentName name) {
342         try {
343             return name != null ? mContext.getPackageManager().getServiceInfo(name,
344                     PackageManager.MATCH_DEBUG_TRIAGED_MISSING) : null;
345         } catch (NameNotFoundException e) {
346             return null;
347         }
348     }
349
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.");
357             return;
358         }
359
360         stopDreamLocked(true /*immediate*/);
361
362         Slog.i(TAG, "Entering dreamland.");
363
364         final Binder newToken = new Binder();
365         mCurrentDreamToken = newToken;
366         mCurrentDreamName = name;
367         mCurrentDreamIsTest = isTest;
368         mCurrentDreamCanDoze = canDoze;
369         mCurrentDreamUserId = userId;
370
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)));
375     }
376
377     private void stopDreamLocked(final boolean immediate) {
378         if (mCurrentDreamToken != null) {
379             if (immediate) {
380                 Slog.i(TAG, "Leaving dreamland.");
381                 cleanupDreamLocked();
382             } else if (mCurrentDreamIsWaking) {
383                 return; // already waking
384             } else {
385                 Slog.i(TAG, "Gently waking up from dream.");
386                 mCurrentDreamIsWaking = true;
387             }
388
389             mHandler.post(new Runnable() {
390                 @Override
391                 public void run() {
392                     Slog.i(TAG, "Performing gentle wake from dream.");
393                     mController.stopDream(immediate);
394                 }
395             });
396         }
397     }
398
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();
409         }
410         mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
411         mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
412     }
413
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);
419         }
420     }
421
422     private void writePulseGestureEnabled() {
423         ComponentName name = getDozeComponent();
424         boolean dozeEnabled = validateDream(name);
425         LocalServices.getService(InputManagerInternal.class).setPulseGestureEnabled(dozeEnabled);
426     }
427
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) {
433                     names.append(',');
434                 }
435                 names.append(componentName.flattenToString());
436             }
437         }
438         return names.toString();
439     }
440
441     private static ComponentName[] componentsFromString(String names) {
442         if (names == null) {
443             return null;
444         }
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]);
449         }
450         return componentNames;
451     }
452
453     private final DreamController.Listener mControllerListener = new DreamController.Listener() {
454         @Override
455         public void onDreamStopped(Binder token) {
456             synchronized (mLock) {
457                 if (mCurrentDreamToken == token) {
458                     cleanupDreamLocked();
459                 }
460             }
461         }
462     };
463
464     private final ContentObserver mDozeEnabledObserver = new ContentObserver(null) {
465         @Override
466         public void onChange(boolean selfChange) {
467             writePulseGestureEnabled();
468         }
469     };
470
471     /**
472      * Handler for asynchronous operations performed by the dream manager.
473      * Ensures operations to {@link DreamController} are single-threaded.
474      */
475     private final class DreamHandler extends Handler {
476         public DreamHandler(Looper looper) {
477             super(looper, null, true /*async*/);
478         }
479     }
480
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());
489                 return;
490             }
491
492             final long ident = Binder.clearCallingIdentity();
493             try {
494                 dumpInternal(pw);
495             } finally {
496                 Binder.restoreCallingIdentity(ident);
497             }
498         }
499
500         @Override // Binder call
501         public ComponentName[] getDreamComponents() {
502             checkPermission(android.Manifest.permission.READ_DREAM_STATE);
503
504             final int userId = UserHandle.getCallingUserId();
505             final long ident = Binder.clearCallingIdentity();
506             try {
507                 return getDreamComponentsForUser(userId);
508             } finally {
509                 Binder.restoreCallingIdentity(ident);
510             }
511         }
512
513         @Override // Binder call
514         public void setDreamComponents(ComponentName[] componentNames) {
515             checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
516
517             final int userId = UserHandle.getCallingUserId();
518             final long ident = Binder.clearCallingIdentity();
519             try {
520                 setDreamComponentsForUser(userId, componentNames);
521             } finally {
522                 Binder.restoreCallingIdentity(ident);
523             }
524         }
525
526         @Override // Binder call
527         public ComponentName getDefaultDreamComponent() {
528             checkPermission(android.Manifest.permission.READ_DREAM_STATE);
529
530             final int userId = UserHandle.getCallingUserId();
531             final long ident = Binder.clearCallingIdentity();
532             try {
533                 return getDefaultDreamComponentForUser(userId);
534             } finally {
535                 Binder.restoreCallingIdentity(ident);
536             }
537         }
538
539         @Override // Binder call
540         public boolean isDreaming() {
541             checkPermission(android.Manifest.permission.READ_DREAM_STATE);
542
543             final long ident = Binder.clearCallingIdentity();
544             try {
545                 return isDreamingInternal();
546             } finally {
547                 Binder.restoreCallingIdentity(ident);
548             }
549         }
550
551         @Override // Binder call
552         public void dream() {
553             checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
554
555             final long ident = Binder.clearCallingIdentity();
556             try {
557                 requestDreamInternal();
558             } finally {
559                 Binder.restoreCallingIdentity(ident);
560             }
561         }
562
563         @Override // Binder call
564         public void testDream(ComponentName dream) {
565             if (dream == null) {
566                 throw new IllegalArgumentException("dream must not be null");
567             }
568             checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
569
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);
577                 return;
578             }
579             final long ident = Binder.clearCallingIdentity();
580             try {
581                 testDreamInternal(dream, callingUserId);
582             } finally {
583                 Binder.restoreCallingIdentity(ident);
584             }
585         }
586
587         @Override // Binder call
588         public void awaken() {
589             checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
590
591             final long ident = Binder.clearCallingIdentity();
592             try {
593                 requestAwakenInternal();
594             } finally {
595                 Binder.restoreCallingIdentity(ident);
596             }
597         }
598
599         @Override // Binder call
600         public void finishSelf(IBinder token, boolean immediate) {
601             // Requires no permission, called by Dream from an arbitrary process.
602             if (token == null) {
603                 throw new IllegalArgumentException("token must not be null");
604             }
605
606             final long ident = Binder.clearCallingIdentity();
607             try {
608                 finishSelfInternal(token, immediate);
609             } finally {
610                 Binder.restoreCallingIdentity(ident);
611             }
612         }
613
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.
617             if (token == null) {
618                 throw new IllegalArgumentException("token must not be null");
619             }
620
621             final long ident = Binder.clearCallingIdentity();
622             try {
623                 startDozingInternal(token, screenState, screenBrightness);
624             } finally {
625                 Binder.restoreCallingIdentity(ident);
626             }
627         }
628
629         @Override // Binder call
630         public void stopDozing(IBinder token) {
631             // Requires no permission, called by Dream from an arbitrary process.
632             if (token == null) {
633                 throw new IllegalArgumentException("token must not be null");
634             }
635
636             final long ident = Binder.clearCallingIdentity();
637             try {
638                 stopDozingInternal(token);
639             } finally {
640                 Binder.restoreCallingIdentity(ident);
641             }
642         }
643     }
644
645     private final class LocalService extends DreamManagerInternal {
646         @Override
647         public void startDream(boolean doze) {
648             startDreamInternal(doze);
649         }
650
651         @Override
652         public void stopDream(boolean immediate) {
653             stopDreamInternal(immediate);
654         }
655
656         @Override
657         public boolean isDreaming() {
658             return isDreamingInternal();
659         }
660     }
661
662     private final Runnable mSystemPropertiesChanged = new Runnable() {
663         @Override
664         public void run() {
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");
672                 }
673             }
674         }
675     };
676 }