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