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