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