Notifier.java revision c522d1646ac353aec302252fa53976c1fa46ad3d
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
17package com.android.server.power;
18
19import android.app.ActivityManagerInternal;
20import android.app.AppOpsManager;
21
22import com.android.internal.app.IAppOpsService;
23import com.android.internal.app.IBatteryStats;
24import com.android.server.EventLogTags;
25import com.android.server.LocalServices;
26
27import android.app.ActivityManagerNative;
28import android.content.BroadcastReceiver;
29import android.content.Context;
30import android.content.Intent;
31import android.hardware.input.InputManagerInternal;
32import android.media.AudioManager;
33import android.media.Ringtone;
34import android.media.RingtoneManager;
35import android.net.Uri;
36import android.os.BatteryStats;
37import android.os.Handler;
38import android.os.Looper;
39import android.os.Message;
40import android.os.PowerManager;
41import android.os.Process;
42import android.os.RemoteException;
43import android.os.SystemClock;
44import android.os.UserHandle;
45import android.os.WorkSource;
46import android.provider.Settings;
47import android.util.EventLog;
48import android.util.Slog;
49import android.view.WindowManagerPolicy;
50
51/**
52 * Sends broadcasts about important power state changes.
53 * <p>
54 * This methods of this class may be called by the power manager service while
55 * its lock is being held.  Internally it takes care of sending broadcasts to
56 * notify other components of the system or applications asynchronously.
57 * </p><p>
58 * The notifier is designed to collapse unnecessary broadcasts when it is not
59 * possible for the system to have observed an intermediate state.
60 * </p><p>
61 * For example, if the device wakes up, goes to sleep, wakes up again and goes to
62 * sleep again before the wake up notification is sent, then the system will
63 * be told about only one wake up and sleep.  However, we always notify the
64 * fact that at least one transition occurred.  It is especially important to
65 * tell the system when we go to sleep so that it can lock the keyguard if needed.
66 * </p>
67 */
68final class Notifier {
69    private static final String TAG = "PowerManagerNotifier";
70
71    private static final boolean DEBUG = false;
72
73    private static final int POWER_STATE_UNKNOWN = 0;
74    private static final int POWER_STATE_AWAKE = 1;
75    private static final int POWER_STATE_ASLEEP = 2;
76
77    private static final int MSG_USER_ACTIVITY = 1;
78    private static final int MSG_BROADCAST = 2;
79    private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
80
81    private final Object mLock = new Object();
82
83    private final Context mContext;
84    private final IBatteryStats mBatteryStats;
85    private final IAppOpsService mAppOps;
86    private final SuspendBlocker mSuspendBlocker;
87    private final ScreenOnBlocker mScreenOnBlocker;
88    private final WindowManagerPolicy mPolicy;
89    private final ActivityManagerInternal mActivityManagerInternal;
90    private final InputManagerInternal mInputManagerInternal;
91
92    private final NotifierHandler mHandler;
93    private final Intent mScreenOnIntent;
94    private final Intent mScreenOffIntent;
95
96    // The current power state.
97    private int mActualPowerState;
98    private int mLastGoToSleepReason;
99
100    // True if there is a pending transition that needs to be reported.
101    private boolean mPendingWakeUpBroadcast;
102    private boolean mPendingGoToSleepBroadcast;
103
104    // The currently broadcasted power state.  This reflects what other parts of the
105    // system have observed.
106    private int mBroadcastedPowerState;
107    private boolean mBroadcastInProgress;
108    private long mBroadcastStartTime;
109
110    // True if a user activity message should be sent.
111    private boolean mUserActivityPending;
112
113    // True if the screen on blocker has been acquired.
114    private boolean mScreenOnBlockerAcquired;
115
116    public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
117            IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
118            WindowManagerPolicy policy) {
119        mContext = context;
120        mBatteryStats = batteryStats;
121        mAppOps = appOps;
122        mSuspendBlocker = suspendBlocker;
123        mScreenOnBlocker = screenOnBlocker;
124        mPolicy = policy;
125        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
126        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
127
128        mHandler = new NotifierHandler(looper);
129        mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
130        mScreenOnIntent.addFlags(
131                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
132        mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
133        mScreenOffIntent.addFlags(
134                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
135
136        // Initialize interactive state for battery stats.
137        try {
138            mBatteryStats.noteInteractive(true);
139        } catch (RemoteException ex) { }
140    }
141
142    /**
143     * Called when a wake lock is acquired.
144     */
145    public void onWakeLockAcquired(int flags, String tag, String packageName,
146            int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
147        if (DEBUG) {
148            Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
149                    + "\", packageName=" + packageName
150                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
151                    + ", workSource=" + workSource);
152        }
153
154        try {
155            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
156            boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
157                    && ownerUid == Process.SYSTEM_UID;
158            if (workSource != null) {
159                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag,
160                        monitorType, unimportantForLogging);
161            } else {
162                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
163                        monitorType, unimportantForLogging);
164                // XXX need to deal with disabled operations.
165                mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
166                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
167            }
168        } catch (RemoteException ex) {
169            // Ignore
170        }
171    }
172
173    /**
174     * Called when a wake lock is changing.
175     */
176    public void onWakeLockChanging(int flags, String tag, String packageName,
177            int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
178            int newFlags, String newTag, String newPackageName, int newOwnerUid,
179            int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) {
180
181        if (workSource != null && newWorkSource != null) {
182            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
183            final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
184            boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
185                    && newOwnerUid == Process.SYSTEM_UID;
186            if (DEBUG) {
187                Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag
188                        + "\", packageName=" + newPackageName
189                        + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid
190                        + ", workSource=" + newWorkSource);
191            }
192            try {
193                mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
194                        monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
195                        newMonitorType, unimportantForLogging);
196            } catch (RemoteException ex) {
197                // Ignore
198            }
199        } else {
200            onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
201            onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
202                    newWorkSource, newHistoryTag);
203        }
204    }
205
206    /**
207     * Called when a wake lock is released.
208     */
209    public void onWakeLockReleased(int flags, String tag, String packageName,
210            int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
211        if (DEBUG) {
212            Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
213                    + "\", packageName=" + packageName
214                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
215                    + ", workSource=" + workSource);
216        }
217
218        try {
219            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
220            if (workSource != null) {
221                mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag,
222                        monitorType);
223            } else {
224                mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType);
225                mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
226                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
227            }
228        } catch (RemoteException ex) {
229            // Ignore
230        }
231    }
232
233    private static int getBatteryStatsWakeLockMonitorType(int flags) {
234        switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
235            case PowerManager.PARTIAL_WAKE_LOCK:
236            case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
237                return BatteryStats.WAKE_TYPE_PARTIAL;
238            default:
239                return BatteryStats.WAKE_TYPE_FULL;
240        }
241    }
242
243    /**
244     * Notifies that the device is changing interactive state.
245     */
246    public void onInteractiveStateChangeStarted(boolean interactive, final int reason) {
247        if (DEBUG) {
248            Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
249                    + ", reason=" + reason);
250        }
251
252        synchronized (mLock) {
253            if (interactive) {
254                // Waking up...
255                if (mActualPowerState != POWER_STATE_AWAKE) {
256                    mActualPowerState = POWER_STATE_AWAKE;
257                    mPendingWakeUpBroadcast = true;
258                    if (!mScreenOnBlockerAcquired) {
259                        mScreenOnBlockerAcquired = true;
260                        mScreenOnBlocker.acquire();
261                    }
262                    mHandler.post(new Runnable() {
263                        @Override
264                        public void run() {
265                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
266                            mPolicy.wakingUp(mScreenOnListener);
267                            mActivityManagerInternal.wakingUp();
268                        }
269                    });
270                    updatePendingBroadcastLocked();
271                }
272            } else {
273                // Going to sleep...
274                mLastGoToSleepReason = reason;
275            }
276        }
277
278        mInputManagerInternal.setInteractive(interactive);
279
280        if (interactive) {
281            try {
282                mBatteryStats.noteInteractive(true);
283            } catch (RemoteException ex) { }
284        }
285    }
286
287    /**
288     * Notifies that the device has finished changing interactive state.
289     */
290    public void onInteractiveStateChangeFinished(boolean interactive) {
291        if (DEBUG) {
292            Slog.d(TAG, "onInteractiveChangeFinished");
293        }
294
295        synchronized (mLock) {
296            if (!interactive) {
297                // Finished going to sleep...
298                // This is a good time to make transitions that we don't want the user to see,
299                // such as bringing the key guard to focus.  There's no guarantee for this,
300                // however because the user could turn the device on again at any time.
301                // Some things may need to be protected by other mechanisms that defer screen on.
302                if (mActualPowerState != POWER_STATE_ASLEEP) {
303                    mActualPowerState = POWER_STATE_ASLEEP;
304                    mPendingGoToSleepBroadcast = true;
305                    if (mUserActivityPending) {
306                        mUserActivityPending = false;
307                        mHandler.removeMessages(MSG_USER_ACTIVITY);
308                    }
309                    mHandler.post(new Runnable() {
310                        @Override
311                        public void run() {
312                            int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
313                            switch (mLastGoToSleepReason) {
314                                case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
315                                    why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
316                                    break;
317                                case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
318                                    why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
319                                    break;
320                            }
321                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
322                            mPolicy.goingToSleep(why);
323                            mActivityManagerInternal.goingToSleep();
324                        }
325                    });
326                    updatePendingBroadcastLocked();
327                }
328            }
329        }
330
331        if (!interactive) {
332            try {
333                mBatteryStats.noteInteractive(false);
334            } catch (RemoteException ex) { }
335        }
336    }
337
338    /**
339     * Called when there has been user activity.
340     */
341    public void onUserActivity(int event, int uid) {
342        if (DEBUG) {
343            Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
344        }
345
346        try {
347            mBatteryStats.noteUserActivity(uid, event);
348        } catch (RemoteException ex) {
349            // Ignore
350        }
351
352        synchronized (mLock) {
353            if (!mUserActivityPending) {
354                mUserActivityPending = true;
355                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
356                msg.setAsynchronous(true);
357                mHandler.sendMessage(msg);
358            }
359        }
360    }
361
362    /**
363     * Called when wireless charging has started so as to provide user feedback.
364     */
365    public void onWirelessChargingStarted() {
366        if (DEBUG) {
367            Slog.d(TAG, "onWirelessChargingStarted");
368        }
369
370        mSuspendBlocker.acquire();
371        Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
372        msg.setAsynchronous(true);
373        mHandler.sendMessage(msg);
374    }
375
376    private void updatePendingBroadcastLocked() {
377        if (!mBroadcastInProgress
378                && mActualPowerState != POWER_STATE_UNKNOWN
379                && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
380                        || mActualPowerState != mBroadcastedPowerState)) {
381            mBroadcastInProgress = true;
382            mSuspendBlocker.acquire();
383            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
384            msg.setAsynchronous(true);
385            mHandler.sendMessage(msg);
386        }
387    }
388
389    private void finishPendingBroadcastLocked() {
390        mBroadcastInProgress = false;
391        mSuspendBlocker.release();
392    }
393
394    private void sendUserActivity() {
395        synchronized (mLock) {
396            if (!mUserActivityPending) {
397                return;
398            }
399            mUserActivityPending = false;
400        }
401
402        mPolicy.userActivity();
403    }
404
405    private void sendNextBroadcast() {
406        final int powerState;
407        final int goToSleepReason;
408        synchronized (mLock) {
409            if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
410                // Broadcasted power state is unknown.  Send wake up.
411                mPendingWakeUpBroadcast = false;
412                mBroadcastedPowerState = POWER_STATE_AWAKE;
413            } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) {
414                // Broadcasted power state is awake.  Send asleep if needed.
415                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
416                        || mActualPowerState == POWER_STATE_ASLEEP) {
417                    mPendingGoToSleepBroadcast = false;
418                    mBroadcastedPowerState = POWER_STATE_ASLEEP;
419                } else {
420                    finishPendingBroadcastLocked();
421                    return;
422                }
423            } else {
424                // Broadcasted power state is asleep.  Send awake if needed.
425                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
426                        || mActualPowerState == POWER_STATE_AWAKE) {
427                    mPendingWakeUpBroadcast = false;
428                    mBroadcastedPowerState = POWER_STATE_AWAKE;
429                } else {
430                    finishPendingBroadcastLocked();
431                    return;
432                }
433            }
434
435            mBroadcastStartTime = SystemClock.uptimeMillis();
436            powerState = mBroadcastedPowerState;
437        }
438
439        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
440
441        if (powerState == POWER_STATE_AWAKE) {
442            sendWakeUpBroadcast();
443        } else {
444            sendGoToSleepBroadcast();
445        }
446    }
447
448    private void sendWakeUpBroadcast() {
449        if (DEBUG) {
450            Slog.d(TAG, "Sending wake up broadcast.");
451        }
452
453        if (ActivityManagerNative.isSystemReady()) {
454            mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
455                    mWakeUpBroadcastDone, mHandler, 0, null, null);
456        } else {
457            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
458            sendNextBroadcast();
459        }
460    }
461
462    private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
463            new WindowManagerPolicy.ScreenOnListener() {
464        @Override
465        public void onScreenOn() {
466            synchronized (mLock) {
467                if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
468                    mScreenOnBlockerAcquired = false;
469                    mScreenOnBlocker.release();
470                }
471            }
472        }
473    };
474
475    private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
476        @Override
477        public void onReceive(Context context, Intent intent) {
478            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
479                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
480            sendNextBroadcast();
481        }
482    };
483
484    private void sendGoToSleepBroadcast() {
485        if (DEBUG) {
486            Slog.d(TAG, "Sending go to sleep broadcast.");
487        }
488
489        if (ActivityManagerNative.isSystemReady()) {
490            mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
491                    mGoToSleepBroadcastDone, mHandler, 0, null, null);
492        } else {
493            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
494            sendNextBroadcast();
495        }
496    }
497
498    private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
499        @Override
500        public void onReceive(Context context, Intent intent) {
501            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
502                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
503            sendNextBroadcast();
504        }
505    };
506
507    private void playWirelessChargingStartedSound() {
508        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
509                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
510        if (soundPath != null) {
511            final Uri soundUri = Uri.parse("file://" + soundPath);
512            if (soundUri != null) {
513                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
514                if (sfx != null) {
515                    sfx.setStreamType(AudioManager.STREAM_SYSTEM);
516                    sfx.play();
517                }
518            }
519        }
520
521        mSuspendBlocker.release();
522    }
523
524    private final class NotifierHandler extends Handler {
525        public NotifierHandler(Looper looper) {
526            super(looper, null, true /*async*/);
527        }
528
529        @Override
530        public void handleMessage(Message msg) {
531            switch (msg.what) {
532                case MSG_USER_ACTIVITY:
533                    sendUserActivity();
534                    break;
535
536                case MSG_BROADCAST:
537                    sendNextBroadcast();
538                    break;
539
540                case MSG_WIRELESS_CHARGING_STARTED:
541                    playWirelessChargingStartedSound();
542                    break;
543            }
544        }
545    }
546}
547