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