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