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

Commit 921a373e authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Disable wakelock when the corresponding process is frozen" into main

parents f6f44e34 43c44e10
Loading
Loading
Loading
Loading
+82 −5
Original line number Diff line number Diff line
@@ -156,6 +156,7 @@ import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.NoSuchElementException;
@@ -187,6 +188,9 @@ public final class PowerManagerService extends SystemService
    // Message: Sent when the policy want to release all timeout override wake locks.
    private static final int MSG_RELEASE_ALL_OVERRIDE_WAKE_LOCKS = 6;

    // Message: Sent when the processes frozen state changes
    private static final int MSG_PROCESS_FROZEN_STATE_CHANGED = 7;

    // Dirty bit: mWakeLocks changed
    private static final int DIRTY_WAKE_LOCKS = 1 << 0;
    // Dirty bit: mWakefulness changed
@@ -4369,10 +4373,15 @@ public final class PowerManagerService extends SystemService

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

    @GuardedBy("mLock")
    private void updateWakeLockDisabledStatesLocked(List<WakeLock> wakelocks) {
        boolean changed = false;
        final int numWakeLocks = mWakeLocks.size();
        int numWakeLocks = wakelocks.size();
        for (int i = 0; i < numWakeLocks; i++) {
            final WakeLock wakeLock = mWakeLocks.get(i);
            final WakeLock wakeLock = wakelocks.get(i);
            if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                    == PowerManager.PARTIAL_WAKE_LOCK || isScreenLock(wakeLock)) {
                if (setWakeLockDisabledStateLocked(wakeLock)) {
@@ -4386,6 +4395,7 @@ public final class PowerManagerService extends SystemService
                }
            }
        }

        if (changed) {
            mDirty |= DIRTY_WAKE_LOCKS;
            updatePowerStateLocked();
@@ -4394,9 +4404,16 @@ public final class PowerManagerService extends SystemService

    @GuardedBy("mLock")
    private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
        boolean disabled = false;
        if (wakeLock.isFrozenLocked()) {
            if (DEBUG_SPEW) {
                Slog.d(TAG, "Process frozen. Disabling the wakelock " + wakeLock.mTag);
            }
            disabled = true;
            return wakeLock.setDisabled(disabled);
        }
        if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                == PowerManager.PARTIAL_WAKE_LOCK) {
            boolean disabled = false;
            final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
            if (appid >= Process.FIRST_APPLICATION_UID) {
                // Cached inactive processes are never allowed to hold wake locks.
@@ -4429,7 +4446,6 @@ public final class PowerManagerService extends SystemService
            }
            return wakeLock.setDisabled(disabled);
        } else if (mDisableScreenWakeLocksWhileCached && isScreenLock(wakeLock)) {
            boolean disabled = false;
            final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
            final UidState state = wakeLock.mUidState;
            // Cached inactive processes are never allowed to hold wake locks.
@@ -5454,6 +5470,9 @@ public final class PowerManagerService extends SystemService
                case MSG_RELEASE_ALL_OVERRIDE_WAKE_LOCKS:
                    releaseAllOverrideWakeLocks(msg.arg1);
                    break;
                case MSG_PROCESS_FROZEN_STATE_CHANGED:
                    handleProcessFrozenStateChange(msg.obj, msg.arg1);
                    break;
            }

            return true;
@@ -5463,7 +5482,8 @@ public final class PowerManagerService extends SystemService
    /**
     * Represents a wake lock that has been acquired by an application.
     */
    /* package */ final class WakeLock implements IBinder.DeathRecipient {
    /* package */ final class WakeLock implements IBinder.DeathRecipient,
            IBinder.FrozenStateChangeCallback {
        public final IBinder mLock;
        public final int mDisplayId;
        public int mFlags;
@@ -5478,6 +5498,7 @@ public final class PowerManagerService extends SystemService
        public boolean mNotifiedAcquired;
        public boolean mNotifiedLong;
        public boolean mDisabled;
        private boolean mIsFrozen;
        public IWakeLockCallback mCallback;

        public WakeLock(IBinder lock, int displayId, int flags, String tag, String packageName,
@@ -5494,6 +5515,21 @@ 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();
        }

@@ -5503,6 +5539,23 @@ public final class PowerManagerService extends SystemService
            PowerManagerService.this.handleWakeLockDeath(this);
        }

        @Override
        public void onFrozenStateChanged(@androidx.annotation.NonNull IBinder who, int state) {
            if (mFeatureFlags.isDisableFrozenProcessWakelocksEnabled()) {
                Message msg = mHandler.obtainMessage(MSG_PROCESS_FROZEN_STATE_CHANGED,
                        state, /* arg2= */ 0, mLock);
                mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
            }
        }

        public boolean isFrozenLocked() {
            return mIsFrozen;
        }

        public void setFrozenLocked(int state) {
            mIsFrozen = (state == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
        }

        private void linkToDeath() {
            try {
                mLock.linkToDeath(this, 0);
@@ -5601,6 +5654,10 @@ public final class PowerManagerService extends SystemService
            }
            sb.append(" (uid=");
            sb.append(mOwnerUid);

            sb.append(" isFrozen=");
            sb.append(mIsFrozen);

            if (mOwnerPid != 0) {
                sb.append(" pid=");
                sb.append(mOwnerPid);
@@ -7269,6 +7326,26 @@ public final class PowerManagerService extends SystemService
        }
    }

    @VisibleForTesting
    void handleProcessFrozenStateChange(@NonNull Object lock, int state) {
        if (lock instanceof IBinder) {
            synchronized (mLock) {
                int index = findWakeLockIndexLocked((IBinder) lock);
                if (index < 0) {
                    if (DEBUG_SPEW) {
                        Slog.d(TAG, "No wakelock found whose frozen state is to be changed");
                    }
                    return;
                }
                WakeLock wakelock = mWakeLocks.get(index);
                wakelock.setFrozenLocked(state);
                updateWakeLockDisabledStatesLocked(Collections.singletonList(wakelock));
            }
        } else {
            Slog.wtf(TAG, "not an IBinder object: " + lock);
        }
    }

    @VisibleForTesting
    final class LocalService extends PowerManagerInternal {
        @Override
+51 −14
Original line number Diff line number Diff line
@@ -51,12 +51,14 @@ import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.annotation.NonNull;
import android.app.ActivityManagerInternal;
import android.attention.AttentionManagerInternal;
import android.compat.testing.PlatformCompatChangeRule;
@@ -145,7 +147,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;

@@ -292,7 +293,7 @@ public class PowerManagerServiceTest {

        mClock = new OffsettableClock.Stopped();
        mTestLooper = new TestLooper(mClock::now);
        DisplayInfo displayInfo = Mockito.mock(DisplayInfo.class);
        DisplayInfo displayInfo = mock(DisplayInfo.class);
        displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
        when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY))
                .thenReturn(displayInfo);
@@ -857,7 +858,7 @@ public class PowerManagerServiceTest {
                .isEqualTo(WAKEFULNESS_DOZING);

        // Wakeup the display from the non default power group
        DisplayInfo displayInfo = Mockito.mock(DisplayInfo.class);
        DisplayInfo displayInfo = mock(DisplayInfo.class);
        displayInfo.displayGroupId = nonDefaultPowerGroupId;
        when(mDisplayManagerInternalMock.getDisplayInfo(displayInNonDefaultGroup))
                .thenReturn(displayInfo);
@@ -2933,6 +2934,38 @@ public class PowerManagerServiceTest {
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    @RequiresFlagsEnabled({Flags.FLAG_DISABLE_FROZEN_PROCESS_WAKELOCKS})
    public void testDisableWakelocks_whenFrozen() {
        createService();
        startSystem();

        class RemoteBinder extends Binder {
            @Override
            public void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback) {

            }
        }
        RemoteBinder token = new RemoteBinder();
        WakeLock wakeLock = acquireWakeLock("frozenTestWakeLock",
                PowerManager.PARTIAL_WAKE_LOCK, token, Display.INVALID_DISPLAY);
        assertThat(wakeLock.mDisabled).isFalse();
        assertThat(wakeLock.isFrozenLocked()).isFalse();
        advanceTime(1000);

        // The process gets frozen, which disables the wakelock
        wakeLock.onFrozenStateChanged(token, 0);
        advanceTime(1000);
        assertThat(wakeLock.mDisabled).isTrue();
        assertThat(wakeLock.isFrozenLocked()).isTrue();

        // The process gets unfrozen, which enables the wakelock
        wakeLock.onFrozenStateChanged(token, 1);
        advanceTime(1000);
        assertThat(wakeLock.mDisabled).isFalse();
        assertThat(wakeLock.isFrozenLocked()).isFalse();
    }

    @Test
    public void testDisableWakelocksInLightDeviceIdle_FlagDisabled_FgApp() {
        mSetFlagsRule.disableFlags(FLAG_DISABLE_WAKELOCKS_IN_LIGHT_IDLE);
@@ -3059,6 +3092,10 @@ public class PowerManagerServiceTest {

    private WakeLock acquireWakeLock(String tag, int flags, int displayId) {
        IBinder token = new Binder();
        return acquireWakeLock(tag, flags, token, displayId);
    }

    private WakeLock acquireWakeLock(String tag, int flags, IBinder token, int displayId) {
        String packageName = "pkg.name";
        mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
                null /* workSource */, null /* historyTag */, displayId,
@@ -3081,8 +3118,8 @@ public class PowerManagerServiceTest {
        final String packageName = "pkg.name";
        final IBinder token = new Binder();
        final int flags = PowerManager.PARTIAL_WAKE_LOCK;
        final IWakeLockCallback callback = Mockito.mock(IWakeLockCallback.class);
        final IBinder callbackBinder = Mockito.mock(Binder.class);
        final IWakeLockCallback callback = mock(IWakeLockCallback.class);
        final IBinder callbackBinder = mock(Binder.class);
        when(callback.asBinder()).thenReturn(callbackBinder);
        mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
                null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, callback);
@@ -3106,8 +3143,8 @@ public class PowerManagerServiceTest {
        final String packageName = "pkg.name";
        final IBinder token = new Binder();
        int flags = PowerManager.PARTIAL_WAKE_LOCK;
        final IWakeLockCallback callback1 = Mockito.mock(IWakeLockCallback.class);
        final IBinder callbackBinder1 = Mockito.mock(Binder.class);
        final IWakeLockCallback callback1 = mock(IWakeLockCallback.class);
        final IBinder callbackBinder1 = mock(Binder.class);
        when(callback1.asBinder()).thenReturn(callbackBinder1);
        WorkSource oldWorksource = new WorkSource();
        oldWorksource.createWorkChain().addNode(1000, null);
@@ -3139,16 +3176,16 @@ public class PowerManagerServiceTest {
        final String packageName = "pkg.name";
        final IBinder token = new Binder();
        int flags = PowerManager.PARTIAL_WAKE_LOCK;
        final IWakeLockCallback callback1 = Mockito.mock(IWakeLockCallback.class);
        final IBinder callbackBinder1 = Mockito.mock(Binder.class);
        final IWakeLockCallback callback1 = mock(IWakeLockCallback.class);
        final IBinder callbackBinder1 = mock(Binder.class);
        when(callback1.asBinder()).thenReturn(callbackBinder1);
        mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
                null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, callback1);
        verify(mNotifierMock).onWakeLockAcquired(anyInt(), eq(tag), eq(packageName),
                anyInt(), anyInt(), any(), any(), same(callback1));

        final IWakeLockCallback callback2 = Mockito.mock(IWakeLockCallback.class);
        final IBinder callbackBinder2 = Mockito.mock(Binder.class);
        final IWakeLockCallback callback2 = mock(IWakeLockCallback.class);
        final IBinder callbackBinder2 = mock(Binder.class);
        when(callback2.asBinder()).thenReturn(callbackBinder2);
        mService.getBinderServiceInstance().updateWakeLockCallback(token, callback2);
        verify(mNotifierMock).onWakeLockChanging(anyInt(), eq(tag), eq(packageName),
@@ -3622,7 +3659,7 @@ public class PowerManagerServiceTest {
        createService();
        startSystem();

        final IScreenTimeoutPolicyListener listener = Mockito.mock(
        final IScreenTimeoutPolicyListener listener = mock(
                IScreenTimeoutPolicyListener.class);
        mService.getBinderServiceInstance().addScreenTimeoutPolicyListener(
                Display.DEFAULT_DISPLAY_GROUP, listener);
@@ -3651,7 +3688,7 @@ public class PowerManagerServiceTest {
        createService();
        startSystem();

        final IScreenTimeoutPolicyListener listener = Mockito.mock(
        final IScreenTimeoutPolicyListener listener = mock(
                IScreenTimeoutPolicyListener.class);
        mService.getBinderServiceInstance().addScreenTimeoutPolicyListener(
                Display.DEFAULT_DISPLAY, listener);
@@ -3704,7 +3741,7 @@ public class PowerManagerServiceTest {
        acquireWakeLock("screenBright", PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                Display.DEFAULT_DISPLAY);

        final IScreenTimeoutPolicyListener listener = Mockito.mock(
        final IScreenTimeoutPolicyListener listener = mock(
                IScreenTimeoutPolicyListener.class);
        mService.getBinderServiceInstance().addScreenTimeoutPolicyListener(
                Display.DEFAULT_DISPLAY_GROUP, listener);