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