2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.power;
19 import android.app.ActivityManagerInternal;
20 import android.app.AppOpsManager;
22 import com.android.internal.app.IAppOpsService;
23 import com.android.internal.app.IBatteryStats;
24 import com.android.server.EventLogTags;
25 import com.android.server.LocalServices;
27 import android.app.ActivityManagerNative;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.hardware.input.InputManagerInternal;
32 import android.media.AudioManager;
33 import android.media.Ringtone;
34 import android.media.RingtoneManager;
35 import android.net.Uri;
36 import android.os.BatteryStats;
37 import android.os.Handler;
38 import android.os.Looper;
39 import android.os.Message;
40 import android.os.PowerManager;
41 import android.os.PowerManagerInternal;
42 import android.os.Process;
43 import android.os.RemoteException;
44 import android.os.SystemClock;
45 import android.os.UserHandle;
46 import android.os.WorkSource;
47 import android.provider.Settings;
48 import android.util.EventLog;
49 import android.util.Slog;
50 import android.view.WindowManagerPolicy;
53 * Sends broadcasts about important power state changes.
55 * This methods of this class may be called by the power manager service while
56 * its lock is being held. Internally it takes care of sending broadcasts to
57 * notify other components of the system or applications asynchronously.
59 * The notifier is designed to collapse unnecessary broadcasts when it is not
60 * possible for the system to have observed an intermediate state.
62 * For example, if the device wakes up, goes to sleep, wakes up again and goes to
63 * sleep again before the wake up notification is sent, then the system will
64 * be told about only one wake up and sleep. However, we always notify the
65 * fact that at least one transition occurred. It is especially important to
66 * tell the system when we go to sleep so that it can lock the keyguard if needed.
69 final class Notifier {
70 private static final String TAG = "PowerManagerNotifier";
72 private static final boolean DEBUG = false;
74 private static final int INTERACTIVE_STATE_UNKNOWN = 0;
75 private static final int INTERACTIVE_STATE_AWAKE = 1;
76 private static final int INTERACTIVE_STATE_ASLEEP = 2;
78 private static final int MSG_USER_ACTIVITY = 1;
79 private static final int MSG_BROADCAST = 2;
80 private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
82 private final Object mLock = new Object();
84 private final Context mContext;
85 private final IBatteryStats mBatteryStats;
86 private final IAppOpsService mAppOps;
87 private final SuspendBlocker mSuspendBlocker;
88 private final WindowManagerPolicy mPolicy;
89 private final ActivityManagerInternal mActivityManagerInternal;
90 private final InputManagerInternal mInputManagerInternal;
92 private final NotifierHandler mHandler;
93 private final Intent mScreenOnIntent;
94 private final Intent mScreenOffIntent;
96 // The current interactive state.
97 private int mActualInteractiveState;
98 private int mLastReason;
100 // True if there is a pending transition that needs to be reported.
101 private boolean mPendingWakeUpBroadcast;
102 private boolean mPendingGoToSleepBroadcast;
104 // The currently broadcasted interactive state. This reflects what other parts of the
105 // system have observed.
106 private int mBroadcastedInteractiveState;
107 private boolean mBroadcastInProgress;
108 private long mBroadcastStartTime;
110 // True if a user activity message should be sent.
111 private boolean mUserActivityPending;
113 public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
114 IAppOpsService appOps, SuspendBlocker suspendBlocker,
115 WindowManagerPolicy policy) {
117 mBatteryStats = batteryStats;
119 mSuspendBlocker = suspendBlocker;
121 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
122 mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
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);
132 // Initialize interactive state for battery stats.
134 mBatteryStats.noteInteractive(true);
135 } catch (RemoteException ex) { }
139 * Called when a wake lock is acquired.
141 public void onWakeLockAcquired(int flags, String tag, String packageName,
142 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
144 Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
145 + "\", packageName=" + packageName
146 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
147 + ", workSource=" + workSource);
151 final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
152 boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
153 && ownerUid == Process.SYSTEM_UID;
154 if (workSource != null) {
155 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag,
156 monitorType, unimportantForLogging);
158 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
159 monitorType, unimportantForLogging);
160 // XXX need to deal with disabled operations.
161 mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
162 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
164 } catch (RemoteException ex) {
170 * Called when a wake lock is changing.
172 public void onWakeLockChanging(int flags, String tag, String packageName,
173 int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
174 int newFlags, String newTag, String newPackageName, int newOwnerUid,
175 int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) {
177 if (workSource != null && newWorkSource != null) {
178 final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
179 final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
180 boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
181 && newOwnerUid == Process.SYSTEM_UID;
183 Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag
184 + "\", packageName=" + newPackageName
185 + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid
186 + ", workSource=" + newWorkSource);
189 mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
190 monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
191 newMonitorType, unimportantForLogging);
192 } catch (RemoteException ex) {
196 onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
197 onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
198 newWorkSource, newHistoryTag);
203 * Called when a wake lock is released.
205 public void onWakeLockReleased(int flags, String tag, String packageName,
206 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
208 Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
209 + "\", packageName=" + packageName
210 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
211 + ", workSource=" + workSource);
215 final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
216 if (workSource != null) {
217 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag,
220 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType);
221 mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
222 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
224 } catch (RemoteException ex) {
229 private static int getBatteryStatsWakeLockMonitorType(int flags) {
230 switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
231 case PowerManager.PARTIAL_WAKE_LOCK:
232 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
233 return BatteryStats.WAKE_TYPE_PARTIAL;
235 return BatteryStats.WAKE_TYPE_FULL;
240 * Notifies that the device is changing wakefulness.
242 public void onWakefulnessChangeStarted(int wakefulness, int reason) {
244 Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
245 + ", reason=" + reason);
248 // We handle interactive state changes once they start so that the system can
249 // set everything up or the user to begin interacting with applications.
250 final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
252 handleWakefulnessChange(wakefulness, interactive, reason);
254 mLastReason = reason;
257 // Start input as soon as we start waking up or going to sleep.
258 mInputManagerInternal.setInteractive(interactive);
262 * Notifies that the device has finished changing wakefulness.
264 public void onWakefulnessChangeFinished(int wakefulness) {
266 Slog.d(TAG, "onWakefulnessChangeFinished: wakefulness=" + wakefulness);
269 // Handle interactive state changes once they are finished so that the system can
270 // finish pending transitions (such as turning the screen off) before causing
271 // applications to change state visibly.
272 final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
274 handleWakefulnessChange(wakefulness, interactive, mLastReason);
278 private void handleWakefulnessChange(final int wakefulness, boolean interactive,
280 // Tell the activity manager about changes in wakefulness, not just interactivity.
281 // It needs more granularity than other components.
282 mHandler.post(new Runnable() {
285 mActivityManagerInternal.onWakefulnessChanged(wakefulness);
289 // Handle changes in the overall interactive state.
290 boolean interactiveChanged = false;
291 synchronized (mLock) {
292 // Broadcast interactive state changes.
295 interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_AWAKE);
296 if (interactiveChanged) {
297 mActualInteractiveState = INTERACTIVE_STATE_AWAKE;
298 mPendingWakeUpBroadcast = true;
299 mHandler.post(new Runnable() {
302 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
306 updatePendingBroadcastLocked();
310 // This is a good time to make transitions that we don't want the user to see,
311 // such as bringing the key guard to focus. There's no guarantee for this,
312 // however because the user could turn the device on again at any time.
313 // Some things may need to be protected by other mechanisms that defer screen on.
314 interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_ASLEEP);
315 if (interactiveChanged) {
316 mActualInteractiveState = INTERACTIVE_STATE_ASLEEP;
317 mPendingGoToSleepBroadcast = true;
318 if (mUserActivityPending) {
319 mUserActivityPending = false;
320 mHandler.removeMessages(MSG_USER_ACTIVITY);
322 mHandler.post(new Runnable() {
325 int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
327 case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
328 why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
330 case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
331 why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
334 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
335 mPolicy.goingToSleep(why);
338 updatePendingBroadcastLocked();
343 // Notify battery stats.
344 if (interactiveChanged) {
346 mBatteryStats.noteInteractive(interactive);
347 } catch (RemoteException ex) { }
352 * Called when there has been user activity.
354 public void onUserActivity(int event, int uid) {
356 Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
360 mBatteryStats.noteUserActivity(uid, event);
361 } catch (RemoteException ex) {
365 synchronized (mLock) {
366 if (!mUserActivityPending) {
367 mUserActivityPending = true;
368 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
369 msg.setAsynchronous(true);
370 mHandler.sendMessage(msg);
376 * Called when wireless charging has started so as to provide user feedback.
378 public void onWirelessChargingStarted() {
380 Slog.d(TAG, "onWirelessChargingStarted");
383 mSuspendBlocker.acquire();
384 Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
385 msg.setAsynchronous(true);
386 mHandler.sendMessage(msg);
389 private void updatePendingBroadcastLocked() {
390 if (!mBroadcastInProgress
391 && mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN
392 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
393 || mActualInteractiveState != mBroadcastedInteractiveState)) {
394 mBroadcastInProgress = true;
395 mSuspendBlocker.acquire();
396 Message msg = mHandler.obtainMessage(MSG_BROADCAST);
397 msg.setAsynchronous(true);
398 mHandler.sendMessage(msg);
402 private void finishPendingBroadcastLocked() {
403 mBroadcastInProgress = false;
404 mSuspendBlocker.release();
407 private void sendUserActivity() {
408 synchronized (mLock) {
409 if (!mUserActivityPending) {
412 mUserActivityPending = false;
415 mPolicy.userActivity();
418 private void sendNextBroadcast() {
419 final int powerState;
420 synchronized (mLock) {
421 if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
422 // Broadcasted power state is unknown. Send wake up.
423 mPendingWakeUpBroadcast = false;
424 mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
425 } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
426 // Broadcasted power state is awake. Send asleep if needed.
427 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
428 || mActualInteractiveState == INTERACTIVE_STATE_ASLEEP) {
429 mPendingGoToSleepBroadcast = false;
430 mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
432 finishPendingBroadcastLocked();
436 // Broadcasted power state is asleep. Send awake if needed.
437 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
438 || mActualInteractiveState == INTERACTIVE_STATE_AWAKE) {
439 mPendingWakeUpBroadcast = false;
440 mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
442 finishPendingBroadcastLocked();
447 mBroadcastStartTime = SystemClock.uptimeMillis();
448 powerState = mBroadcastedInteractiveState;
451 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
453 if (powerState == INTERACTIVE_STATE_AWAKE) {
454 sendWakeUpBroadcast();
456 sendGoToSleepBroadcast();
460 private void sendWakeUpBroadcast() {
462 Slog.d(TAG, "Sending wake up broadcast.");
465 if (ActivityManagerNative.isSystemReady()) {
466 mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
467 mWakeUpBroadcastDone, mHandler, 0, null, null);
469 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
474 private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
476 public void onReceive(Context context, Intent intent) {
477 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
478 SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
483 private void sendGoToSleepBroadcast() {
485 Slog.d(TAG, "Sending go to sleep broadcast.");
488 if (ActivityManagerNative.isSystemReady()) {
489 mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
490 mGoToSleepBroadcastDone, mHandler, 0, null, null);
492 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
497 private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
499 public void onReceive(Context context, Intent intent) {
500 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
501 SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
506 private void playWirelessChargingStartedSound() {
507 final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
508 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
509 if (soundPath != null) {
510 final Uri soundUri = Uri.parse("file://" + soundPath);
511 if (soundUri != null) {
512 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
514 sfx.setStreamType(AudioManager.STREAM_SYSTEM);
520 mSuspendBlocker.release();
523 private final class NotifierHandler extends Handler {
524 public NotifierHandler(Looper looper) {
525 super(looper, null, true /*async*/);
529 public void handleMessage(Message msg) {
531 case MSG_USER_ACTIVITY:
539 case MSG_WIRELESS_CHARGING_STARTED:
540 playWirelessChargingStartedSound();