Notifier.java revision 01ee6f6cf7de9fb98fc3a88509b43416caa71040
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.RemoteException; 42import android.os.SystemClock; 43import android.os.UserHandle; 44import android.os.WorkSource; 45import android.provider.Settings; 46import android.util.EventLog; 47import android.util.Slog; 48import android.view.WindowManagerPolicy; 49 50/** 51 * Sends broadcasts about important power state changes. 52 * <p> 53 * This methods of this class may be called by the power manager service while 54 * its lock is being held. Internally it takes care of sending broadcasts to 55 * notify other components of the system or applications asynchronously. 56 * </p><p> 57 * The notifier is designed to collapse unnecessary broadcasts when it is not 58 * possible for the system to have observed an intermediate state. 59 * </p><p> 60 * For example, if the device wakes up, goes to sleep, wakes up again and goes to 61 * sleep again before the wake up notification is sent, then the system will 62 * be told about only one wake up and sleep. However, we always notify the 63 * fact that at least one transition occurred. It is especially important to 64 * tell the system when we go to sleep so that it can lock the keyguard if needed. 65 * </p> 66 */ 67final class Notifier { 68 private static final String TAG = "PowerManagerNotifier"; 69 70 private static final boolean DEBUG = false; 71 72 private static final int POWER_STATE_UNKNOWN = 0; 73 private static final int POWER_STATE_AWAKE = 1; 74 private static final int POWER_STATE_ASLEEP = 2; 75 76 private static final int MSG_USER_ACTIVITY = 1; 77 private static final int MSG_BROADCAST = 2; 78 private static final int MSG_WIRELESS_CHARGING_STARTED = 3; 79 80 private final Object mLock = new Object(); 81 82 private final Context mContext; 83 private final IBatteryStats mBatteryStats; 84 private final IAppOpsService mAppOps; 85 private final SuspendBlocker mSuspendBlocker; 86 private final ScreenOnBlocker mScreenOnBlocker; 87 private final WindowManagerPolicy mPolicy; 88 private final ActivityManagerInternal mActivityManagerInternal; 89 private final InputManagerInternal mInputManagerInternal; 90 91 private final NotifierHandler mHandler; 92 private final Intent mScreenOnIntent; 93 private final Intent mScreenOffIntent; 94 95 // The current power state. 96 private int mActualPowerState; 97 private int mLastGoToSleepReason; 98 99 // True if there is a pending transition that needs to be reported. 100 private boolean mPendingWakeUpBroadcast; 101 private boolean mPendingGoToSleepBroadcast; 102 103 // The currently broadcasted power state. This reflects what other parts of the 104 // system have observed. 105 private int mBroadcastedPowerState; 106 private boolean mBroadcastInProgress; 107 private long mBroadcastStartTime; 108 109 // True if a user activity message should be sent. 110 private boolean mUserActivityPending; 111 112 // True if the screen on blocker has been acquired. 113 private boolean mScreenOnBlockerAcquired; 114 115 public Notifier(Looper looper, Context context, IBatteryStats batteryStats, 116 IAppOpsService appOps, SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker, 117 WindowManagerPolicy policy) { 118 mContext = context; 119 mBatteryStats = batteryStats; 120 mAppOps = appOps; 121 mSuspendBlocker = suspendBlocker; 122 mScreenOnBlocker = screenOnBlocker; 123 mPolicy = policy; 124 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 125 mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); 126 127 mHandler = new NotifierHandler(looper); 128 mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); 129 mScreenOnIntent.addFlags( 130 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 131 mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); 132 mScreenOffIntent.addFlags( 133 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 134 135 // Initialize interactive state for battery stats. 136 try { 137 mBatteryStats.noteInteractive(true); 138 } catch (RemoteException ex) { } 139 } 140 141 /** 142 * Called when a wake lock is acquired. 143 */ 144 public void onWakeLockAcquired(int flags, String tag, String packageName, 145 int ownerUid, int ownerPid, WorkSource workSource) { 146 if (DEBUG) { 147 Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag 148 + "\", packageName=" + packageName 149 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 150 + ", workSource=" + workSource); 151 } 152 153 try { 154 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 155 if (workSource != null) { 156 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType); 157 } else { 158 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType); 159 // XXX need to deal with disabled operations. 160 mAppOps.startOperation(AppOpsManager.getToken(mAppOps), 161 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); 162 } 163 } catch (RemoteException ex) { 164 // Ignore 165 } 166 } 167 168 /** 169 * Called when a wake lock is released. 170 */ 171 public void onWakeLockReleased(int flags, String tag, String packageName, 172 int ownerUid, int ownerPid, WorkSource workSource) { 173 if (DEBUG) { 174 Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag 175 + "\", packageName=" + packageName 176 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 177 + ", workSource=" + workSource); 178 } 179 180 try { 181 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 182 if (workSource != null) { 183 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType); 184 } else { 185 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType); 186 mAppOps.finishOperation(AppOpsManager.getToken(mAppOps), 187 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); 188 } 189 } catch (RemoteException ex) { 190 // Ignore 191 } 192 } 193 194 private static int getBatteryStatsWakeLockMonitorType(int flags) { 195 switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) { 196 case PowerManager.PARTIAL_WAKE_LOCK: 197 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: 198 return BatteryStats.WAKE_TYPE_PARTIAL; 199 default: 200 return BatteryStats.WAKE_TYPE_FULL; 201 } 202 } 203 204 /** 205 * Notifies that the device is changing interactive state. 206 */ 207 public void onInteractiveStateChangeStarted(boolean interactive, int reason) { 208 if (DEBUG) { 209 Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive 210 + ", reason=" + reason); 211 } 212 213 synchronized (mLock) { 214 if (interactive) { 215 // Waking up... 216 if (mActualPowerState != POWER_STATE_AWAKE) { 217 mActualPowerState = POWER_STATE_AWAKE; 218 mPendingWakeUpBroadcast = true; 219 if (!mScreenOnBlockerAcquired) { 220 mScreenOnBlockerAcquired = true; 221 mScreenOnBlocker.acquire(); 222 } 223 updatePendingBroadcastLocked(); 224 } 225 } else { 226 // Going to sleep... 227 mLastGoToSleepReason = reason; 228 } 229 } 230 231 mInputManagerInternal.setInteractive(interactive); 232 233 if (interactive) { 234 try { 235 mBatteryStats.noteInteractive(true); 236 } catch (RemoteException ex) { } 237 } 238 } 239 240 /** 241 * Notifies that the device has finished changing interactive state. 242 */ 243 public void onInteractiveStateChangeFinished(boolean interactive) { 244 if (DEBUG) { 245 Slog.d(TAG, "onInteractiveChangeFinished"); 246 } 247 248 synchronized (mLock) { 249 if (!interactive) { 250 // Finished going to sleep... 251 // This is a good time to make transitions that we don't want the user to see, 252 // such as bringing the key guard to focus. There's no guarantee for this, 253 // however because the user could turn the device on again at any time. 254 // Some things may need to be protected by other mechanisms that defer screen on. 255 if (mActualPowerState != POWER_STATE_ASLEEP) { 256 mActualPowerState = POWER_STATE_ASLEEP; 257 mPendingGoToSleepBroadcast = true; 258 if (mUserActivityPending) { 259 mUserActivityPending = false; 260 mHandler.removeMessages(MSG_USER_ACTIVITY); 261 } 262 updatePendingBroadcastLocked(); 263 } 264 } 265 } 266 267 if (!interactive) { 268 try { 269 mBatteryStats.noteInteractive(false); 270 } catch (RemoteException ex) { } 271 } 272 } 273 274 /** 275 * Called when there has been user activity. 276 */ 277 public void onUserActivity(int event, int uid) { 278 if (DEBUG) { 279 Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid); 280 } 281 282 try { 283 mBatteryStats.noteUserActivity(uid, event); 284 } catch (RemoteException ex) { 285 // Ignore 286 } 287 288 synchronized (mLock) { 289 if (!mUserActivityPending) { 290 mUserActivityPending = true; 291 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY); 292 msg.setAsynchronous(true); 293 mHandler.sendMessage(msg); 294 } 295 } 296 } 297 298 /** 299 * Called when wireless charging has started so as to provide user feedback. 300 */ 301 public void onWirelessChargingStarted() { 302 if (DEBUG) { 303 Slog.d(TAG, "onWirelessChargingStarted"); 304 } 305 306 mSuspendBlocker.acquire(); 307 Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED); 308 msg.setAsynchronous(true); 309 mHandler.sendMessage(msg); 310 } 311 312 private void updatePendingBroadcastLocked() { 313 if (!mBroadcastInProgress 314 && mActualPowerState != POWER_STATE_UNKNOWN 315 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 316 || mActualPowerState != mBroadcastedPowerState)) { 317 mBroadcastInProgress = true; 318 mSuspendBlocker.acquire(); 319 Message msg = mHandler.obtainMessage(MSG_BROADCAST); 320 msg.setAsynchronous(true); 321 mHandler.sendMessage(msg); 322 } 323 } 324 325 private void finishPendingBroadcastLocked() { 326 mBroadcastInProgress = false; 327 mSuspendBlocker.release(); 328 } 329 330 private void sendUserActivity() { 331 synchronized (mLock) { 332 if (!mUserActivityPending) { 333 return; 334 } 335 mUserActivityPending = false; 336 } 337 338 mPolicy.userActivity(); 339 } 340 341 private void sendNextBroadcast() { 342 final int powerState; 343 final int goToSleepReason; 344 synchronized (mLock) { 345 if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) { 346 // Broadcasted power state is unknown. Send wake up. 347 mPendingWakeUpBroadcast = false; 348 mBroadcastedPowerState = POWER_STATE_AWAKE; 349 } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) { 350 // Broadcasted power state is awake. Send asleep if needed. 351 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 352 || mActualPowerState == POWER_STATE_ASLEEP) { 353 mPendingGoToSleepBroadcast = false; 354 mBroadcastedPowerState = POWER_STATE_ASLEEP; 355 } else { 356 finishPendingBroadcastLocked(); 357 return; 358 } 359 } else { 360 // Broadcasted power state is asleep. Send awake if needed. 361 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 362 || mActualPowerState == POWER_STATE_AWAKE) { 363 mPendingWakeUpBroadcast = false; 364 mBroadcastedPowerState = POWER_STATE_AWAKE; 365 } else { 366 finishPendingBroadcastLocked(); 367 return; 368 } 369 } 370 371 mBroadcastStartTime = SystemClock.uptimeMillis(); 372 powerState = mBroadcastedPowerState; 373 goToSleepReason = mLastGoToSleepReason; 374 } 375 376 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1); 377 378 if (powerState == POWER_STATE_AWAKE) { 379 sendWakeUpBroadcast(); 380 } else { 381 sendGoToSleepBroadcast(goToSleepReason); 382 } 383 } 384 385 private void sendWakeUpBroadcast() { 386 if (DEBUG) { 387 Slog.d(TAG, "Sending wake up broadcast."); 388 } 389 390 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); 391 392 mPolicy.wakingUp(mScreenOnListener); 393 mActivityManagerInternal.wakingUp(); 394 395 if (ActivityManagerNative.isSystemReady()) { 396 mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null, 397 mWakeUpBroadcastDone, mHandler, 0, null, null); 398 } else { 399 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1); 400 sendNextBroadcast(); 401 } 402 } 403 404 private final WindowManagerPolicy.ScreenOnListener mScreenOnListener = 405 new WindowManagerPolicy.ScreenOnListener() { 406 @Override 407 public void onScreenOn() { 408 synchronized (mLock) { 409 if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) { 410 mScreenOnBlockerAcquired = false; 411 mScreenOnBlocker.release(); 412 } 413 } 414 } 415 }; 416 417 private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() { 418 @Override 419 public void onReceive(Context context, Intent intent) { 420 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1, 421 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 422 sendNextBroadcast(); 423 } 424 }; 425 426 private void sendGoToSleepBroadcast(int reason) { 427 if (DEBUG) { 428 Slog.d(TAG, "Sending go to sleep broadcast."); 429 } 430 431 int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER; 432 switch (reason) { 433 case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN: 434 why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN; 435 break; 436 case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT: 437 why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT; 438 break; 439 } 440 441 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0); 442 443 mPolicy.goingToSleep(why); 444 mActivityManagerInternal.goingToSleep(); 445 446 if (ActivityManagerNative.isSystemReady()) { 447 mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null, 448 mGoToSleepBroadcastDone, mHandler, 0, null, null); 449 } else { 450 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1); 451 sendNextBroadcast(); 452 } 453 } 454 455 private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() { 456 @Override 457 public void onReceive(Context context, Intent intent) { 458 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, 459 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 460 sendNextBroadcast(); 461 } 462 }; 463 464 private void playWirelessChargingStartedSound() { 465 final String soundPath = Settings.Global.getString(mContext.getContentResolver(), 466 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND); 467 if (soundPath != null) { 468 final Uri soundUri = Uri.parse("file://" + soundPath); 469 if (soundUri != null) { 470 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); 471 if (sfx != null) { 472 sfx.setStreamType(AudioManager.STREAM_SYSTEM); 473 sfx.play(); 474 } 475 } 476 } 477 478 mSuspendBlocker.release(); 479 } 480 481 private final class NotifierHandler extends Handler { 482 public NotifierHandler(Looper looper) { 483 super(looper, null, true /*async*/); 484 } 485 486 @Override 487 public void handleMessage(Message msg) { 488 switch (msg.what) { 489 case MSG_USER_ACTIVITY: 490 sendUserActivity(); 491 break; 492 493 case MSG_BROADCAST: 494 sendNextBroadcast(); 495 break; 496 497 case MSG_WIRELESS_CHARGING_STARTED: 498 playWirelessChargingStartedSound(); 499 break; 500 } 501 } 502 } 503} 504