Notifier.java revision e95c3cd89591ba586aa8a0f7a17660c6fb8770bc
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 ScreenOnBlocker mScreenOnBlocker;
88    private final WindowManagerPolicy mPolicy;
89    private final ActivityManagerInternal mActivityManagerInternal;
90    private final InputManagerInternal mInputManagerInternal;
91
92    private final NotifierHandler mHandler;
93    private final Intent mScreenOnIntent;
94    private final Intent mScreenOffIntent;
95
96    // The current power state.
97    private int mActualPowerState;
98    private int mLastGoToSleepReason;
99
100    // True if there is a pending transition that needs to be reported.
101    private boolean mPendingWakeUpBroadcast;
102    private boolean mPendingGoToSleepBroadcast;
103
104    // The currently broadcasted power state.  This reflects what other parts of the
105    // system have observed.
106    private int mBroadcastedPowerState;
107    private boolean mBroadcastInProgress;
108    private long mBroadcastStartTime;
109
110    // True if a user activity message should be sent.
111    private boolean mUserActivityPending;
112
113    // True if the screen on blocker has been acquired.
114    private boolean mScreenOnBlockerAcquired;
115
116    public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
117            IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
118            WindowManagerPolicy policy) {
119        mContext = context;
120        mBatteryStats = batteryStats;
121        mAppOps = appOps;
122        mSuspendBlocker = suspendBlocker;
123        mScreenOnBlocker = screenOnBlocker;
124        mPolicy = policy;
125        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
126        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
127
128        mHandler = new NotifierHandler(looper);
129        mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
130        mScreenOnIntent.addFlags(
131                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
132        mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
133        mScreenOffIntent.addFlags(
134                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
135
136        // Initialize interactive state for battery stats.
137        try {
138            mBatteryStats.noteInteractive(true);
139        } catch (RemoteException ex) { }
140    }
141
142    /**
143     * Called when a wake lock is acquired.
144     */
145    public void onWakeLockAcquired(int flags, String tag, String packageName,
146            int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
147        if (DEBUG) {
148            Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
149                    + "\", packageName=" + packageName
150                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
151                    + ", workSource=" + workSource);
152        }
153
154        try {
155            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
156            boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
157                    && ownerUid == Process.SYSTEM_UID;
158            if (workSource != null) {
159                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag,
160                        monitorType, unimportantForLogging);
161            } else {
162                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
163                        monitorType, unimportantForLogging);
164                // XXX need to deal with disabled operations.
165                mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
166                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
167            }
168        } catch (RemoteException ex) {
169            // Ignore
170        }
171    }
172
173    /**
174     * Called when a wake lock is changing.
175     */
176    public void onWakeLockChanging(int flags, String tag, String packageName,
177            int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
178            int newFlags, String newTag, String newPackageName, int newOwnerUid,
179            int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) {
180
181        if (workSource != null && newWorkSource != null) {
182            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
183            final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
184            boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
185                    && newOwnerUid == Process.SYSTEM_UID;
186            if (DEBUG) {
187                Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag
188                        + "\", packageName=" + newPackageName
189                        + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid
190                        + ", workSource=" + newWorkSource);
191            }
192            try {
193                mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, monitorType,
194                        newWorkSource, newOwnerPid, newTag, newHistoryTag,
195                        newMonitorType, unimportantForLogging);
196            } catch (RemoteException ex) {
197                // Ignore
198            }
199        } else {
200            onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource);
201            onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
202                    newWorkSource, newHistoryTag);
203        }
204    }
205
206    /**
207     * Called when a wake lock is released.
208     */
209    public void onWakeLockReleased(int flags, String tag, String packageName,
210            int ownerUid, int ownerPid, WorkSource workSource) {
211        if (DEBUG) {
212            Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
213                    + "\", packageName=" + packageName
214                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
215                    + ", workSource=" + workSource);
216        }
217
218        try {
219            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
220            if (workSource != null) {
221                mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
222            } else {
223                mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
224                mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
225                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
226            }
227        } catch (RemoteException ex) {
228            // Ignore
229        }
230    }
231
232    private static int getBatteryStatsWakeLockMonitorType(int flags) {
233        switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
234            case PowerManager.PARTIAL_WAKE_LOCK:
235            case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
236                return BatteryStats.WAKE_TYPE_PARTIAL;
237            default:
238                return BatteryStats.WAKE_TYPE_FULL;
239        }
240    }
241
242    /**
243     * Notifies that the device is changing interactive state.
244     */
245    public void onInteractiveStateChangeStarted(boolean interactive, int reason) {
246        if (DEBUG) {
247            Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
248                    + ", reason=" + reason);
249        }
250
251        synchronized (mLock) {
252            if (interactive) {
253                // Waking up...
254                if (mActualPowerState != POWER_STATE_AWAKE) {
255                    mActualPowerState = POWER_STATE_AWAKE;
256                    mPendingWakeUpBroadcast = true;
257                    if (!mScreenOnBlockerAcquired) {
258                        mScreenOnBlockerAcquired = true;
259                        mScreenOnBlocker.acquire();
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                    updatePendingBroadcastLocked();
301                }
302            }
303        }
304
305        if (!interactive) {
306            try {
307                mBatteryStats.noteInteractive(false);
308            } catch (RemoteException ex) { }
309        }
310    }
311
312    /**
313     * Called when there has been user activity.
314     */
315    public void onUserActivity(int event, int uid) {
316        if (DEBUG) {
317            Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
318        }
319
320        try {
321            mBatteryStats.noteUserActivity(uid, event);
322        } catch (RemoteException ex) {
323            // Ignore
324        }
325
326        synchronized (mLock) {
327            if (!mUserActivityPending) {
328                mUserActivityPending = true;
329                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
330                msg.setAsynchronous(true);
331                mHandler.sendMessage(msg);
332            }
333        }
334    }
335
336    /**
337     * Called when wireless charging has started so as to provide user feedback.
338     */
339    public void onWirelessChargingStarted() {
340        if (DEBUG) {
341            Slog.d(TAG, "onWirelessChargingStarted");
342        }
343
344        mSuspendBlocker.acquire();
345        Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
346        msg.setAsynchronous(true);
347        mHandler.sendMessage(msg);
348    }
349
350    private void updatePendingBroadcastLocked() {
351        if (!mBroadcastInProgress
352                && mActualPowerState != POWER_STATE_UNKNOWN
353                && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
354                        || mActualPowerState != mBroadcastedPowerState)) {
355            mBroadcastInProgress = true;
356            mSuspendBlocker.acquire();
357            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
358            msg.setAsynchronous(true);
359            mHandler.sendMessage(msg);
360        }
361    }
362
363    private void finishPendingBroadcastLocked() {
364        mBroadcastInProgress = false;
365        mSuspendBlocker.release();
366    }
367
368    private void sendUserActivity() {
369        synchronized (mLock) {
370            if (!mUserActivityPending) {
371                return;
372            }
373            mUserActivityPending = false;
374        }
375
376        mPolicy.userActivity();
377    }
378
379    private void sendNextBroadcast() {
380        final int powerState;
381        final int goToSleepReason;
382        synchronized (mLock) {
383            if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
384                // Broadcasted power state is unknown.  Send wake up.
385                mPendingWakeUpBroadcast = false;
386                mBroadcastedPowerState = POWER_STATE_AWAKE;
387            } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) {
388                // Broadcasted power state is awake.  Send asleep if needed.
389                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
390                        || mActualPowerState == POWER_STATE_ASLEEP) {
391                    mPendingGoToSleepBroadcast = false;
392                    mBroadcastedPowerState = POWER_STATE_ASLEEP;
393                } else {
394                    finishPendingBroadcastLocked();
395                    return;
396                }
397            } else {
398                // Broadcasted power state is asleep.  Send awake if needed.
399                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
400                        || mActualPowerState == POWER_STATE_AWAKE) {
401                    mPendingWakeUpBroadcast = false;
402                    mBroadcastedPowerState = POWER_STATE_AWAKE;
403                } else {
404                    finishPendingBroadcastLocked();
405                    return;
406                }
407            }
408
409            mBroadcastStartTime = SystemClock.uptimeMillis();
410            powerState = mBroadcastedPowerState;
411            goToSleepReason = mLastGoToSleepReason;
412        }
413
414        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
415
416        if (powerState == POWER_STATE_AWAKE) {
417            sendWakeUpBroadcast();
418        } else {
419            sendGoToSleepBroadcast(goToSleepReason);
420        }
421    }
422
423    private void sendWakeUpBroadcast() {
424        if (DEBUG) {
425            Slog.d(TAG, "Sending wake up broadcast.");
426        }
427
428        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
429
430        mPolicy.wakingUp(mScreenOnListener);
431        mActivityManagerInternal.wakingUp();
432
433        if (ActivityManagerNative.isSystemReady()) {
434            mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
435                    mWakeUpBroadcastDone, mHandler, 0, null, null);
436        } else {
437            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
438            sendNextBroadcast();
439        }
440    }
441
442    private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
443            new WindowManagerPolicy.ScreenOnListener() {
444        @Override
445        public void onScreenOn() {
446            synchronized (mLock) {
447                if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
448                    mScreenOnBlockerAcquired = false;
449                    mScreenOnBlocker.release();
450                }
451            }
452        }
453    };
454
455    private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
456        @Override
457        public void onReceive(Context context, Intent intent) {
458            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
459                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
460            sendNextBroadcast();
461        }
462    };
463
464    private void sendGoToSleepBroadcast(int reason) {
465        if (DEBUG) {
466            Slog.d(TAG, "Sending go to sleep broadcast.");
467        }
468
469        int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
470        switch (reason) {
471            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
472                why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
473                break;
474            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
475                why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
476                break;
477        }
478
479        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
480
481        mPolicy.goingToSleep(why);
482        mActivityManagerInternal.goingToSleep();
483
484        if (ActivityManagerNative.isSystemReady()) {
485            mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
486                    mGoToSleepBroadcastDone, mHandler, 0, null, null);
487        } else {
488            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
489            sendNextBroadcast();
490        }
491    }
492
493    private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
494        @Override
495        public void onReceive(Context context, Intent intent) {
496            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
497                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
498            sendNextBroadcast();
499        }
500    };
501
502    private void playWirelessChargingStartedSound() {
503        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
504                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
505        if (soundPath != null) {
506            final Uri soundUri = Uri.parse("file://" + soundPath);
507            if (soundUri != null) {
508                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
509                if (sfx != null) {
510                    sfx.setStreamType(AudioManager.STREAM_SYSTEM);
511                    sfx.play();
512                }
513            }
514        }
515
516        mSuspendBlocker.release();
517    }
518
519    private final class NotifierHandler extends Handler {
520        public NotifierHandler(Looper looper) {
521            super(looper, null, true /*async*/);
522        }
523
524        @Override
525        public void handleMessage(Message msg) {
526            switch (msg.what) {
527                case MSG_USER_ACTIVITY:
528                    sendUserActivity();
529                    break;
530
531                case MSG_BROADCAST:
532                    sendNextBroadcast();
533                    break;
534
535                case MSG_WIRELESS_CHARGING_STARTED:
536                    playWirelessChargingStartedSound();
537                    break;
538            }
539        }
540    }
541}
542