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