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