blob: c5a71eccce02edcf5db5b29260fc4cb6009f5660 [file] [log] [blame]
Jeff Brown96307042012-07-27 15:51:34 -07001/*
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
Dianne Hackborn713df152013-05-17 11:27:57 -070019import android.app.AppOpsManager;
20import com.android.internal.app.IAppOpsService;
Jeff Brown96307042012-07-27 15:51:34 -070021import com.android.internal.app.IBatteryStats;
22import com.android.server.EventLogTags;
23
24import android.app.ActivityManagerNative;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.Intent;
Jeff Brown84e27562012-12-07 13:56:34 -080028import android.media.AudioManager;
29import android.media.Ringtone;
30import android.media.RingtoneManager;
31import android.net.Uri;
Jeff Brown96307042012-07-27 15:51:34 -070032import android.os.BatteryStats;
33import android.os.Handler;
34import android.os.Looper;
35import android.os.Message;
36import android.os.PowerManager;
Jeff Brown96307042012-07-27 15:51:34 -070037import android.os.RemoteException;
38import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070039import android.os.UserHandle;
Jeff Brown96307042012-07-27 15:51:34 -070040import android.os.WorkSource;
Jeff Brown84e27562012-12-07 13:56:34 -080041import android.provider.Settings;
Jeff Brown96307042012-07-27 15:51:34 -070042import android.util.EventLog;
43import android.util.Slog;
44import android.view.WindowManagerPolicy;
Jeff Brown96307042012-07-27 15:51:34 -070045
46/**
47 * Sends broadcasts about important power state changes.
Jeff Brown54308352012-10-04 17:59:58 -070048 * <p>
Jeff Brown96307042012-07-27 15:51:34 -070049 * This methods of this class may be called by the power manager service while
50 * its lock is being held. Internally it takes care of sending broadcasts to
51 * notify other components of the system or applications asynchronously.
Jeff Brown54308352012-10-04 17:59:58 -070052 * </p><p>
Jeff Brown96307042012-07-27 15:51:34 -070053 * The notifier is designed to collapse unnecessary broadcasts when it is not
54 * possible for the system to have observed an intermediate state.
Jeff Brown54308352012-10-04 17:59:58 -070055 * </p><p>
56 * For example, if the device wakes up, goes to sleep, wakes up again and goes to
57 * sleep again before the wake up notification is sent, then the system will
58 * be told about only one wake up and sleep. However, we always notify the
59 * fact that at least one transition occurred. It is especially important to
60 * tell the system when we go to sleep so that it can lock the keyguard if needed.
61 * </p>
Jeff Brown96307042012-07-27 15:51:34 -070062 */
63final class Notifier {
64 private static final String TAG = "PowerManagerNotifier";
65
66 private static final boolean DEBUG = false;
67
68 private static final int POWER_STATE_UNKNOWN = 0;
69 private static final int POWER_STATE_AWAKE = 1;
70 private static final int POWER_STATE_ASLEEP = 2;
71
72 private static final int MSG_USER_ACTIVITY = 1;
73 private static final int MSG_BROADCAST = 2;
Jeff Brown84e27562012-12-07 13:56:34 -080074 private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
Jeff Brown96307042012-07-27 15:51:34 -070075
76 private final Object mLock = new Object();
77
78 private final Context mContext;
79 private final IBatteryStats mBatteryStats;
Dianne Hackborn713df152013-05-17 11:27:57 -070080 private final IAppOpsService mAppOps;
Jeff Brown96307042012-07-27 15:51:34 -070081 private final SuspendBlocker mSuspendBlocker;
Jeff Brownc38c9be2012-10-04 13:16:19 -070082 private final ScreenOnBlocker mScreenOnBlocker;
Jeff Brown96307042012-07-27 15:51:34 -070083 private final WindowManagerPolicy mPolicy;
Jeff Brown96307042012-07-27 15:51:34 -070084
85 private final NotifierHandler mHandler;
86 private final Intent mScreenOnIntent;
87 private final Intent mScreenOffIntent;
88
89 // The current power state.
90 private int mActualPowerState;
91 private int mLastGoToSleepReason;
92
Jeff Brown54308352012-10-04 17:59:58 -070093 // True if there is a pending transition that needs to be reported.
94 private boolean mPendingWakeUpBroadcast;
95 private boolean mPendingGoToSleepBroadcast;
96
Jeff Brown96307042012-07-27 15:51:34 -070097 // The currently broadcasted power state. This reflects what other parts of the
98 // system have observed.
99 private int mBroadcastedPowerState;
100 private boolean mBroadcastInProgress;
101 private long mBroadcastStartTime;
102
103 // True if a user activity message should be sent.
104 private boolean mUserActivityPending;
105
Jeff Brownc38c9be2012-10-04 13:16:19 -0700106 // True if the screen on blocker has been acquired.
107 private boolean mScreenOnBlockerAcquired;
108
Jeff Brown96307042012-07-27 15:51:34 -0700109 public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
Dianne Hackborn713df152013-05-17 11:27:57 -0700110 IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
Jeff Brownc38c9be2012-10-04 13:16:19 -0700111 WindowManagerPolicy policy) {
Jeff Brown96307042012-07-27 15:51:34 -0700112 mContext = context;
113 mBatteryStats = batteryStats;
Dianne Hackborn713df152013-05-17 11:27:57 -0700114 mAppOps = appOps;
Jeff Brown96307042012-07-27 15:51:34 -0700115 mSuspendBlocker = suspendBlocker;
Jeff Brownc38c9be2012-10-04 13:16:19 -0700116 mScreenOnBlocker = screenOnBlocker;
Jeff Brown96307042012-07-27 15:51:34 -0700117 mPolicy = policy;
Jeff Brown96307042012-07-27 15:51:34 -0700118
119 mHandler = new NotifierHandler(looper);
120 mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
121 mScreenOnIntent.addFlags(
122 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
123 mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
124 mScreenOffIntent.addFlags(
125 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
126 }
127
128 /**
129 * Called when a wake lock is acquired.
130 */
Dianne Hackborn713df152013-05-17 11:27:57 -0700131 public void onWakeLockAcquired(int flags, String tag, String packageName,
132 int ownerUid, int ownerPid, WorkSource workSource) {
Jeff Brown96307042012-07-27 15:51:34 -0700133 if (DEBUG) {
134 Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
Dianne Hackborn713df152013-05-17 11:27:57 -0700135 + "\", packageName=" + packageName
136 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
Jeff Brown96307042012-07-27 15:51:34 -0700137 + ", workSource=" + workSource);
138 }
139
Craig Mautner259328c2012-08-21 19:30:58 -0700140 try {
141 final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
142 if (workSource != null) {
143 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
144 } else {
145 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
Dianne Hackborn713df152013-05-17 11:27:57 -0700146 // XXX need to deal with disabled operations.
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700147 mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
148 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
Jeff Brown96307042012-07-27 15:51:34 -0700149 }
Craig Mautner259328c2012-08-21 19:30:58 -0700150 } catch (RemoteException ex) {
151 // Ignore
Jeff Brown96307042012-07-27 15:51:34 -0700152 }
153 }
154
155 /**
156 * Called when a wake lock is released.
157 */
Dianne Hackborn713df152013-05-17 11:27:57 -0700158 public void onWakeLockReleased(int flags, String tag, String packageName,
159 int ownerUid, int ownerPid, WorkSource workSource) {
Jeff Brown96307042012-07-27 15:51:34 -0700160 if (DEBUG) {
161 Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
Dianne Hackborn713df152013-05-17 11:27:57 -0700162 + "\", packageName=" + packageName
163 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
Jeff Brown96307042012-07-27 15:51:34 -0700164 + ", workSource=" + workSource);
165 }
166
Craig Mautner259328c2012-08-21 19:30:58 -0700167 try {
168 final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
169 if (workSource != null) {
170 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
171 } else {
172 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700173 mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
174 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
Jeff Brown96307042012-07-27 15:51:34 -0700175 }
Craig Mautner259328c2012-08-21 19:30:58 -0700176 } catch (RemoteException ex) {
177 // Ignore
Jeff Brown96307042012-07-27 15:51:34 -0700178 }
179 }
180
Jeff Brown96307042012-07-27 15:51:34 -0700181 private static int getBatteryStatsWakeLockMonitorType(int flags) {
182 switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
183 case PowerManager.PARTIAL_WAKE_LOCK:
184 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
185 return BatteryStats.WAKE_TYPE_PARTIAL;
186 default:
187 return BatteryStats.WAKE_TYPE_FULL;
188 }
189 }
190
191 /**
Jeff Brown96307042012-07-27 15:51:34 -0700192 * Called when the device is waking up from sleep and the
193 * display is about to be turned on.
194 */
195 public void onWakeUpStarted() {
196 if (DEBUG) {
197 Slog.d(TAG, "onWakeUpStarted");
198 }
199
200 synchronized (mLock) {
201 if (mActualPowerState != POWER_STATE_AWAKE) {
202 mActualPowerState = POWER_STATE_AWAKE;
Jeff Brown54308352012-10-04 17:59:58 -0700203 mPendingWakeUpBroadcast = true;
Jeff Brownc38c9be2012-10-04 13:16:19 -0700204 if (!mScreenOnBlockerAcquired) {
205 mScreenOnBlockerAcquired = true;
206 mScreenOnBlocker.acquire();
207 }
Jeff Brown96307042012-07-27 15:51:34 -0700208 updatePendingBroadcastLocked();
209 }
210 }
211 }
212
213 /**
214 * Called when the device has finished waking up from sleep
215 * and the display has been turned on.
216 */
217 public void onWakeUpFinished() {
218 if (DEBUG) {
219 Slog.d(TAG, "onWakeUpFinished");
220 }
221 }
222
223 /**
224 * Called when the device is going to sleep.
225 */
226 public void onGoToSleepStarted(int reason) {
227 if (DEBUG) {
228 Slog.d(TAG, "onGoToSleepStarted");
229 }
230
231 synchronized (mLock) {
232 mLastGoToSleepReason = reason;
233 }
234 }
235
236 /**
237 * Called when the device has finished going to sleep and the
238 * display has been turned off.
239 *
240 * This is a good time to make transitions that we don't want the user to see,
241 * such as bringing the key guard to focus. There's no guarantee for this,
242 * however because the user could turn the device on again at any time.
243 * Some things may need to be protected by other mechanisms that defer screen on.
244 */
245 public void onGoToSleepFinished() {
246 if (DEBUG) {
247 Slog.d(TAG, "onGoToSleepFinished");
248 }
249
250 synchronized (mLock) {
251 if (mActualPowerState != POWER_STATE_ASLEEP) {
252 mActualPowerState = POWER_STATE_ASLEEP;
Jeff Brown54308352012-10-04 17:59:58 -0700253 mPendingGoToSleepBroadcast = true;
Jeff Brown96307042012-07-27 15:51:34 -0700254 if (mUserActivityPending) {
255 mUserActivityPending = false;
256 mHandler.removeMessages(MSG_USER_ACTIVITY);
257 }
258 updatePendingBroadcastLocked();
259 }
260 }
261 }
262
263 /**
264 * Called when there has been user activity.
265 */
266 public void onUserActivity(int event, int uid) {
267 if (DEBUG) {
268 Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
269 }
270
271 try {
272 mBatteryStats.noteUserActivity(uid, event);
273 } catch (RemoteException ex) {
274 // Ignore
275 }
276
277 synchronized (mLock) {
278 if (!mUserActivityPending) {
279 mUserActivityPending = true;
280 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
281 msg.setAsynchronous(true);
282 mHandler.sendMessage(msg);
283 }
284 }
285 }
286
Jeff Brown84e27562012-12-07 13:56:34 -0800287 /**
288 * Called when wireless charging has started so as to provide user feedback.
289 */
290 public void onWirelessChargingStarted() {
291 if (DEBUG) {
292 Slog.d(TAG, "onWirelessChargingStarted");
293 }
294
295 mSuspendBlocker.acquire();
296 Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
297 msg.setAsynchronous(true);
298 mHandler.sendMessage(msg);
299 }
300
Jeff Brown96307042012-07-27 15:51:34 -0700301 private void updatePendingBroadcastLocked() {
302 if (!mBroadcastInProgress
303 && mActualPowerState != POWER_STATE_UNKNOWN
Jeff Brown54308352012-10-04 17:59:58 -0700304 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
305 || mActualPowerState != mBroadcastedPowerState)) {
Jeff Brown96307042012-07-27 15:51:34 -0700306 mBroadcastInProgress = true;
307 mSuspendBlocker.acquire();
308 Message msg = mHandler.obtainMessage(MSG_BROADCAST);
309 msg.setAsynchronous(true);
310 mHandler.sendMessage(msg);
311 }
312 }
313
Jeff Brown54308352012-10-04 17:59:58 -0700314 private void finishPendingBroadcastLocked() {
315 mBroadcastInProgress = false;
316 mSuspendBlocker.release();
317 }
318
Jeff Brown96307042012-07-27 15:51:34 -0700319 private void sendUserActivity() {
320 synchronized (mLock) {
321 if (!mUserActivityPending) {
322 return;
323 }
324 mUserActivityPending = false;
325 }
326
327 mPolicy.userActivity();
328 }
329
330 private void sendNextBroadcast() {
331 final int powerState;
332 final int goToSleepReason;
333 synchronized (mLock) {
Jeff Brown54308352012-10-04 17:59:58 -0700334 if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
335 // Broadcasted power state is unknown. Send wake up.
336 mPendingWakeUpBroadcast = false;
337 mBroadcastedPowerState = POWER_STATE_AWAKE;
338 } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) {
339 // Broadcasted power state is awake. Send asleep if needed.
340 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
341 || mActualPowerState == POWER_STATE_ASLEEP) {
342 mPendingGoToSleepBroadcast = false;
343 mBroadcastedPowerState = POWER_STATE_ASLEEP;
344 } else {
345 finishPendingBroadcastLocked();
346 return;
347 }
348 } else {
349 // Broadcasted power state is asleep. Send awake if needed.
350 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
351 || mActualPowerState == POWER_STATE_AWAKE) {
352 mPendingWakeUpBroadcast = false;
353 mBroadcastedPowerState = POWER_STATE_AWAKE;
354 } else {
355 finishPendingBroadcastLocked();
356 return;
357 }
Jeff Brown96307042012-07-27 15:51:34 -0700358 }
359
Jeff Brown96307042012-07-27 15:51:34 -0700360 mBroadcastStartTime = SystemClock.uptimeMillis();
Jeff Brown54308352012-10-04 17:59:58 -0700361 powerState = mBroadcastedPowerState;
362 goToSleepReason = mLastGoToSleepReason;
Jeff Brown96307042012-07-27 15:51:34 -0700363 }
364
365 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
366
367 if (powerState == POWER_STATE_AWAKE) {
368 sendWakeUpBroadcast();
369 } else {
370 sendGoToSleepBroadcast(goToSleepReason);
371 }
372 }
373
374 private void sendWakeUpBroadcast() {
375 if (DEBUG) {
376 Slog.d(TAG, "Sending wake up broadcast.");
377 }
378
379 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
380
381 mPolicy.screenTurningOn(mScreenOnListener);
Jeff Brownc38c9be2012-10-04 13:16:19 -0700382
Jeff Brown96307042012-07-27 15:51:34 -0700383 try {
384 ActivityManagerNative.getDefault().wakingUp();
385 } catch (RemoteException e) {
386 // ignore it
387 }
388
389 if (ActivityManagerNative.isSystemReady()) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700390 mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
Jeff Brown96307042012-07-27 15:51:34 -0700391 mWakeUpBroadcastDone, mHandler, 0, null, null);
392 } else {
393 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
394 sendNextBroadcast();
395 }
396 }
397
Jeff Brownc38c9be2012-10-04 13:16:19 -0700398 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
Jeff Brown96307042012-07-27 15:51:34 -0700411 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 try {
439 ActivityManagerNative.getDefault().goingToSleep();
440 } catch (RemoteException e) {
441 // ignore it.
442 }
443
444 if (ActivityManagerNative.isSystemReady()) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700445 mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
Jeff Brown96307042012-07-27 15:51:34 -0700446 mGoToSleepBroadcastDone, mHandler, 0, null, null);
447 } else {
448 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
449 sendNextBroadcast();
450 }
451 }
452
453 private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
454 @Override
455 public void onReceive(Context context, Intent intent) {
456 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
457 SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
458 sendNextBroadcast();
459 }
460 };
461
Jeff Brown84e27562012-12-07 13:56:34 -0800462 private void playWirelessChargingStartedSound() {
463 final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
464 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
465 if (soundPath != null) {
466 final Uri soundUri = Uri.parse("file://" + soundPath);
467 if (soundUri != null) {
468 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
469 if (sfx != null) {
470 sfx.setStreamType(AudioManager.STREAM_SYSTEM);
471 sfx.play();
472 }
473 }
474 }
475
476 mSuspendBlocker.release();
477 }
478
Jeff Brown96307042012-07-27 15:51:34 -0700479 private final class NotifierHandler extends Handler {
480 public NotifierHandler(Looper looper) {
Jeff Browna2910d02012-08-25 12:29:46 -0700481 super(looper, null, true /*async*/);
Jeff Brown96307042012-07-27 15:51:34 -0700482 }
483
484 @Override
485 public void handleMessage(Message msg) {
486 switch (msg.what) {
487 case MSG_USER_ACTIVITY:
488 sendUserActivity();
489 break;
490
491 case MSG_BROADCAST:
492 sendNextBroadcast();
493 break;
Jeff Brown84e27562012-12-07 13:56:34 -0800494
495 case MSG_WIRELESS_CHARGING_STARTED:
496 playWirelessChargingStartedSound();
497 break;
Jeff Brown96307042012-07-27 15:51:34 -0700498 }
499 }
500 }
501}