From 543083593430208af87e51b94cdbbb51cbe2d7b5 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Thu, 4 Oct 2012 17:59:58 -0700 Subject: [PATCH] Ensure we send at least one wakeup/gotosleep transition. This fixes an issue where the device would not lock immediately when the user quickly pressed power off / power on even if configured to do so. We were suppressing the screen off and wake up broadcast in this case. Now we make sure to always send at least one broadcast to indicate the transition. We still collapse back-to-back full cycle transitions though so as not to end up enqueuing useless broadcasts. Bug: 7061116 Change-Id: I7211c5fd963c271c2b0aceb4d2f746063c629079 --- .../com/android/server/power/Notifier.java | 64 ++++++++++++++----- .../server/power/PowerManagerService.java | 29 +++++---- 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java index ce1e147029212..3042124859451 100644 --- a/services/java/com/android/server/power/Notifier.java +++ b/services/java/com/android/server/power/Notifier.java @@ -39,17 +39,20 @@ import android.view.WindowManagerPolicy.ScreenOnListener; /** * Sends broadcasts about important power state changes. - * + *

* This methods of this class may be called by the power manager service while * its lock is being held. Internally it takes care of sending broadcasts to * notify other components of the system or applications asynchronously. - * + *

* The notifier is designed to collapse unnecessary broadcasts when it is not * possible for the system to have observed an intermediate state. - * - * For example, if the device wakes up, goes to sleep and wakes up again immediately - * before the go to sleep broadcast has been sent, then no broadcast will be - * sent about the system going to sleep and waking up. + *

+ * For example, if the device wakes up, goes to sleep, wakes up again and goes to + * sleep again before the wake up notification is sent, then the system will + * be told about only one wake up and sleep. However, we always notify the + * fact that at least one transition occurred. It is especially important to + * tell the system when we go to sleep so that it can lock the keyguard if needed. + *

*/ final class Notifier { private static final String TAG = "PowerManagerNotifier"; @@ -79,6 +82,10 @@ final class Notifier { private int mActualPowerState; private int mLastGoToSleepReason; + // True if there is a pending transition that needs to be reported. + private boolean mPendingWakeUpBroadcast; + private boolean mPendingGoToSleepBroadcast; + // The currently broadcasted power state. This reflects what other parts of the // system have observed. private int mBroadcastedPowerState; @@ -219,6 +226,7 @@ final class Notifier { synchronized (mLock) { if (mActualPowerState != POWER_STATE_AWAKE) { mActualPowerState = POWER_STATE_AWAKE; + mPendingWakeUpBroadcast = true; updatePendingBroadcastLocked(); } } @@ -264,6 +272,7 @@ final class Notifier { synchronized (mLock) { if (mActualPowerState != POWER_STATE_ASLEEP) { mActualPowerState = POWER_STATE_ASLEEP; + mPendingGoToSleepBroadcast = true; if (mUserActivityPending) { mUserActivityPending = false; mHandler.removeMessages(MSG_USER_ACTIVITY); @@ -300,7 +309,8 @@ final class Notifier { private void updatePendingBroadcastLocked() { if (!mBroadcastInProgress && mActualPowerState != POWER_STATE_UNKNOWN - && mActualPowerState != mBroadcastedPowerState) { + && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast + || mActualPowerState != mBroadcastedPowerState)) { mBroadcastInProgress = true; mSuspendBlocker.acquire(); Message msg = mHandler.obtainMessage(MSG_BROADCAST); @@ -309,6 +319,11 @@ final class Notifier { } } + private void finishPendingBroadcastLocked() { + mBroadcastInProgress = false; + mSuspendBlocker.release(); + } + private void sendUserActivity() { synchronized (mLock) { if (!mUserActivityPending) { @@ -324,18 +339,35 @@ final class Notifier { final int powerState; final int goToSleepReason; synchronized (mLock) { - if (mActualPowerState == POWER_STATE_UNKNOWN - || mActualPowerState == mBroadcastedPowerState) { - mBroadcastInProgress = false; - mSuspendBlocker.release(); - return; + if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) { + // Broadcasted power state is unknown. Send wake up. + mPendingWakeUpBroadcast = false; + mBroadcastedPowerState = POWER_STATE_AWAKE; + } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) { + // Broadcasted power state is awake. Send asleep if needed. + if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast + || mActualPowerState == POWER_STATE_ASLEEP) { + mPendingGoToSleepBroadcast = false; + mBroadcastedPowerState = POWER_STATE_ASLEEP; + } else { + finishPendingBroadcastLocked(); + return; + } + } else { + // Broadcasted power state is asleep. Send awake if needed. + if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast + || mActualPowerState == POWER_STATE_AWAKE) { + mPendingWakeUpBroadcast = false; + mBroadcastedPowerState = POWER_STATE_AWAKE; + } else { + finishPendingBroadcastLocked(); + return; + } } - powerState = mActualPowerState; - goToSleepReason = mLastGoToSleepReason; - - mBroadcastedPowerState = powerState; mBroadcastStartTime = SystemClock.uptimeMillis(); + powerState = mBroadcastedPowerState; + goToSleepReason = mLastGoToSleepReason; } EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1); diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index eecac077e0498..ae7b2d1ffb122 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -828,9 +828,9 @@ public final class PowerManagerService extends IPowerManager.Stub switch (mWakefulness) { case WAKEFULNESS_ASLEEP: Slog.i(TAG, "Waking up from sleep..."); + sendPendingNotificationsLocked(); mNotifier.onWakeUpStarted(); mSendWakeUpFinishedNotificationWhenReady = true; - mSendGoToSleepFinishedNotificationWhenReady = false; break; case WAKEFULNESS_DREAMING: Slog.i(TAG, "Waking up from dream..."); @@ -901,12 +901,13 @@ public final class PowerManagerService extends IPowerManager.Stub break; } + sendPendingNotificationsLocked(); + mNotifier.onGoToSleepStarted(reason); + mSendGoToSleepFinishedNotificationWhenReady = true; + mLastSleepTime = eventTime; mDirty |= DIRTY_WAKEFULNESS; mWakefulness = WAKEFULNESS_ASLEEP; - mNotifier.onGoToSleepStarted(reason); - mSendGoToSleepFinishedNotificationWhenReady = true; - mSendWakeUpFinishedNotificationWhenReady = false; // Report the number of wake locks that will be cleared by going to sleep. int numWakeLocksCleared = 0; @@ -1005,7 +1006,9 @@ public final class PowerManagerService extends IPowerManager.Stub updateDisplayPowerStateLocked(dirtyPhase2); // Phase 3: Send notifications, if needed. - sendPendingNotificationsLocked(); + if (mDisplayReady) { + sendPendingNotificationsLocked(); + } // Phase 4: Update suspend blocker. // Because we might release the last suspend blocker here, we need to make sure @@ -1014,15 +1017,13 @@ public final class PowerManagerService extends IPowerManager.Stub } private void sendPendingNotificationsLocked() { - if (mDisplayReady) { - if (mSendWakeUpFinishedNotificationWhenReady) { - mSendWakeUpFinishedNotificationWhenReady = false; - mNotifier.onWakeUpFinished(); - } - if (mSendGoToSleepFinishedNotificationWhenReady) { - mSendGoToSleepFinishedNotificationWhenReady = false; - mNotifier.onGoToSleepFinished(); - } + if (mSendWakeUpFinishedNotificationWhenReady) { + mSendWakeUpFinishedNotificationWhenReady = false; + mNotifier.onWakeUpFinished(); + } + if (mSendGoToSleepFinishedNotificationWhenReady) { + mSendGoToSleepFinishedNotificationWhenReady = false; + mNotifier.onGoToSleepFinished(); } }