jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.server.power; |
| 18 | |
Makoto Onuki | 66a7812 | 2017-11-14 15:03:21 -0800 | [diff] [blame] | 19 | import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP; |
| 20 | import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; |
| 21 | |
| 22 | import static com.google.common.truth.Truth.assertThat; |
| 23 | |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 24 | import static org.mockito.ArgumentMatchers.any; |
| 25 | import static org.mockito.ArgumentMatchers.anyInt; |
| 26 | import static org.mockito.ArgumentMatchers.anyString; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 27 | import static org.mockito.ArgumentMatchers.eq; |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 28 | import static org.mockito.Mockito.doAnswer; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 29 | import static org.mockito.Mockito.mock; |
Makoto Onuki | 66a7812 | 2017-11-14 15:03:21 -0800 | [diff] [blame] | 30 | import static org.mockito.Mockito.when; |
| 31 | |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 32 | import android.app.ActivityManagerInternal; |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 33 | import android.attention.AttentionManagerInternal; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 34 | import android.content.Context; |
| 35 | import android.hardware.display.DisplayManagerInternal; |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 36 | import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 37 | import android.os.BatteryManagerInternal; |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 38 | import android.os.Binder; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 39 | import android.os.Looper; |
Salvador Martinez | a6f7b25 | 2017-04-10 10:46:15 -0700 | [diff] [blame] | 40 | import android.os.PowerManager; |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 41 | import android.os.PowerSaveState; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 42 | import android.os.SystemClock; |
Mark Salyzyn | e65c0c6 | 2017-08-15 07:53:47 -0700 | [diff] [blame] | 43 | import android.os.SystemProperties; |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 44 | import android.test.AndroidTestCase; |
Alex Kershaw | 2418ea9 | 2018-10-19 17:17:49 +0100 | [diff] [blame] | 45 | import android.test.suitebuilder.annotation.MediumTest; |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 46 | import android.test.suitebuilder.annotation.SmallTest; |
Makoto Onuki | 66a7812 | 2017-11-14 15:03:21 -0800 | [diff] [blame] | 47 | |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 48 | import com.android.internal.app.IBatteryStats; |
| 49 | import com.android.server.LocalServices; |
| 50 | import com.android.server.SystemService; |
| 51 | import com.android.server.lights.LightsManager; |
| 52 | import com.android.server.policy.WindowManagerPolicy; |
| 53 | import com.android.server.power.PowerManagerService.Injector; |
| 54 | import com.android.server.power.PowerManagerService.NativeWrapper; |
Kweku Adams | 7fb72a4 | 2019-01-08 16:08:49 -0800 | [diff] [blame] | 55 | import com.android.server.power.batterysaver.BatterySaverPolicy; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 56 | import com.android.server.power.batterysaver.BatterySavingStats; |
Makoto Onuki | 66a7812 | 2017-11-14 15:03:21 -0800 | [diff] [blame] | 57 | |
Salvador Martinez | a6f7b25 | 2017-04-10 10:46:15 -0700 | [diff] [blame] | 58 | import org.junit.Rule; |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 59 | import org.mockito.Mock; |
| 60 | import org.mockito.MockitoAnnotations; |
| 61 | |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 62 | import java.util.HashMap; |
| 63 | import java.util.Map; |
| 64 | |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 65 | /** |
| 66 | * Tests for {@link com.android.server.power.PowerManagerService} |
| 67 | */ |
| 68 | public class PowerManagerServiceTest extends AndroidTestCase { |
| 69 | private static final float PRECISION = 0.001f; |
| 70 | private static final float BRIGHTNESS_FACTOR = 0.7f; |
| 71 | private static final boolean BATTERY_SAVER_ENABLED = true; |
Mark Salyzyn | e65c0c6 | 2017-08-15 07:53:47 -0700 | [diff] [blame] | 72 | private static final String TEST_LAST_REBOOT_PROPERTY = "test.sys.boot.reason"; |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 73 | |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 74 | private @Mock BatterySaverPolicy mBatterySaverPolicyMock; |
| 75 | private @Mock LightsManager mLightsManagerMock; |
| 76 | private @Mock DisplayManagerInternal mDisplayManagerInternalMock; |
| 77 | private @Mock BatteryManagerInternal mBatteryManagerInternalMock; |
| 78 | private @Mock ActivityManagerInternal mActivityManagerInternalMock; |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 79 | private @Mock AttentionManagerInternal mAttentionManagerInternalMock; |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 80 | private @Mock PowerManagerService.NativeWrapper mNativeWrapperMock; |
| 81 | private @Mock Notifier mNotifierMock; |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 82 | private PowerManagerService mService; |
| 83 | private PowerSaveState mPowerSaveState; |
| 84 | private DisplayPowerRequest mDisplayPowerRequest; |
Salvador Martinez | a6f7b25 | 2017-04-10 10:46:15 -0700 | [diff] [blame] | 85 | |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 86 | |
| 87 | |
Salvador Martinez | a6f7b25 | 2017-04-10 10:46:15 -0700 | [diff] [blame] | 88 | @Rule |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 89 | public void setUp() throws Exception { |
| 90 | super.setUp(); |
| 91 | MockitoAnnotations.initMocks(this); |
| 92 | |
| 93 | mPowerSaveState = new PowerSaveState.Builder() |
| 94 | .setBatterySaverEnabled(BATTERY_SAVER_ENABLED) |
| 95 | .setBrightnessFactor(BRIGHTNESS_FACTOR) |
| 96 | .build(); |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 97 | when(mBatterySaverPolicyMock.getBatterySaverPolicy( |
Kweku Adams | 9f488e2 | 2019-01-14 16:25:08 -0800 | [diff] [blame] | 98 | eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS))) |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 99 | .thenReturn(mPowerSaveState); |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 100 | |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 101 | mDisplayPowerRequest = new DisplayPowerRequest(); |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 102 | addLocalServiceMock(LightsManager.class, mLightsManagerMock); |
| 103 | addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock); |
| 104 | addLocalServiceMock(BatteryManagerInternal.class, mBatteryManagerInternalMock); |
| 105 | addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock); |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 106 | addLocalServiceMock(AttentionManagerInternal.class, mAttentionManagerInternalMock); |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 107 | |
| 108 | mService = new PowerManagerService(getContext(), new Injector() { |
| 109 | Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, |
| 110 | SuspendBlocker suspendBlocker, WindowManagerPolicy policy) { |
| 111 | return mNotifierMock; |
| 112 | } |
| 113 | |
| 114 | SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) { |
| 115 | return mock(SuspendBlocker.class); |
| 116 | } |
| 117 | |
| 118 | BatterySaverPolicy createBatterySaverPolicy( |
| 119 | Object lock, Context context, BatterySavingStats batterySavingStats) { |
| 120 | return mBatterySaverPolicyMock; |
| 121 | } |
| 122 | |
| 123 | NativeWrapper createNativeWrapper() { |
| 124 | return mNativeWrapperMock; |
| 125 | } |
| 126 | }); |
| 127 | } |
| 128 | |
| 129 | @Override |
| 130 | public void tearDown() throws Exception { |
| 131 | LocalServices.removeServiceForTest(LightsManager.class); |
| 132 | LocalServices.removeServiceForTest(DisplayManagerInternal.class); |
| 133 | LocalServices.removeServiceForTest(BatteryManagerInternal.class); |
| 134 | LocalServices.removeServiceForTest(ActivityManagerInternal.class); |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * Creates a mock and registers it to {@link LocalServices}. |
| 139 | */ |
| 140 | private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { |
| 141 | LocalServices.removeServiceForTest(clazz); |
| 142 | LocalServices.addService(clazz, mock); |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | @SmallTest |
| 146 | public void testUpdatePowerScreenPolicy_UpdateDisplayPowerRequest() { |
| 147 | mService.updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest); |
| 148 | assertThat(mDisplayPowerRequest.lowPowerMode).isEqualTo(BATTERY_SAVER_ENABLED); |
| 149 | assertThat(mDisplayPowerRequest.screenLowPowerBrightnessFactor) |
| 150 | .isWithin(PRECISION).of(BRIGHTNESS_FACTOR); |
| 151 | } |
Salvador Martinez | a6f7b25 | 2017-04-10 10:46:15 -0700 | [diff] [blame] | 152 | |
| 153 | @SmallTest |
| 154 | public void testGetLastShutdownReasonInternal() { |
Mark Salyzyn | e65c0c6 | 2017-08-15 07:53:47 -0700 | [diff] [blame] | 155 | SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "shutdown,thermal"); |
| 156 | int reason = mService.getLastShutdownReasonInternal(TEST_LAST_REBOOT_PROPERTY); |
| 157 | SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, ""); |
Salvador Martinez | a6f7b25 | 2017-04-10 10:46:15 -0700 | [diff] [blame] | 158 | assertThat(reason).isEqualTo(PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN); |
| 159 | } |
Santos Cordon | 21e9f2b | 2017-09-13 11:59:39 -0700 | [diff] [blame] | 160 | |
| 161 | @SmallTest |
| 162 | public void testGetDesiredScreenPolicy_WithVR() throws Exception { |
| 163 | // Brighten up the screen |
Michael Wright | e300104 | 2019-02-05 00:13:14 +0000 | [diff] [blame] | 164 | mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0); |
Santos Cordon | 21e9f2b | 2017-09-13 11:59:39 -0700 | [diff] [blame] | 165 | assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo( |
| 166 | DisplayPowerRequest.POLICY_BRIGHT); |
| 167 | |
| 168 | // Move to VR |
| 169 | mService.setVrModeEnabled(true); |
| 170 | assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo( |
| 171 | DisplayPowerRequest.POLICY_VR); |
| 172 | |
| 173 | // Then take a nap |
Michael Wright | e300104 | 2019-02-05 00:13:14 +0000 | [diff] [blame] | 174 | mService.setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, |
| 175 | 0); |
Santos Cordon | 21e9f2b | 2017-09-13 11:59:39 -0700 | [diff] [blame] | 176 | assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo( |
| 177 | DisplayPowerRequest.POLICY_OFF); |
| 178 | |
| 179 | // Wake up to VR |
Michael Wright | e300104 | 2019-02-05 00:13:14 +0000 | [diff] [blame] | 180 | mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0); |
Santos Cordon | 21e9f2b | 2017-09-13 11:59:39 -0700 | [diff] [blame] | 181 | assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo( |
| 182 | DisplayPowerRequest.POLICY_VR); |
| 183 | |
| 184 | // And back to normal |
| 185 | mService.setVrModeEnabled(false); |
| 186 | assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo( |
| 187 | DisplayPowerRequest.POLICY_BRIGHT); |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 188 | } |
Santos Cordon | 21e9f2b | 2017-09-13 11:59:39 -0700 | [diff] [blame] | 189 | |
Santos Cordon | 64a6e61 | 2018-08-22 19:27:04 +0100 | [diff] [blame] | 190 | @SmallTest |
| 191 | public void testWakefulnessAwake_InitialValue() throws Exception { |
| 192 | assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); |
| 193 | } |
| 194 | |
| 195 | @SmallTest |
| 196 | public void testWakefulnessSleep_NoDozeSleepFlag() throws Exception { |
| 197 | // Start with AWAKE state |
| 198 | assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); |
| 199 | |
| 200 | mService.systemReady(null); |
| 201 | mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| 202 | |
| 203 | // Take a nap with a flag. |
| 204 | mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(), |
| 205 | PowerManager.GO_TO_SLEEP_REASON_APPLICATION, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); |
| 206 | |
| 207 | assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); |
Santos Cordon | 21e9f2b | 2017-09-13 11:59:39 -0700 | [diff] [blame] | 208 | } |
Alex Kershaw | 2418ea9 | 2018-10-19 17:17:49 +0100 | [diff] [blame] | 209 | |
| 210 | @MediumTest |
| 211 | public void testWasDeviceIdleFor_true() { |
| 212 | int interval = 1000; |
| 213 | mService.onUserActivity(); |
| 214 | SystemClock.sleep(interval); |
| 215 | assertThat(mService.wasDeviceIdleForInternal(interval)).isTrue(); |
| 216 | } |
| 217 | |
| 218 | @SmallTest |
| 219 | public void testWasDeviceIdleFor_false() { |
| 220 | int interval = 1000; |
| 221 | mService.onUserActivity(); |
| 222 | assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse(); |
| 223 | } |
Santos Cordon | 12f92eb | 2019-02-01 21:28:47 +0000 | [diff] [blame] | 224 | |
| 225 | @SmallTest |
| 226 | public void testForceSuspend_putsDeviceToSleep() { |
| 227 | mService.systemReady(null); |
| 228 | mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| 229 | |
| 230 | // Verify that we start awake |
| 231 | assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); |
| 232 | |
| 233 | // Grab the wakefulness value when PowerManager finally calls into the |
| 234 | // native component to actually perform the suspend. |
| 235 | when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> { |
| 236 | assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); |
| 237 | return true; |
| 238 | }); |
| 239 | |
| 240 | boolean retval = mService.getBinderServiceInstance().forceSuspend(); |
| 241 | assertThat(retval).isTrue(); |
| 242 | |
| 243 | // Still asleep when the function returns. |
| 244 | assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); |
| 245 | } |
| 246 | |
| 247 | @SmallTest |
| 248 | public void testForceSuspend_pakeLocksDisabled() { |
| 249 | final String tag = "TestWakelockTag_098213"; |
| 250 | final int flags = PowerManager.PARTIAL_WAKE_LOCK; |
| 251 | final String pkg = getContext().getOpPackageName(); |
| 252 | |
| 253 | // Set up the Notification mock to keep track of the wakelocks that are currently |
| 254 | // active or disabled. We'll use this to verify that wakelocks are disabled when |
| 255 | // they should be. |
| 256 | final Map<String, Integer> wakelockMap = new HashMap<>(1); |
| 257 | doAnswer(inv -> { |
| 258 | wakelockMap.put((String) inv.getArguments()[1], (int) inv.getArguments()[0]); |
| 259 | return null; |
| 260 | }).when(mNotifierMock).onWakeLockAcquired(anyInt(), anyString(), anyString(), anyInt(), |
| 261 | anyInt(), any(), any()); |
| 262 | doAnswer(inv -> { |
| 263 | wakelockMap.remove((String) inv.getArguments()[1]); |
| 264 | return null; |
| 265 | }).when(mNotifierMock).onWakeLockReleased(anyInt(), anyString(), anyString(), anyInt(), |
| 266 | anyInt(), any(), any()); |
| 267 | |
| 268 | // |
| 269 | // TEST STARTS HERE |
| 270 | // |
| 271 | mService.systemReady(null); |
| 272 | mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); |
| 273 | |
| 274 | // Verify that we start awake |
| 275 | assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); |
| 276 | |
| 277 | // Create a wakelock |
| 278 | mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg, |
| 279 | null /* workSource */, null /* historyTag */); |
| 280 | assertThat(wakelockMap.get(tag)).isEqualTo(flags); // Verify wakelock is active. |
| 281 | |
| 282 | // Confirm that the wakelocks have been disabled when the forceSuspend is in flight. |
| 283 | when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> { |
| 284 | // Verify that the wakelock is disabled by the time we get to the native force |
| 285 | // suspend call. |
| 286 | assertThat(wakelockMap.containsKey(tag)).isFalse(); |
| 287 | return true; |
| 288 | }); |
| 289 | |
| 290 | assertThat(mService.getBinderServiceInstance().forceSuspend()).isTrue(); |
| 291 | assertThat(wakelockMap.get(tag)).isEqualTo(flags); |
| 292 | |
| 293 | } |
| 294 | |
| 295 | @SmallTest |
| 296 | public void testForceSuspend_forceSuspendFailurePropogated() { |
| 297 | when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false); |
| 298 | assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse(); |
| 299 | } |
jackqdyulei | 92681e8 | 2017-02-28 11:26:28 -0800 | [diff] [blame] | 300 | } |