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 17 package com.android.server.power; 18 19 import android.app.ActivityManagerInternal; 20 import android.app.AppOpsManager; 21 22 import com.android.internal.app.IAppOpsService; 23 import com.android.internal.app.IBatteryStats; 24 import com.android.server.EventLogTags; 25 import com.android.server.LocalServices; 26 27 import android.app.ActivityManagerNative; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.hardware.input.InputManagerInternal; 32 import android.media.AudioManager; 33 import android.media.Ringtone; 34 import android.media.RingtoneManager; 35 import android.net.Uri; 36 import android.os.BatteryStats; 37 import android.os.Handler; 38 import android.os.Looper; 39 import android.os.Message; 40 import android.os.PowerManager; 41 import android.os.Process; 42 import android.os.RemoteException; 43 import android.os.SystemClock; 44 import android.os.UserHandle; 45 import android.os.WorkSource; 46 import android.provider.Settings; 47 import android.util.EventLog; 48 import android.util.Slog; 49 import 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 */ 68 final 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 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 public Notifier(Looper looper, Context context, IBatteryStats batteryStats, 113 IAppOpsService appOps, SuspendBlocker suspendBlocker, 114 WindowManagerPolicy policy) { 115 mContext = context; 116 mBatteryStats = batteryStats; 117 mAppOps = appOps; 118 mSuspendBlocker = suspendBlocker; 119 mPolicy = policy; 120 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 121 mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); 122 123 mHandler = new NotifierHandler(looper); 124 mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); 125 mScreenOnIntent.addFlags( 126 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 127 mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); 128 mScreenOffIntent.addFlags( 129 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 130 131 // Initialize interactive state for battery stats. 132 try { 133 mBatteryStats.noteInteractive(true); 134 } catch (RemoteException ex) { } 135 } 136 137 /** 138 * Called when a wake lock is acquired. 139 */ 140 public void onWakeLockAcquired(int flags, String tag, String packageName, 141 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { 142 if (DEBUG) { 143 Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag 144 + "\", packageName=" + packageName 145 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 146 + ", workSource=" + workSource); 147 } 148 149 try { 150 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 151 boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0 152 && ownerUid == Process.SYSTEM_UID; 153 if (workSource != null) { 154 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag, 155 monitorType, unimportantForLogging); 156 } else { 157 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag, 158 monitorType, unimportantForLogging); 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 changing. 170 */ 171 public void onWakeLockChanging(int flags, String tag, String packageName, 172 int ownerUid, int ownerPid, WorkSource workSource, String historyTag, 173 int newFlags, String newTag, String newPackageName, int newOwnerUid, 174 int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) { 175 176 if (workSource != null && newWorkSource != null) { 177 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 178 final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags); 179 boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0 180 && newOwnerUid == Process.SYSTEM_UID; 181 if (DEBUG) { 182 Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag 183 + "\", packageName=" + newPackageName 184 + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid 185 + ", workSource=" + newWorkSource); 186 } 187 try { 188 mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag, 189 monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag, 190 newMonitorType, unimportantForLogging); 191 } catch (RemoteException ex) { 192 // Ignore 193 } 194 } else { 195 onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag); 196 onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid, 197 newWorkSource, newHistoryTag); 198 } 199 } 200 201 /** 202 * Called when a wake lock is released. 203 */ 204 public void onWakeLockReleased(int flags, String tag, String packageName, 205 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { 206 if (DEBUG) { 207 Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag 208 + "\", packageName=" + packageName 209 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 210 + ", workSource=" + workSource); 211 } 212 213 try { 214 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 215 if (workSource != null) { 216 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag, 217 monitorType); 218 } else { 219 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType); 220 mAppOps.finishOperation(AppOpsManager.getToken(mAppOps), 221 AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); 222 } 223 } catch (RemoteException ex) { 224 // Ignore 225 } 226 } 227 228 private static int getBatteryStatsWakeLockMonitorType(int flags) { 229 switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) { 230 case PowerManager.PARTIAL_WAKE_LOCK: 231 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: 232 return BatteryStats.WAKE_TYPE_PARTIAL; 233 default: 234 return BatteryStats.WAKE_TYPE_FULL; 235 } 236 } 237 238 /** 239 * Notifies that the device is changing interactive state. 240 */ 241 public void onInteractiveStateChangeStarted(boolean interactive, final int reason) { 242 if (DEBUG) { 243 Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive 244 + ", reason=" + reason); 245 } 246 247 synchronized (mLock) { 248 if (interactive) { 249 // Waking up... 250 if (mActualPowerState != POWER_STATE_AWAKE) { 251 mActualPowerState = POWER_STATE_AWAKE; 252 mPendingWakeUpBroadcast = true; 253 mHandler.post(new Runnable() { 254 @Override 255 public void run() { 256 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); 257 mPolicy.wakingUp(); 258 mActivityManagerInternal.wakingUp(); 259 } 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 mHandler.post(new Runnable() { 301 @Override 302 public void run() { 303 int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER; 304 switch (mLastGoToSleepReason) { 305 case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN: 306 why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN; 307 break; 308 case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT: 309 why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT; 310 break; 311 } 312 EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0); 313 mPolicy.goingToSleep(why); 314 mActivityManagerInternal.goingToSleep(); 315 } 316 }); 317 updatePendingBroadcastLocked(); 318 } 319 } 320 } 321 322 if (!interactive) { 323 try { 324 mBatteryStats.noteInteractive(false); 325 } catch (RemoteException ex) { } 326 } 327 } 328 329 /** 330 * Called when there has been user activity. 331 */ 332 public void onUserActivity(int event, int uid) { 333 if (DEBUG) { 334 Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid); 335 } 336 337 try { 338 mBatteryStats.noteUserActivity(uid, event); 339 } catch (RemoteException ex) { 340 // Ignore 341 } 342 343 synchronized (mLock) { 344 if (!mUserActivityPending) { 345 mUserActivityPending = true; 346 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY); 347 msg.setAsynchronous(true); 348 mHandler.sendMessage(msg); 349 } 350 } 351 } 352 353 /** 354 * Called when wireless charging has started so as to provide user feedback. 355 */ 356 public void onWirelessChargingStarted() { 357 if (DEBUG) { 358 Slog.d(TAG, "onWirelessChargingStarted"); 359 } 360 361 mSuspendBlocker.acquire(); 362 Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED); 363 msg.setAsynchronous(true); 364 mHandler.sendMessage(msg); 365 } 366 367 private void updatePendingBroadcastLocked() { 368 if (!mBroadcastInProgress 369 && mActualPowerState != POWER_STATE_UNKNOWN 370 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 371 || mActualPowerState != mBroadcastedPowerState)) { 372 mBroadcastInProgress = true; 373 mSuspendBlocker.acquire(); 374 Message msg = mHandler.obtainMessage(MSG_BROADCAST); 375 msg.setAsynchronous(true); 376 mHandler.sendMessage(msg); 377 } 378 } 379 380 private void finishPendingBroadcastLocked() { 381 mBroadcastInProgress = false; 382 mSuspendBlocker.release(); 383 } 384 385 private void sendUserActivity() { 386 synchronized (mLock) { 387 if (!mUserActivityPending) { 388 return; 389 } 390 mUserActivityPending = false; 391 } 392 393 mPolicy.userActivity(); 394 } 395 396 private void sendNextBroadcast() { 397 final int powerState; 398 synchronized (mLock) { 399 if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) { 400 // Broadcasted power state is unknown. Send wake up. 401 mPendingWakeUpBroadcast = false; 402 mBroadcastedPowerState = POWER_STATE_AWAKE; 403 } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) { 404 // Broadcasted power state is awake. Send asleep if needed. 405 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 406 || mActualPowerState == POWER_STATE_ASLEEP) { 407 mPendingGoToSleepBroadcast = false; 408 mBroadcastedPowerState = POWER_STATE_ASLEEP; 409 } else { 410 finishPendingBroadcastLocked(); 411 return; 412 } 413 } else { 414 // Broadcasted power state is asleep. Send awake if needed. 415 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 416 || mActualPowerState == POWER_STATE_AWAKE) { 417 mPendingWakeUpBroadcast = false; 418 mBroadcastedPowerState = POWER_STATE_AWAKE; 419 } else { 420 finishPendingBroadcastLocked(); 421 return; 422 } 423 } 424 425 mBroadcastStartTime = SystemClock.uptimeMillis(); 426 powerState = mBroadcastedPowerState; 427 } 428 429 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1); 430 431 if (powerState == POWER_STATE_AWAKE) { 432 sendWakeUpBroadcast(); 433 } else { 434 sendGoToSleepBroadcast(); 435 } 436 } 437 438 private void sendWakeUpBroadcast() { 439 if (DEBUG) { 440 Slog.d(TAG, "Sending wake up broadcast."); 441 } 442 443 if (ActivityManagerNative.isSystemReady()) { 444 mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null, 445 mWakeUpBroadcastDone, mHandler, 0, null, null); 446 } else { 447 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1); 448 sendNextBroadcast(); 449 } 450 } 451 452 private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() { 453 @Override 454 public void onReceive(Context context, Intent intent) { 455 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1, 456 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 457 sendNextBroadcast(); 458 } 459 }; 460 461 private void sendGoToSleepBroadcast() { 462 if (DEBUG) { 463 Slog.d(TAG, "Sending go to sleep broadcast."); 464 } 465 466 if (ActivityManagerNative.isSystemReady()) { 467 mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null, 468 mGoToSleepBroadcastDone, mHandler, 0, null, null); 469 } else { 470 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1); 471 sendNextBroadcast(); 472 } 473 } 474 475 private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() { 476 @Override 477 public void onReceive(Context context, Intent intent) { 478 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, 479 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 480 sendNextBroadcast(); 481 } 482 }; 483 484 private void playWirelessChargingStartedSound() { 485 final String soundPath = Settings.Global.getString(mContext.getContentResolver(), 486 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND); 487 if (soundPath != null) { 488 final Uri soundUri = Uri.parse("file://" + soundPath); 489 if (soundUri != null) { 490 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); 491 if (sfx != null) { 492 sfx.setStreamType(AudioManager.STREAM_SYSTEM); 493 sfx.play(); 494 } 495 } 496 } 497 498 mSuspendBlocker.release(); 499 } 500 501 private final class NotifierHandler extends Handler { 502 public NotifierHandler(Looper looper) { 503 super(looper, null, true /*async*/); 504 } 505 506 @Override 507 public void handleMessage(Message msg) { 508 switch (msg.what) { 509 case MSG_USER_ACTIVITY: 510 sendUserActivity(); 511 break; 512 513 case MSG_BROADCAST: 514 sendNextBroadcast(); 515 break; 516 517 case MSG_WIRELESS_CHARGING_STARTED: 518 playWirelessChargingStartedSound(); 519 break; 520 } 521 } 522 } 523 } 524