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