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