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