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

Commit f19b13f2 authored by Rupesh Bansal's avatar Rupesh Bansal
Browse files

Fix binder leakage when wakelock is released

We were not unsubscribing the callbacks when the wakelocks are released,
but were doing that only when the binder died. This lead to many leaky
binders for the released wakelocks

Bug: 431687714
Flag: com.android.server.power.feature.flags.disable_frozen_process_wakelocks
Test: atest PowerManagerServiceTest
Change-Id: Ifaba8c97ca072735f391ff534e2a134e75d6fba2
parent 909b391f
Loading
Loading
Loading
Loading
+29 −22
Original line number Diff line number Diff line
@@ -1694,6 +1694,7 @@ public final class PowerManagerService extends SystemService
            }

            applyWakeLockFlagsOnAcquireLocked(wakeLock);
            addFrozenStateChangeCallbacksLocked(wakeLock);
            mDirty |= DIRTY_WAKE_LOCKS;
            updatePowerStateLocked();
            if (notifyAcquire) {
@@ -1864,7 +1865,25 @@ public final class PowerManagerService extends SystemService
        }
    }

    private void removeWakelockFrozenStateReferences(WakeLock wakelock) {
    private void addFrozenStateChangeCallbacksLocked(WakeLock wakelock) {
        if (mFeatureFlags.isDisableFrozenProcessWakelocksEnabled()) {
            try {
                wakelock.mLock.addFrozenStateChangeCallback(wakelock);
            } catch (UnsupportedOperationException e) {
                // Ignore the exception.  The callback is not supported on this platform or on
                // this binder.  The callback is never supported for local binders.  There is
                // no error. A log message is provided for debug.
                if (DEBUG_SPEW) {
                    Slog.v(TAG, "FrozenStateChangeCallback not supported for this wakelock "
                            + wakelock.mTag + " " + e.getLocalizedMessage());
                }
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void removeFrozenStateChangeCallbacksLocked(WakeLock wakelock) {
        if (mFeatureFlags.isDisableFrozenProcessWakelocksEnabled()) {
            try {
                wakelock.mLock.removeFrozenStateChangeCallback(wakelock);
@@ -1873,6 +1892,8 @@ public final class PowerManagerService extends SystemService
                    Slog.v(TAG, "FrozenStateChangeCallback not supported for this wakelock "
                            + wakelock.mTag + " " + e.getLocalizedMessage());
                }
            } catch (IllegalArgumentException e) {
                Slog.v(TAG, "FrozenStateChangeCallback was already unregistered");
            }
        }
    }
@@ -1900,13 +1921,14 @@ public final class PowerManagerService extends SystemService

    @GuardedBy("mLock")
    private void removeWakeLockLocked(WakeLock wakeLock, int index) {
        removeFrozenStateChangeCallbacksLocked(wakeLock);
        removeWakeLockNoUpdateLocked(wakeLock, index);
        updatePowerStateLocked();
    }

    @GuardedBy("mLock")
    private void removeWakeLockDeathLocked(WakeLock wakeLock, int index) {
        removeWakelockFrozenStateReferences(wakeLock);
        removeFrozenStateChangeCallbacksLocked(wakeLock);
        removeWakeLockNoUpdateLocked(wakeLock, index, RELEASE_REASON_WAKE_LOCK_DEATH);
        updatePowerStateLocked();
    }
@@ -4516,11 +4538,6 @@ public final class PowerManagerService extends SystemService
        return mDeviceIdleMode || (mLightDeviceIdleMode && disableWakelocksInLightIdle());
    }

    @GuardedBy("mLock")
    private void updateWakeLockDisabledStatesLocked() {
        updateWakeLockDisabledStatesLocked(mWakeLocks);
    }

    @GuardedBy("mLock")
    private void updateWakeLockDisabledStatesLocked(List<WakeLock> wakelocks) {
        boolean changed = false;
@@ -4547,6 +4564,11 @@ public final class PowerManagerService extends SystemService
        }
    }

    @GuardedBy("mLock")
    private void updateWakeLockDisabledStatesLocked() {
        updateWakeLockDisabledStatesLocked(mWakeLocks);
    }

    @GuardedBy("mLock")
    private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
        boolean disabled = false;
@@ -5687,21 +5709,6 @@ public final class PowerManagerService extends SystemService
            mOwnerPid = ownerPid;
            mUidState = uidState;
            mCallback = callback;
            if (mFeatureFlags.isDisableFrozenProcessWakelocksEnabled()) {
                try {
                    lock.addFrozenStateChangeCallback(this);
                } catch (UnsupportedOperationException e) {
                    // Ignore the exception.  The callback is not supported on this platform or on
                    // this binder.  The callback is never supported for local binders.  There is
                    // no error. A log message is provided for debug.
                    if (DEBUG_SPEW) {
                        Slog.v(TAG, "FrozenStateChangeCallback not supported for this wakelock "
                                + tag + " " + e.getLocalizedMessage());
                    }
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }
            }
            linkToDeath();
        }

+5 −1
Original line number Diff line number Diff line
@@ -3595,10 +3595,10 @@ public class PowerManagerServiceTest {

        IBinder mockBinder = mock(IBinder.class);
        doNothing().when(mockBinder).addFrozenStateChangeCallback(any());
        when(mockBinder.removeFrozenStateChangeCallback(any())).thenReturn(true);

        WakeLock wakeLock = acquireWakeLock("frozenTestWakeLock",
                PowerManager.PARTIAL_WAKE_LOCK, mockBinder, Display.INVALID_DISPLAY);
        verify(mockBinder).addFrozenStateChangeCallback(wakeLock);
        assertThat(wakeLock.mDisabled).isFalse();
        assertThat(wakeLock.isFrozenLocked()).isFalse();
        advanceTime(1000);
@@ -3614,6 +3614,10 @@ public class PowerManagerServiceTest {
        advanceTime(1000);
        assertThat(wakeLock.mDisabled).isFalse();
        assertThat(wakeLock.isFrozenLocked()).isFalse();

        when(mockBinder.removeFrozenStateChangeCallback(wakeLock)).thenReturn(true);
        mService.getBinderServiceInstance().releaseWakeLock(mockBinder, 0);
        verify(mockBinder).removeFrozenStateChangeCallback(wakeLock);
    }

    @Test