Notifier.java revision ad9ef191f50767d8d5b6f0fbd4b59bb1400dcd25
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 device is waking up from sleep and the
193     * display is about to be turned on.
194     */
195    public void onWakeUpStarted() {
196        if (DEBUG) {
197            Slog.d(TAG, "onWakeUpStarted");
198        }
199
200        synchronized (mLock) {
201            if (mActualPowerState != POWER_STATE_AWAKE) {
202                mActualPowerState = POWER_STATE_AWAKE;
203                mPendingWakeUpBroadcast = true;
204                if (!mScreenOnBlockerAcquired) {
205                    mScreenOnBlockerAcquired = true;
206                    mScreenOnBlocker.acquire();
207                }
208                updatePendingBroadcastLocked();
209            }
210        }
211    }
212
213    /**
214     * Called when the device has finished waking up from sleep
215     * and the display has been turned on.
216     */
217    public void onWakeUpFinished() {
218        if (DEBUG) {
219            Slog.d(TAG, "onWakeUpFinished");
220        }
221    }
222
223    /**
224     * Called when the device is going to sleep.
225     */
226    public void onGoToSleepStarted(int reason) {
227        if (DEBUG) {
228            Slog.d(TAG, "onGoToSleepStarted");
229        }
230
231        synchronized (mLock) {
232            mLastGoToSleepReason = reason;
233        }
234    }
235
236    /**
237     * Called when the device has finished going to sleep and the
238     * display has been turned off.
239     *
240     * This is a good time to make transitions that we don't want the user to see,
241     * such as bringing the key guard to focus.  There's no guarantee for this,
242     * however because the user could turn the device on again at any time.
243     * Some things may need to be protected by other mechanisms that defer screen on.
244     */
245    public void onGoToSleepFinished() {
246        if (DEBUG) {
247            Slog.d(TAG, "onGoToSleepFinished");
248        }
249
250        synchronized (mLock) {
251            if (mActualPowerState != POWER_STATE_ASLEEP) {
252                mActualPowerState = POWER_STATE_ASLEEP;
253                mPendingGoToSleepBroadcast = true;
254                if (mUserActivityPending) {
255                    mUserActivityPending = false;
256                    mHandler.removeMessages(MSG_USER_ACTIVITY);
257                }
258                updatePendingBroadcastLocked();
259            }
260        }
261    }
262
263    /**
264     * Called when there has been user activity.
265     */
266    public void onUserActivity(int event, int uid) {
267        if (DEBUG) {
268            Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
269        }
270
271        try {
272            mBatteryStats.noteUserActivity(uid, event);
273        } catch (RemoteException ex) {
274            // Ignore
275        }
276
277        synchronized (mLock) {
278            if (!mUserActivityPending) {
279                mUserActivityPending = true;
280                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
281                msg.setAsynchronous(true);
282                mHandler.sendMessage(msg);
283            }
284        }
285    }
286
287    /**
288     * Called when wireless charging has started so as to provide user feedback.
289     */
290    public void onWirelessChargingStarted() {
291        if (DEBUG) {
292            Slog.d(TAG, "onWirelessChargingStarted");
293        }
294
295        mSuspendBlocker.acquire();
296        Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
297        msg.setAsynchronous(true);
298        mHandler.sendMessage(msg);
299    }
300
301    private void updatePendingBroadcastLocked() {
302        if (!mBroadcastInProgress
303                && mActualPowerState != POWER_STATE_UNKNOWN
304                && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
305                        || mActualPowerState != mBroadcastedPowerState)) {
306            mBroadcastInProgress = true;
307            mSuspendBlocker.acquire();
308            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
309            msg.setAsynchronous(true);
310            mHandler.sendMessage(msg);
311        }
312    }
313
314    private void finishPendingBroadcastLocked() {
315        mBroadcastInProgress = false;
316        mSuspendBlocker.release();
317    }
318
319    private void sendUserActivity() {
320        synchronized (mLock) {
321            if (!mUserActivityPending) {
322                return;
323            }
324            mUserActivityPending = false;
325        }
326
327        mPolicy.userActivity();
328    }
329
330    private void sendNextBroadcast() {
331        final int powerState;
332        final int goToSleepReason;
333        synchronized (mLock) {
334            if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
335                // Broadcasted power state is unknown.  Send wake up.
336                mPendingWakeUpBroadcast = false;
337                mBroadcastedPowerState = POWER_STATE_AWAKE;
338            } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) {
339                // Broadcasted power state is awake.  Send asleep if needed.
340                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
341                        || mActualPowerState == POWER_STATE_ASLEEP) {
342                    mPendingGoToSleepBroadcast = false;
343                    mBroadcastedPowerState = POWER_STATE_ASLEEP;
344                } else {
345                    finishPendingBroadcastLocked();
346                    return;
347                }
348            } else {
349                // Broadcasted power state is asleep.  Send awake if needed.
350                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
351                        || mActualPowerState == POWER_STATE_AWAKE) {
352                    mPendingWakeUpBroadcast = false;
353                    mBroadcastedPowerState = POWER_STATE_AWAKE;
354                } else {
355                    finishPendingBroadcastLocked();
356                    return;
357                }
358            }
359
360            mBroadcastStartTime = SystemClock.uptimeMillis();
361            powerState = mBroadcastedPowerState;
362            goToSleepReason = mLastGoToSleepReason;
363        }
364
365        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
366
367        if (powerState == POWER_STATE_AWAKE) {
368            sendWakeUpBroadcast();
369        } else {
370            sendGoToSleepBroadcast(goToSleepReason);
371        }
372    }
373
374    private void sendWakeUpBroadcast() {
375        if (DEBUG) {
376            Slog.d(TAG, "Sending wake up broadcast.");
377        }
378
379        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
380
381        mPolicy.screenTurningOn(mScreenOnListener);
382
383        try {
384            ActivityManagerNative.getDefault().wakingUp();
385        } catch (RemoteException e) {
386            // ignore it
387        }
388
389        if (ActivityManagerNative.isSystemReady()) {
390            mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
391                    mWakeUpBroadcastDone, mHandler, 0, null, null);
392        } else {
393            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
394            sendNextBroadcast();
395        }
396    }
397
398    private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
399            new WindowManagerPolicy.ScreenOnListener() {
400        @Override
401        public void onScreenOn() {
402            synchronized (mLock) {
403                if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
404                    mScreenOnBlockerAcquired = false;
405                    mScreenOnBlocker.release();
406                }
407            }
408        }
409    };
410
411    private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
412        @Override
413        public void onReceive(Context context, Intent intent) {
414            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
415                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
416            sendNextBroadcast();
417        }
418    };
419
420    private void sendGoToSleepBroadcast(int reason) {
421        if (DEBUG) {
422            Slog.d(TAG, "Sending go to sleep broadcast.");
423        }
424
425        int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
426        switch (reason) {
427            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
428                why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
429                break;
430            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
431                why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
432                break;
433        }
434
435        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
436
437        mPolicy.screenTurnedOff(why);
438        try {
439            ActivityManagerNative.getDefault().goingToSleep();
440        } catch (RemoteException e) {
441            // ignore it.
442        }
443
444        if (ActivityManagerNative.isSystemReady()) {
445            mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
446                    mGoToSleepBroadcastDone, mHandler, 0, null, null);
447        } else {
448            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
449            sendNextBroadcast();
450        }
451    }
452
453    private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
454        @Override
455        public void onReceive(Context context, Intent intent) {
456            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
457                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
458            sendNextBroadcast();
459        }
460    };
461
462    private void playWirelessChargingStartedSound() {
463        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
464                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
465        if (soundPath != null) {
466            final Uri soundUri = Uri.parse("file://" + soundPath);
467            if (soundUri != null) {
468                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
469                if (sfx != null) {
470                    sfx.setStreamType(AudioManager.STREAM_SYSTEM);
471                    sfx.play();
472                }
473            }
474        }
475
476        mSuspendBlocker.release();
477    }
478
479    private final class NotifierHandler extends Handler {
480        public NotifierHandler(Looper looper) {
481            super(looper, null, true /*async*/);
482        }
483
484        @Override
485        public void handleMessage(Message msg) {
486            switch (msg.what) {
487                case MSG_USER_ACTIVITY:
488                    sendUserActivity();
489                    break;
490
491                case MSG_BROADCAST:
492                    sendNextBroadcast();
493                    break;
494
495                case MSG_WIRELESS_CHARGING_STARTED:
496                    playWirelessChargingStartedSound();
497                    break;
498            }
499        }
500    }
501}
502