Notifier.java revision 9630704ed3b265f008a8f64ec60a33cf9dcd3345
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 com.android.internal.app.IBatteryStats;
20import com.android.server.EventLogTags;
21
22import android.app.ActivityManagerNative;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.os.BatteryStats;
27import android.os.Handler;
28import android.os.Looper;
29import android.os.Message;
30import android.os.PowerManager;
31import android.os.Process;
32import android.os.RemoteException;
33import android.os.SystemClock;
34import android.os.WorkSource;
35import android.util.EventLog;
36import android.util.Slog;
37import android.view.WindowManagerPolicy;
38import android.view.WindowManagerPolicy.ScreenOnListener;
39
40/**
41 * Sends broadcasts about important power state changes.
42 *
43 * This methods of this class may be called by the power manager service while
44 * its lock is being held.  Internally it takes care of sending broadcasts to
45 * notify other components of the system or applications asynchronously.
46 *
47 * The notifier is designed to collapse unnecessary broadcasts when it is not
48 * possible for the system to have observed an intermediate state.
49 *
50 * For example, if the device wakes up, goes to sleep and wakes up again immediately
51 * before the go to sleep broadcast has been sent, then no broadcast will be
52 * sent about the system going to sleep and waking up.
53 */
54final class Notifier {
55    private static final String TAG = "PowerManagerNotifier";
56
57    private static final boolean DEBUG = false;
58
59    private static final int POWER_STATE_UNKNOWN = 0;
60    private static final int POWER_STATE_AWAKE = 1;
61    private static final int POWER_STATE_ASLEEP = 2;
62
63    private static final int MSG_USER_ACTIVITY = 1;
64    private static final int MSG_BROADCAST = 2;
65
66    private final Object mLock = new Object();
67
68    private final Context mContext;
69    private final IBatteryStats mBatteryStats;
70    private final SuspendBlocker mSuspendBlocker;
71    private final WindowManagerPolicy mPolicy;
72    private final ScreenOnListener mScreenOnListener;
73
74    private final NotifierHandler mHandler;
75    private final Intent mScreenOnIntent;
76    private final Intent mScreenOffIntent;
77
78    // The current power state.
79    private int mActualPowerState;
80    private int mLastGoToSleepReason;
81
82    // The currently broadcasted power state.  This reflects what other parts of the
83    // system have observed.
84    private int mBroadcastedPowerState;
85    private boolean mBroadcastInProgress;
86    private long mBroadcastStartTime;
87
88    // True if a user activity message should be sent.
89    private boolean mUserActivityPending;
90
91    public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
92            SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
93            ScreenOnListener screenOnListener) {
94        mContext = context;
95        mBatteryStats = batteryStats;
96        mSuspendBlocker = suspendBlocker;
97        mPolicy = policy;
98        mScreenOnListener = screenOnListener;
99
100        mHandler = new NotifierHandler(looper);
101        mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
102        mScreenOnIntent.addFlags(
103                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
104        mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
105        mScreenOffIntent.addFlags(
106                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
107    }
108
109    /**
110     * Called when a wake lock is acquired.
111     */
112    public void onWakeLockAcquired(int flags, String tag, int ownerUid, int ownerPid,
113            WorkSource workSource) {
114        if (DEBUG) {
115            Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
116                    + "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
117                    + ", workSource=" + workSource);
118        }
119
120        if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
121            try {
122                final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
123                if (workSource != null) {
124                    mBatteryStats.noteStartWakelockFromSource(
125                            workSource, ownerPid, tag, monitorType);
126                } else {
127                    mBatteryStats.noteStartWakelock(
128                            ownerUid, ownerPid, tag, monitorType);
129                }
130            } catch (RemoteException ex) {
131                // Ignore
132            }
133        }
134    }
135
136    /**
137     * Called when a wake lock is released.
138     */
139    public void onWakeLockReleased(int flags, String tag, int ownerUid, int ownerPid,
140            WorkSource workSource) {
141        if (DEBUG) {
142            Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
143                    + "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
144                    + ", workSource=" + workSource);
145        }
146
147        if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
148            try {
149                final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
150                if (workSource != null) {
151                    mBatteryStats.noteStopWakelockFromSource(
152                            workSource, ownerPid, tag, monitorType);
153                } else {
154                    mBatteryStats.noteStopWakelock(
155                            ownerUid, ownerPid, tag, monitorType);
156                }
157            } catch (RemoteException ex) {
158                // Ignore
159            }
160        }
161    }
162
163    private static boolean isWakeLockAlreadyReportedToBatteryStats(String tag, int uid) {
164        // The window manager already takes care of reporting battery stats associated
165        // with the use of the KEEP_SCREEN_ON_FLAG.
166        // TODO: Use a WorkSource to handle this situation instead of hardcoding it here.
167        return uid == Process.SYSTEM_UID
168                && tag.equals(PowerManager.KEEP_SCREEN_ON_FLAG_TAG);
169    }
170
171    private static int getBatteryStatsWakeLockMonitorType(int flags) {
172        switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
173            case PowerManager.PARTIAL_WAKE_LOCK:
174            case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
175                return BatteryStats.WAKE_TYPE_PARTIAL;
176            default:
177                return BatteryStats.WAKE_TYPE_FULL;
178        }
179    }
180
181    /**
182     * Called when the screen is turned on.
183     */
184    public void onScreenOn() {
185        if (DEBUG) {
186            Slog.d(TAG, "onScreenOn");
187        }
188
189        try {
190            mBatteryStats.noteScreenOn();
191        } catch (RemoteException ex) {
192            // Ignore
193        }
194    }
195
196    /**
197     * Called when the screen is turned off.
198     */
199    public void onScreenOff() {
200        if (DEBUG) {
201            Slog.d(TAG, "onScreenOff");
202        }
203
204        try {
205            mBatteryStats.noteScreenOff();
206        } catch (RemoteException ex) {
207            // Ignore
208        }
209    }
210
211    /**
212     * Called when the screen changes brightness.
213     */
214    public void onScreenBrightness(int brightness) {
215        if (DEBUG) {
216            Slog.d(TAG, "onScreenBrightness: brightness=" + brightness);
217        }
218
219        try {
220            mBatteryStats.noteScreenBrightness(brightness);
221        } catch (RemoteException ex) {
222            // Ignore
223        }
224    }
225
226    /**
227     * Called when the device is waking up from sleep and the
228     * display is about to be turned on.
229     */
230    public void onWakeUpStarted() {
231        if (DEBUG) {
232            Slog.d(TAG, "onWakeUpStarted");
233        }
234
235        synchronized (mLock) {
236            if (mActualPowerState != POWER_STATE_AWAKE) {
237                mActualPowerState = POWER_STATE_AWAKE;
238                updatePendingBroadcastLocked();
239            }
240        }
241    }
242
243    /**
244     * Called when the device has finished waking up from sleep
245     * and the display has been turned on.
246     */
247    public void onWakeUpFinished() {
248        if (DEBUG) {
249            Slog.d(TAG, "onWakeUpFinished");
250        }
251    }
252
253    /**
254     * Called when the device is going to sleep.
255     */
256    public void onGoToSleepStarted(int reason) {
257        if (DEBUG) {
258            Slog.d(TAG, "onGoToSleepStarted");
259        }
260
261        synchronized (mLock) {
262            mLastGoToSleepReason = reason;
263        }
264    }
265
266    /**
267     * Called when the device has finished going to sleep and the
268     * display has been turned off.
269     *
270     * This is a good time to make transitions that we don't want the user to see,
271     * such as bringing the key guard to focus.  There's no guarantee for this,
272     * however because the user could turn the device on again at any time.
273     * Some things may need to be protected by other mechanisms that defer screen on.
274     */
275    public void onGoToSleepFinished() {
276        if (DEBUG) {
277            Slog.d(TAG, "onGoToSleepFinished");
278        }
279
280        synchronized (mLock) {
281            if (mActualPowerState != POWER_STATE_ASLEEP) {
282                mActualPowerState = POWER_STATE_ASLEEP;
283                if (mUserActivityPending) {
284                    mUserActivityPending = false;
285                    mHandler.removeMessages(MSG_USER_ACTIVITY);
286                }
287                updatePendingBroadcastLocked();
288            }
289        }
290    }
291
292    /**
293     * Called when there has been user activity.
294     */
295    public void onUserActivity(int event, int uid) {
296        if (DEBUG) {
297            Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
298        }
299
300        try {
301            mBatteryStats.noteUserActivity(uid, event);
302        } catch (RemoteException ex) {
303            // Ignore
304        }
305
306        synchronized (mLock) {
307            if (!mUserActivityPending) {
308                mUserActivityPending = true;
309                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
310                msg.setAsynchronous(true);
311                mHandler.sendMessage(msg);
312            }
313        }
314    }
315
316    private void updatePendingBroadcastLocked() {
317        if (!mBroadcastInProgress
318                && mActualPowerState != POWER_STATE_UNKNOWN
319                && mActualPowerState != mBroadcastedPowerState) {
320            mBroadcastInProgress = true;
321            mSuspendBlocker.acquire();
322            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
323            msg.setAsynchronous(true);
324            mHandler.sendMessage(msg);
325        }
326    }
327
328    private void sendUserActivity() {
329        synchronized (mLock) {
330            if (!mUserActivityPending) {
331                return;
332            }
333            mUserActivityPending = false;
334        }
335
336        mPolicy.userActivity();
337    }
338
339    private void sendNextBroadcast() {
340        final int powerState;
341        final int goToSleepReason;
342        synchronized (mLock) {
343            if (mActualPowerState == POWER_STATE_UNKNOWN
344                    || mActualPowerState == mBroadcastedPowerState) {
345                mBroadcastInProgress = false;
346                mSuspendBlocker.release();
347                return;
348            }
349
350            powerState = mActualPowerState;
351            goToSleepReason = mLastGoToSleepReason;
352
353            mBroadcastedPowerState = powerState;
354            mBroadcastStartTime = SystemClock.uptimeMillis();
355        }
356
357        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
358
359        if (powerState == POWER_STATE_AWAKE) {
360            sendWakeUpBroadcast();
361        } else {
362            sendGoToSleepBroadcast(goToSleepReason);
363        }
364    }
365
366    private void sendWakeUpBroadcast() {
367        if (DEBUG) {
368            Slog.d(TAG, "Sending wake up broadcast.");
369        }
370
371        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
372
373        mPolicy.screenTurningOn(mScreenOnListener);
374        try {
375            ActivityManagerNative.getDefault().wakingUp();
376        } catch (RemoteException e) {
377            // ignore it
378        }
379
380        if (ActivityManagerNative.isSystemReady()) {
381            mContext.sendOrderedBroadcast(mScreenOnIntent, null,
382                    mWakeUpBroadcastDone, mHandler, 0, null, null);
383        } else {
384            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
385            sendNextBroadcast();
386        }
387    }
388
389    private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
390        @Override
391        public void onReceive(Context context, Intent intent) {
392            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
393                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
394            sendNextBroadcast();
395        }
396    };
397
398    private void sendGoToSleepBroadcast(int reason) {
399        if (DEBUG) {
400            Slog.d(TAG, "Sending go to sleep broadcast.");
401        }
402
403        int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
404        switch (reason) {
405            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
406                why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
407                break;
408            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
409                why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
410                break;
411        }
412
413        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
414
415        mPolicy.screenTurnedOff(why);
416        try {
417            ActivityManagerNative.getDefault().goingToSleep();
418        } catch (RemoteException e) {
419            // ignore it.
420        }
421
422        if (ActivityManagerNative.isSystemReady()) {
423            mContext.sendOrderedBroadcast(mScreenOffIntent, null,
424                    mGoToSleepBroadcastDone, mHandler, 0, null, null);
425        } else {
426            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
427            sendNextBroadcast();
428        }
429    }
430
431    private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
432        @Override
433        public void onReceive(Context context, Intent intent) {
434            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
435                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
436            sendNextBroadcast();
437        }
438    };
439
440    private final class NotifierHandler extends Handler {
441        public NotifierHandler(Looper looper) {
442            super(looper);
443        }
444
445        @Override
446        public void handleMessage(Message msg) {
447            switch (msg.what) {
448                case MSG_USER_ACTIVITY:
449                    sendUserActivity();
450                    break;
451
452                case MSG_BROADCAST:
453                    sendNextBroadcast();
454                    break;
455            }
456        }
457    }
458}
459