Disable screen wake locks for cached apps

Bug: 289464589
Test: atest PowerManagerServiceTest
Change-Id: I1cf38ada2456c1cc1f367fad58ce95948d1b3a81
Merged-In: I1cf38ada2456c1cc1f367fad58ce95948d1b3a81
This commit is contained in:
Philip Junker
2023-07-12 16:36:43 +02:00
parent 4c39ad7c8f
commit 4138a2e2e6
4 changed files with 308 additions and 6 deletions

View File

@@ -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 * 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"; 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";
} }
/** /**

View File

@@ -0,0 +1,50 @@
/*
* 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);
}
}

View File

@@ -92,6 +92,7 @@ import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.os.WorkSource; import android.os.WorkSource;
import android.os.WorkSource.WorkChain; import android.os.WorkSource.WorkChain;
import android.provider.DeviceConfigInterface;
import android.provider.Settings; import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException; import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal; import android.service.dreams.DreamManagerInternal;
@@ -128,6 +129,7 @@ import com.android.server.UiThread;
import com.android.server.UserspaceRebootLogger; import com.android.server.UserspaceRebootLogger;
import com.android.server.Watchdog; import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService; import com.android.server.am.BatteryStatsService;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager; import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight; import com.android.server.lights.LogicalLight;
import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy;
@@ -323,6 +325,9 @@ public final class PowerManagerService extends SystemService
private final Injector mInjector; private final Injector mInjector;
private final PermissionCheckerWrapper mPermissionCheckerWrapper; private final PermissionCheckerWrapper mPermissionCheckerWrapper;
private final PowerPropertiesWrapper mPowerPropertiesWrapper; private final PowerPropertiesWrapper mPowerPropertiesWrapper;
private final DeviceConfigParameterProvider mDeviceConfigProvider;
private boolean mDisableScreenWakeLocksWhileCached;
private LightsManager mLightsManager; private LightsManager mLightsManager;
private BatteryManagerInternal mBatteryManagerInternal; 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 */ /** Interface for checking an app op permission */
@@ -1161,6 +1170,7 @@ public final class PowerManagerService extends SystemService
mInjector.createInattentiveSleepWarningController(); mInjector.createInattentiveSleepWarningController();
mPermissionCheckerWrapper = mInjector.createPermissionCheckerWrapper(); mPermissionCheckerWrapper = mInjector.createPermissionCheckerWrapper();
mPowerPropertiesWrapper = mInjector.createPowerPropertiesWrapper(); mPowerPropertiesWrapper = mInjector.createPowerPropertiesWrapper();
mDeviceConfigProvider = mInjector.createDeviceConfigParameterProvider();
mPowerGroupWakefulnessChangeListener = new PowerGroupWakefulnessChangeListener(); mPowerGroupWakefulnessChangeListener = new PowerGroupWakefulnessChangeListener();
@@ -1346,6 +1356,14 @@ public final class PowerManagerService extends SystemService
mLightsManager = getLocalService(LightsManager.class); mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION); mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
updateDeviceConfigLocked();
mDeviceConfigProvider.addOnPropertiesChangedListener(BackgroundThread.getExecutor(),
properties -> {
synchronized (mLock) {
updateDeviceConfigLocked();
updateWakeLockDisabledStatesLocked();
}
});
// Initialize display power management. // Initialize display power management.
mDisplayManagerInternal.initPowerManagement( mDisplayManagerInternal.initPowerManagement(
@@ -1545,6 +1563,12 @@ public final class PowerManagerService extends SystemService
updatePowerStateLocked(); updatePowerStateLocked();
} }
@GuardedBy("mLock")
private void updateDeviceConfigLocked() {
mDisableScreenWakeLocksWhileCached = mDeviceConfigProvider
.isDisableScreenWakeLocksWhileCachedFeatureEnabled();
}
@RequiresPermission(value = android.Manifest.permission.TURN_SCREEN_ON, conditional = true) @RequiresPermission(value = android.Manifest.permission.TURN_SCREEN_ON, conditional = true)
private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag, private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag,
String packageName, WorkSource ws, String historyTag, int uid, int pid, 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. */ /** Get wake lock summary flags that correspond to the given wake lock. */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private int getWakeLockSummaryFlags(WakeLock wakeLock) { 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) { switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK: case PowerManager.PARTIAL_WAKE_LOCK:
if (!wakeLock.mDisabled) {
// We only respect this if the wake lock is not disabled.
return WAKE_LOCK_CPU; return WAKE_LOCK_CPU;
}
break;
case PowerManager.FULL_WAKE_LOCK: case PowerManager.FULL_WAKE_LOCK:
return WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT; return WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
@@ -4151,7 +4175,7 @@ public final class PowerManagerService extends SystemService
for (int i = 0; i < numWakeLocks; i++) { for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i); final WakeLock wakeLock = mWakeLocks.get(i);
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) { == PowerManager.PARTIAL_WAKE_LOCK || isScreenLock(wakeLock)) {
if (setWakeLockDisabledStateLocked(wakeLock)) { if (setWakeLockDisabledStateLocked(wakeLock)) {
changed = true; changed = true;
if (wakeLock.mDisabled) { if (wakeLock.mDisabled) {
@@ -4205,6 +4229,22 @@ public final class PowerManagerService extends SystemService
} }
} }
return wakeLock.setDisabled(disabled); 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; return false;
} }

View File

@@ -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_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; 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.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP; import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -78,6 +80,7 @@ import android.os.PowerManagerInternal;
import android.os.PowerSaveState; import android.os.PowerSaveState;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.test.TestLooper; import android.os.test.TestLooper;
import android.provider.DeviceConfig;
import android.provider.Settings; import android.provider.Settings;
import android.service.dreams.DreamManagerInternal; import android.service.dreams.DreamManagerInternal;
import android.sysprop.PowerProperties; import android.sysprop.PowerProperties;
@@ -91,6 +94,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices; import com.android.server.LocalServices;
import com.android.server.SystemService; import com.android.server.SystemService;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager; import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver; import com.android.server.power.PowerManagerService.BatteryReceiver;
@@ -159,6 +163,7 @@ public class PowerManagerServiceTest {
@Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock; @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
@Mock private PowerManagerService.PermissionCheckerWrapper mPermissionCheckerWrapperMock; @Mock private PowerManagerService.PermissionCheckerWrapper mPermissionCheckerWrapperMock;
@Mock private PowerManagerService.PowerPropertiesWrapper mPowerPropertiesWrapper; @Mock private PowerManagerService.PowerPropertiesWrapper mPowerPropertiesWrapper;
@Mock private DeviceConfigParameterProvider mDeviceParameterProvider;
@Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -340,6 +345,11 @@ public class PowerManagerServiceTest {
PowerManagerService.PowerPropertiesWrapper createPowerPropertiesWrapper() { PowerManagerService.PowerPropertiesWrapper createPowerPropertiesWrapper() {
return mPowerPropertiesWrapper; return mPowerPropertiesWrapper;
} }
@Override
DeviceConfigParameterProvider createDeviceConfigParameterProvider() {
return mDeviceParameterProvider;
}
}); });
return mService; return mService;
} }
@@ -2680,4 +2690,197 @@ public class PowerManagerServiceTest {
verify(mNotifierMock, never()).onUserActivity(anyInt(), anyInt(), anyInt()); 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);
}
} }