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