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