Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 291c32a7 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Allow timed wakelocks to be released gracefully.

When using a reference-counted wakelock together with a timeout, we
can end up with an over-released wakelock which causes an app crash.

To mitigate this, only throw based on count of external
acquire/release events.

Bug: 62326550
Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.cts.PowerManager_WakeLockTest
Change-Id: I66480cb9798f9404ae3d45a70d68eae136d289de
parent f4d4f9b9
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -266,7 +266,13 @@ public final class PowerManager {
     * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor
     * indicates that an object is not in close proximity.
     */
    public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1;
    public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1 << 0;

    /**
     * Flag for {@link WakeLock#release(int)} when called due to timeout.
     * @hide
     */
    public static final int RELEASE_FLAG_TIMEOUT = 1 << 16;

    /**
     * Brightness value for fully on.
@@ -1242,7 +1248,8 @@ public final class PowerManager {
        private String mTag;
        private final String mPackageName;
        private final IBinder mToken;
        private int mCount;
        private int mInternalCount;
        private int mExternalCount;
        private boolean mRefCounted = true;
        private boolean mHeld;
        private WorkSource mWorkSource;
@@ -1251,7 +1258,7 @@ public final class PowerManager {

        private final Runnable mReleaser = new Runnable() {
            public void run() {
                release();
                release(RELEASE_FLAG_TIMEOUT);
            }
        };

@@ -1328,7 +1335,9 @@ public final class PowerManager {
        }

        private void acquireLocked() {
            if (!mRefCounted || mCount++ == 0) {
            mInternalCount++;
            mExternalCount++;
            if (!mRefCounted || mInternalCount == 1) {
                // Do this even if the wake lock is already thought to be held (mHeld == true)
                // because non-reference counted wake locks are not always properly released.
                // For example, the keyguard's wake lock might be forcibly released by the
@@ -1373,7 +1382,11 @@ public final class PowerManager {
         */
        public void release(int flags) {
            synchronized (mToken) {
                if (!mRefCounted || --mCount == 0) {
                mInternalCount--;
                if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
                    mExternalCount--;
                }
                if (!mRefCounted || mInternalCount == 0) {
                    mHandler.removeCallbacks(mReleaser);
                    if (mHeld) {
                        Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
@@ -1385,7 +1398,7 @@ public final class PowerManager {
                        mHeld = false;
                    }
                }
                if (mCount < 0) {
                if (mRefCounted && mExternalCount < 0) {
                    throw new RuntimeException("WakeLock under-locked " + mTag);
                }
            }
@@ -1469,7 +1482,7 @@ public final class PowerManager {
            synchronized (mToken) {
                return "WakeLock{"
                    + Integer.toHexString(System.identityHashCode(this))
                    + " held=" + mHeld + ", refCount=" + mCount + "}";
                    + " held=" + mHeld + ", refCount=" + mInternalCount + "}";
            }
        }