Notifier.java revision 36c4db8bd3bd7dad4b6cb8abd9cdc1a627fe3bbc
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 // The currently active screen on listener. This field is non-null whenever the 114 // ScreenOnBlocker has been acquired and we are awaiting a callback to release it. 115 private ScreenOnUnblocker mPendingScreenOnUnblocker; 116 117 public Notifier(Looper looper, Context context, IBatteryStats batteryStats, 118 IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker, 119 WindowManagerPolicy policy) { 120 mContext = context; 121 mBatteryStats = batteryStats; 122 mAppOps = appOps; 123 mSuspendBlocker = suspendBlocker; 124 mScreenOnBlocker = screenOnBlocker; 125 mPolicy = policy; 126 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 127 mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); 128 129 mHandler = new NotifierHandler(looper); 130 mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); 131 mScreenOnIntent.addFlags( 132 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 133 mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); 134 mScreenOffIntent.addFlags( 135 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 136 137 // Initialize interactive state for battery stats. 138 try { 139 mBatteryStats.noteInteractive(true); 140 } catch (RemoteException ex) { } 141 } 142 143 /** 144 * Called when a wake lock is acquired. 145 */ 146 public void onWakeLockAcquired(int flags, String tag, String packageName, 147 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { 148 if (DEBUG) { 149 Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag 150 + "\", packageName=" + packageName 151 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 152 + ", workSource=" + workSource); 153 } 154 155 try { 156 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 157 boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0 158 && ownerUid == Process.SYSTEM_UID; 159 if (workSource != null) { 160 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag, 161 monitorType, unimportantForLogging); 162 } else { 163 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag, 164 monitorType, unimportantForLogging); 165 // XXX need to deal with disabled operations. 166 mAppOps.startOperation(AppOpsManager.getToken(mAppOps), 167 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); 168 } 169 } catch (RemoteException ex) { 170 // Ignore 171 } 172 } 173 174 /** 175 * Called when a wake lock is changing. 176 */ 177 public void onWakeLockChanging(int flags, String tag, String packageName, 178 int ownerUid, int ownerPid, WorkSource workSource, String historyTag, 179 int newFlags, String newTag, String newPackageName, int newOwnerUid, 180 int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) { 181 182 if (workSource != null && newWorkSource != null) { 183 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 184 final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags); 185 boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0 186 && newOwnerUid == Process.SYSTEM_UID; 187 if (DEBUG) { 188 Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag 189 + "\", packageName=" + newPackageName 190 + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid 191 + ", workSource=" + newWorkSource); 192 } 193 try { 194 mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag, 195 monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag, 196 newMonitorType, unimportantForLogging); 197 } catch (RemoteException ex) { 198 // Ignore 199 } 200 } else { 201 onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag); 202 onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid, 203 newWorkSource, newHistoryTag); 204 } 205 } 206 207 /** 208 * Called when a wake lock is released. 209 */ 210 public void onWakeLockReleased(int flags, String tag, String packageName, 211 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { 212 if (DEBUG) { 213 Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag 214 + "\", packageName=" + packageName 215 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 216 + ", workSource=" + workSource); 217 } 218 219 try { 220 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 221 if (workSource != null) { 222 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag, 223 monitorType); 224 } else { 225 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType); 226 mAppOps.finishOperation(AppOpsManager.getToken(mAppOps), 227 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); 228 } 229 } catch (RemoteException ex) { 230 // Ignore 231 } 232 } 233 234 private static int getBatteryStatsWakeLockMonitorType(int flags) { 235 switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) { 236 case PowerManager.PARTIAL_WAKE_LOCK: 237 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: 238 return BatteryStats.WAKE_TYPE_PARTIAL; 239 default: 240 return BatteryStats.WAKE_TYPE_FULL; 241 } 242 } 243 244 /** 245 * Notifies that the device is changing interactive state. 246 */ 247 public void onInteractiveStateChangeStarted(boolean interactive, final int reason) { 248 if (DEBUG) { 249 Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive 250 + ", reason=" + reason); 251 } 252 253 synchronized (mLock) { 254 if (interactive) { 255 // Waking up... 256 if (mActualPowerState != POWER_STATE_AWAKE) { 257 mActualPowerState = POWER_STATE_AWAKE; 258 mPendingWakeUpBroadcast = true; 259 mHandler.post(new Runnable() { 260 @Override 261 public void run() { 262 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); 263 mPolicy.wakingUp(); 264 mActivityManagerInternal.wakingUp(); 265 } 266 }); 267 updatePendingBroadcastLocked(); 268 } 269 } else { 270 // Going to sleep... 271 mLastGoToSleepReason = reason; 272 } 273 } 274 275 mInputManagerInternal.setInteractive(interactive); 276 277 if (interactive) { 278 try { 279 mBatteryStats.noteInteractive(true); 280 } catch (RemoteException ex) { } 281 } 282 } 283 284 /** 285 * Notifies that the device has finished changing interactive state. 286 */ 287 public void onInteractiveStateChangeFinished(boolean interactive) { 288 if (DEBUG) { 289 Slog.d(TAG, "onInteractiveChangeFinished"); 290 } 291 292 synchronized (mLock) { 293 if (!interactive) { 294 // Finished going to sleep... 295 // This is a good time to make transitions that we don't want the user to see, 296 // such as bringing the key guard to focus. There's no guarantee for this, 297 // however because the user could turn the device on again at any time. 298 // Some things may need to be protected by other mechanisms that defer screen on. 299 if (mActualPowerState != POWER_STATE_ASLEEP) { 300 mActualPowerState = POWER_STATE_ASLEEP; 301 mPendingGoToSleepBroadcast = true; 302 if (mUserActivityPending) { 303 mUserActivityPending = false; 304 mHandler.removeMessages(MSG_USER_ACTIVITY); 305 } 306 mHandler.post(new Runnable() { 307 @Override 308 public void run() { 309 int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER; 310 switch (mLastGoToSleepReason) { 311 case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN: 312 why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN; 313 break; 314 case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT: 315 why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT; 316 break; 317 } 318 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0); 319 mPolicy.goingToSleep(why); 320 mActivityManagerInternal.goingToSleep(); 321 } 322 }); 323 updatePendingBroadcastLocked(); 324 } 325 } 326 } 327 328 if (!interactive) { 329 try { 330 mBatteryStats.noteInteractive(false); 331 } catch (RemoteException ex) { } 332 } 333 } 334 335 /** 336 * Notifies that screen is about to be turned on (any state other than off). 337 */ 338 public void onScreenTurningOn() { 339 synchronized (mLock) { 340 final ScreenOnUnblocker unblocker = blockScreenOnLocked(); 341 mHandler.post(new Runnable() { 342 @Override 343 public void run() { 344 mPolicy.screenTurningOn(unblocker); 345 } 346 }); 347 } 348 } 349 350 /** 351 * Called when there has been user activity. 352 */ 353 public void onUserActivity(int event, int uid) { 354 if (DEBUG) { 355 Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid); 356 } 357 358 try { 359 mBatteryStats.noteUserActivity(uid, event); 360 } catch (RemoteException ex) { 361 // Ignore 362 } 363 364 synchronized (mLock) { 365 if (!mUserActivityPending) { 366 mUserActivityPending = true; 367 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY); 368 msg.setAsynchronous(true); 369 mHandler.sendMessage(msg); 370 } 371 } 372 } 373 374 /** 375 * Called when wireless charging has started so as to provide user feedback. 376 */ 377 public void onWirelessChargingStarted() { 378 if (DEBUG) { 379 Slog.d(TAG, "onWirelessChargingStarted"); 380 } 381 382 mSuspendBlocker.acquire(); 383 Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED); 384 msg.setAsynchronous(true); 385 mHandler.sendMessage(msg); 386 } 387 388 private void updatePendingBroadcastLocked() { 389 if (!mBroadcastInProgress 390 && mActualPowerState != POWER_STATE_UNKNOWN 391 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 392 || mActualPowerState != mBroadcastedPowerState)) { 393 mBroadcastInProgress = true; 394 mSuspendBlocker.acquire(); 395 Message msg = mHandler.obtainMessage(MSG_BROADCAST); 396 msg.setAsynchronous(true); 397 mHandler.sendMessage(msg); 398 } 399 } 400 401 private void finishPendingBroadcastLocked() { 402 mBroadcastInProgress = false; 403 mSuspendBlocker.release(); 404 } 405 406 private void sendUserActivity() { 407 synchronized (mLock) { 408 if (!mUserActivityPending) { 409 return; 410 } 411 mUserActivityPending = false; 412 } 413 414 mPolicy.userActivity(); 415 } 416 417 private void sendNextBroadcast() { 418 final int powerState; 419 synchronized (mLock) { 420 if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) { 421 // Broadcasted power state is unknown. Send wake up. 422 mPendingWakeUpBroadcast = false; 423 mBroadcastedPowerState = POWER_STATE_AWAKE; 424 } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) { 425 // Broadcasted power state is awake. Send asleep if needed. 426 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 427 || mActualPowerState == POWER_STATE_ASLEEP) { 428 mPendingGoToSleepBroadcast = false; 429 mBroadcastedPowerState = POWER_STATE_ASLEEP; 430 } else { 431 finishPendingBroadcastLocked(); 432 return; 433 } 434 } else { 435 // Broadcasted power state is asleep. Send awake if needed. 436 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 437 || mActualPowerState == POWER_STATE_AWAKE) { 438 mPendingWakeUpBroadcast = false; 439 mBroadcastedPowerState = POWER_STATE_AWAKE; 440 } else { 441 finishPendingBroadcastLocked(); 442 return; 443 } 444 } 445 446 mBroadcastStartTime = SystemClock.uptimeMillis(); 447 powerState = mBroadcastedPowerState; 448 } 449 450 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1); 451 452 if (powerState == POWER_STATE_AWAKE) { 453 sendWakeUpBroadcast(); 454 } else { 455 sendGoToSleepBroadcast(); 456 } 457 } 458 459 private void sendWakeUpBroadcast() { 460 if (DEBUG) { 461 Slog.d(TAG, "Sending wake up broadcast."); 462 } 463 464 if (ActivityManagerNative.isSystemReady()) { 465 mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null, 466 mWakeUpBroadcastDone, mHandler, 0, null, null); 467 } else { 468 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1); 469 sendNextBroadcast(); 470 } 471 } 472 473 private ScreenOnUnblocker blockScreenOnLocked() { 474 if (mPendingScreenOnUnblocker == null) { 475 mScreenOnBlocker.acquire(); 476 } 477 mPendingScreenOnUnblocker = new ScreenOnUnblocker(); 478 return mPendingScreenOnUnblocker; 479 } 480 481 private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener { 482 @Override 483 public void onScreenOn() { 484 synchronized (mLock) { 485 if (mPendingScreenOnUnblocker == this) { 486 mPendingScreenOnUnblocker = null; 487 mScreenOnBlocker.release(); 488 } 489 } 490 } 491 } 492 493 private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() { 494 @Override 495 public void onReceive(Context context, Intent intent) { 496 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1, 497 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 498 sendNextBroadcast(); 499 } 500 }; 501 502 private void sendGoToSleepBroadcast() { 503 if (DEBUG) { 504 Slog.d(TAG, "Sending go to sleep broadcast."); 505 } 506 507 if (ActivityManagerNative.isSystemReady()) { 508 mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null, 509 mGoToSleepBroadcastDone, mHandler, 0, null, null); 510 } else { 511 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1); 512 sendNextBroadcast(); 513 } 514 } 515 516 private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() { 517 @Override 518 public void onReceive(Context context, Intent intent) { 519 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, 520 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 521 sendNextBroadcast(); 522 } 523 }; 524 525 private void playWirelessChargingStartedSound() { 526 final String soundPath = Settings.Global.getString(mContext.getContentResolver(), 527 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND); 528 if (soundPath != null) { 529 final Uri soundUri = Uri.parse("file://" + soundPath); 530 if (soundUri != null) { 531 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); 532 if (sfx != null) { 533 sfx.setStreamType(AudioManager.STREAM_SYSTEM); 534 sfx.play(); 535 } 536 } 537 } 538 539 mSuspendBlocker.release(); 540 } 541 542 private final class NotifierHandler extends Handler { 543 public NotifierHandler(Looper looper) { 544 super(looper, null, true /*async*/); 545 } 546 547 @Override 548 public void handleMessage(Message msg) { 549 switch (msg.what) { 550 case MSG_USER_ACTIVITY: 551 sendUserActivity(); 552 break; 553 554 case MSG_BROADCAST: 555 sendNextBroadcast(); 556 break; 557 558 case MSG_WIRELESS_CHARGING_STARTED: 559 playWirelessChargingStartedSound(); 560 break; 561 } 562 } 563 } 564} 565