Notifier.java revision 3edf5272fb2185403dfe64b9722b9fc9b9de80f8
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 synchronized (mLock) { 410 if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) { 411 // Broadcasted power state is unknown. Send wake up. 412 mPendingWakeUpBroadcast = false; 413 mBroadcastedPowerState = POWER_STATE_AWAKE; 414 } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) { 415 // Broadcasted power state is awake. Send asleep if needed. 416 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 417 || mActualPowerState == POWER_STATE_ASLEEP) { 418 mPendingGoToSleepBroadcast = false; 419 mBroadcastedPowerState = POWER_STATE_ASLEEP; 420 } else { 421 finishPendingBroadcastLocked(); 422 return; 423 } 424 } else { 425 // Broadcasted power state is asleep. Send awake if needed. 426 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 427 || mActualPowerState == POWER_STATE_AWAKE) { 428 mPendingWakeUpBroadcast = false; 429 mBroadcastedPowerState = POWER_STATE_AWAKE; 430 } else { 431 finishPendingBroadcastLocked(); 432 return; 433 } 434 } 435 436 mBroadcastStartTime = SystemClock.uptimeMillis(); 437 powerState = mBroadcastedPowerState; 438 } 439 440 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1); 441 442 if (powerState == POWER_STATE_AWAKE) { 443 sendWakeUpBroadcast(); 444 } else { 445 sendGoToSleepBroadcast(); 446 } 447 } 448 449 private void sendWakeUpBroadcast() { 450 if (DEBUG) { 451 Slog.d(TAG, "Sending wake up broadcast."); 452 } 453 454 if (ActivityManagerNative.isSystemReady()) { 455 mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null, 456 mWakeUpBroadcastDone, mHandler, 0, null, null); 457 } else { 458 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1); 459 sendNextBroadcast(); 460 } 461 } 462 463 private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener { 464 @Override 465 public void onScreenOn() { 466 synchronized (mLock) { 467 if (mPendingScreenOnUnblocker == this) { 468 mPendingScreenOnUnblocker = null; 469 mScreenOnBlocker.release(); 470 } 471 } 472 } 473 } 474 475 private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() { 476 @Override 477 public void onReceive(Context context, Intent intent) { 478 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1, 479 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 480 sendNextBroadcast(); 481 } 482 }; 483 484 private void sendGoToSleepBroadcast() { 485 if (DEBUG) { 486 Slog.d(TAG, "Sending go to sleep broadcast."); 487 } 488 489 if (ActivityManagerNative.isSystemReady()) { 490 mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null, 491 mGoToSleepBroadcastDone, mHandler, 0, null, null); 492 } else { 493 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1); 494 sendNextBroadcast(); 495 } 496 } 497 498 private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() { 499 @Override 500 public void onReceive(Context context, Intent intent) { 501 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, 502 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 503 sendNextBroadcast(); 504 } 505 }; 506 507 private void playWirelessChargingStartedSound() { 508 final String soundPath = Settings.Global.getString(mContext.getContentResolver(), 509 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND); 510 if (soundPath != null) { 511 final Uri soundUri = Uri.parse("file://" + soundPath); 512 if (soundUri != null) { 513 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); 514 if (sfx != null) { 515 sfx.setStreamType(AudioManager.STREAM_SYSTEM); 516 sfx.play(); 517 } 518 } 519 } 520 521 mSuspendBlocker.release(); 522 } 523 524 private final class NotifierHandler extends Handler { 525 public NotifierHandler(Looper looper) { 526 super(looper, null, true /*async*/); 527 } 528 529 @Override 530 public void handleMessage(Message msg) { 531 switch (msg.what) { 532 case MSG_USER_ACTIVITY: 533 sendUserActivity(); 534 break; 535 536 case MSG_BROADCAST: 537 sendNextBroadcast(); 538 break; 539 540 case MSG_WIRELESS_CHARGING_STARTED: 541 playWirelessChargingStartedSound(); 542 break; 543 } 544 } 545 } 546} 547