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

Commit b3691fab authored by Philip Junker's avatar Philip Junker Committed by Android Build Coastguard Worker
Browse files

Disable screen wake locks for cached apps

Bug: 289464589
Test: atest PowerManagerServiceTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4138a2e2e683dbdf5c61f8e7d68a04e8ec5e2800)
Merged-In: I1cf38ada2456c1cc1f367fad58ce95948d1b3a81
Change-Id: I1cf38ada2456c1cc1f367fad58ce95948d1b3a81
parent 9112deec
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -1762,6 +1762,15 @@ public final class DisplayManager {
         * 123,1,critical,0.8,default;123,1,moderate,0.6,id_2;456,2,moderate,0.9,critical,0.7
         */
        String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data";

        /**
         * Key for disabling screen wake locks while apps are in cached state.
         * Read value via {@link android.provider.DeviceConfig#getBoolean(String, String, boolean)}
         * with {@link android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER} as the namespace.
         * @hide
         */
        String KEY_DISABLE_SCREEN_WAKE_LOCKS_WHILE_CACHED =
                "disable_screen_wake_locks_while_cached";
    }

    /**
+50 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.display.feature;

import android.hardware.display.DisplayManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;

import java.util.concurrent.Executor;

/**
 * Helper class to access all DeviceConfig features for display_manager namespace
 *
 **/
public class DeviceConfigParameterProvider {

    private static final String TAG = "DisplayFeatureProvider";

    private final DeviceConfigInterface mDeviceConfig;

    public DeviceConfigParameterProvider(DeviceConfigInterface deviceConfig) {
        mDeviceConfig = deviceConfig;
    }

    public boolean isDisableScreenWakeLocksWhileCachedFeatureEnabled() {
        return mDeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                DisplayManager.DeviceConfig.KEY_DISABLE_SCREEN_WAKE_LOCKS_WHILE_CACHED, true);
    }

    /** add property change listener to DeviceConfig */
    public void addOnPropertiesChangedListener(Executor executor,
            DeviceConfig.OnPropertiesChangedListener listener) {
        mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                executor, listener);
    }
}
+46 −6
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
import android.provider.DeviceConfigInterface;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
@@ -128,6 +129,7 @@ import com.android.server.UiThread;
import com.android.server.UserspaceRebootLogger;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
import com.android.server.policy.WindowManagerPolicy;
@@ -323,6 +325,9 @@ public final class PowerManagerService extends SystemService
    private final Injector mInjector;
    private final PermissionCheckerWrapper mPermissionCheckerWrapper;
    private final PowerPropertiesWrapper mPowerPropertiesWrapper;
    private final DeviceConfigParameterProvider mDeviceConfigProvider;

    private boolean mDisableScreenWakeLocksWhileCached;

    private LightsManager mLightsManager;
    private BatteryManagerInternal mBatteryManagerInternal;
@@ -1065,6 +1070,10 @@ public final class PowerManagerService extends SystemService
                }
            };
        }

        DeviceConfigParameterProvider createDeviceConfigParameterProvider() {
            return new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
        }
    }

    /** Interface for checking an app op permission */
@@ -1161,6 +1170,7 @@ public final class PowerManagerService extends SystemService
                mInjector.createInattentiveSleepWarningController();
        mPermissionCheckerWrapper = mInjector.createPermissionCheckerWrapper();
        mPowerPropertiesWrapper = mInjector.createPowerPropertiesWrapper();
        mDeviceConfigProvider = mInjector.createDeviceConfigParameterProvider();

        mPowerGroupWakefulnessChangeListener = new PowerGroupWakefulnessChangeListener();

@@ -1346,6 +1356,14 @@ public final class PowerManagerService extends SystemService

            mLightsManager = getLocalService(LightsManager.class);
            mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
            updateDeviceConfigLocked();
            mDeviceConfigProvider.addOnPropertiesChangedListener(BackgroundThread.getExecutor(),
                    properties -> {
                        synchronized (mLock) {
                            updateDeviceConfigLocked();
                            updateWakeLockDisabledStatesLocked();
                        }
                    });

            // Initialize display power management.
            mDisplayManagerInternal.initPowerManagement(
@@ -1545,6 +1563,12 @@ public final class PowerManagerService extends SystemService
        updatePowerStateLocked();
    }

    @GuardedBy("mLock")
    private void updateDeviceConfigLocked() {
        mDisableScreenWakeLocksWhileCached = mDeviceConfigProvider
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
    }

    @RequiresPermission(value = android.Manifest.permission.TURN_SCREEN_ON, conditional = true)
    private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag,
            String packageName, WorkSource ws, String historyTag, int uid, int pid,
@@ -2760,13 +2784,13 @@ public final class PowerManagerService extends SystemService
    /** Get wake lock summary flags that correspond to the given wake lock. */
    @SuppressWarnings("deprecation")
    private int getWakeLockSummaryFlags(WakeLock wakeLock) {
        if (wakeLock.mDisabled) {
            // We only respect this if the wake lock is not disabled.
            return 0;
        }
        switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
            case PowerManager.PARTIAL_WAKE_LOCK:
                if (!wakeLock.mDisabled) {
                    // We only respect this if the wake lock is not disabled.
                return WAKE_LOCK_CPU;
                }
                break;
            case PowerManager.FULL_WAKE_LOCK:
                return WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
            case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
@@ -4151,7 +4175,7 @@ public final class PowerManagerService extends SystemService
        for (int i = 0; i < numWakeLocks; i++) {
            final WakeLock wakeLock = mWakeLocks.get(i);
            if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                    == PowerManager.PARTIAL_WAKE_LOCK) {
                    == PowerManager.PARTIAL_WAKE_LOCK || isScreenLock(wakeLock)) {
                if (setWakeLockDisabledStateLocked(wakeLock)) {
                    changed = true;
                    if (wakeLock.mDisabled) {
@@ -4205,6 +4229,22 @@ 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.
            if (mConstants.NO_CACHED_WAKE_LOCKS
                    && appid >= Process.FIRST_APPLICATION_UID
                    && !state.mActive
                    && state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
                    && state.mProcState >= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
                if (DEBUG_SPEW) {
                    Slog.d(TAG, "disabling full wakelock " + wakeLock);
                }
                disabled = true;
            }
            return wakeLock.setDisabled(disabled);
        }
        return false;
    }
+203 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.server.power;

import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
import static android.os.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -78,6 +80,7 @@ import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.UserHandle;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.sysprop.PowerProperties;
@@ -91,6 +94,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver;
@@ -159,6 +163,7 @@ public class PowerManagerServiceTest {
    @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
    @Mock private PowerManagerService.PermissionCheckerWrapper mPermissionCheckerWrapperMock;
    @Mock private PowerManagerService.PowerPropertiesWrapper mPowerPropertiesWrapper;
    @Mock private DeviceConfigParameterProvider mDeviceParameterProvider;

    @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();

@@ -340,6 +345,11 @@ public class PowerManagerServiceTest {
            PowerManagerService.PowerPropertiesWrapper createPowerPropertiesWrapper() {
                return mPowerPropertiesWrapper;
            }

            @Override
            DeviceConfigParameterProvider createDeviceConfigParameterProvider() {
                return mDeviceParameterProvider;
            }
        });
        return mService;
    }
@@ -2680,4 +2690,197 @@ public class PowerManagerServiceTest {
        verify(mNotifierMock, never()).onUserActivity(anyInt(),  anyInt(), anyInt());
    }

    @Test
    public void testFeatureEnabledProcStateUncachedToCached_fullWakeLockDisabled() {
        doReturn(true).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
        setUncachedUidProcState(wakeLock.mOwnerUid);

        setCachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isTrue();
    }

    @Test
    public void testFeatureDisabledProcStateUncachedToCached_fullWakeLockEnabled() {
        doReturn(false).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
        setUncachedUidProcState(wakeLock.mOwnerUid);

        setCachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureEnabledProcStateUncachedToCached_screenBrightWakeLockDisabled() {
        doReturn(true).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
                PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
        setUncachedUidProcState(wakeLock.mOwnerUid);

        setCachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isTrue();
    }

    @Test
    public void testFeatureDisabledProcStateUncachedToCached_screenBrightWakeLockEnabled() {
        doReturn(false).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
                PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
        setUncachedUidProcState(wakeLock.mOwnerUid);

        setCachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureEnabledProcStateUncachedToCached_screenDimWakeLockDisabled() {
        doReturn(true).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
                PowerManager.SCREEN_DIM_WAKE_LOCK);
        setUncachedUidProcState(wakeLock.mOwnerUid);

        setCachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isTrue();
    }

    @Test
    public void testFeatureDisabledProcStateUncachedToCached_screenDimWakeLockEnabled() {
        doReturn(false).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
                PowerManager.SCREEN_DIM_WAKE_LOCK);
        setUncachedUidProcState(wakeLock.mOwnerUid);

        setCachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureEnabledProcStateCachedToUncached_fullWakeLockEnabled() {
        doReturn(true).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
        setCachedUidProcState(wakeLock.mOwnerUid);

        setUncachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureDisabledProcStateCachedToUncached_fullWakeLockEnabled() {
        doReturn(false).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
        setCachedUidProcState(wakeLock.mOwnerUid);

        setUncachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureEnabledProcStateCachedToUncached_screenBrightWakeLockEnabled() {
        doReturn(true).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
                PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
        setCachedUidProcState(wakeLock.mOwnerUid);

        setUncachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureDisabledProcStateCachedToUncached_screenBrightWakeLockEnabled() {
        doReturn(false).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
                PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
        setCachedUidProcState(wakeLock.mOwnerUid);

        setUncachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureEnabledProcStateCachedToUncached_screenDimWakeLockEnabled() {
        doReturn(true).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
                PowerManager.SCREEN_DIM_WAKE_LOCK);
        setCachedUidProcState(wakeLock.mOwnerUid);

        setUncachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureDisabledProcStateCachedToUncached_screenDimWakeLockEnabled() {
        doReturn(false).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        createService();
        startSystem();
        WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
                PowerManager.SCREEN_DIM_WAKE_LOCK);
        setCachedUidProcState(wakeLock.mOwnerUid);

        setUncachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    @Test
    public void testFeatureDynamicallyDisabledProcStateUncachedToCached_fullWakeLockEnabled() {
        doReturn(true).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener> listenerCaptor =
                ArgumentCaptor.forClass(DeviceConfig.OnPropertiesChangedListener.class);
        createService();
        startSystem();
        verify(mDeviceParameterProvider, times(1))
                .addOnPropertiesChangedListener(any(), listenerCaptor.capture());
        WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
        setUncachedUidProcState(wakeLock.mOwnerUid);
        // dynamically disable the feature
        doReturn(false).when(mDeviceParameterProvider)
                .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
        listenerCaptor.getValue().onPropertiesChanged(
                new DeviceConfig.Properties("ignored_namespace", null));

        setUncachedUidProcState(wakeLock.mOwnerUid);
        assertThat(wakeLock.mDisabled).isFalse();
    }

    private void setCachedUidProcState(int uid) {
        mService.updateUidProcStateInternal(uid, PROCESS_STATE_TOP_SLEEPING);
    }

    private void setUncachedUidProcState(int uid) {
        mService.updateUidProcStateInternal(uid, PROCESS_STATE_RECEIVER);
    }
}