1 /* 2 * Copyright (C) 2020 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.car.hardware.power; 18 19 import static android.car.hardware.power.PowerComponent.AUDIO; 20 import static android.car.hardware.power.PowerComponent.BLUETOOTH; 21 import static android.car.hardware.power.PowerComponent.CELLULAR; 22 import static android.car.hardware.power.PowerComponent.CPU; 23 import static android.car.hardware.power.PowerComponent.DISPLAY; 24 import static android.car.hardware.power.PowerComponent.ETHERNET; 25 import static android.car.hardware.power.PowerComponent.INPUT; 26 import static android.car.hardware.power.PowerComponent.LOCATION; 27 import static android.car.hardware.power.PowerComponent.MEDIA; 28 import static android.car.hardware.power.PowerComponent.MICROPHONE; 29 import static android.car.hardware.power.PowerComponent.NFC; 30 import static android.car.hardware.power.PowerComponent.PROJECTION; 31 import static android.car.hardware.power.PowerComponent.TRUSTED_DEVICE_DETECTION; 32 import static android.car.hardware.power.PowerComponent.VISUAL_INTERACTION; 33 import static android.car.hardware.power.PowerComponent.VOICE_INTERACTION; 34 import static android.car.hardware.power.PowerComponent.WIFI; 35 36 import static com.android.car.test.power.CarPowerPolicyUtil.assertPolicyIdentical; 37 38 import static com.google.common.truth.Truth.assertThat; 39 import static com.google.common.truth.Truth.assertWithMessage; 40 41 import static org.junit.Assert.assertThrows; 42 import static org.mockito.Mockito.doReturn; 43 import static org.mockito.Mockito.when; 44 45 import android.annotation.NonNull; 46 import android.automotive.powerpolicy.internal.ICarPowerPolicyDelegate; 47 import android.car.Car; 48 import android.car.feature.Flags; 49 import android.car.hardware.power.CarPowerManager; 50 import android.car.hardware.power.CarPowerPolicy; 51 import android.car.hardware.power.CarPowerPolicyFilter; 52 import android.car.hardware.power.PowerComponent; 53 import android.car.test.mocks.AbstractExtendedMockitoTestCase; 54 import android.car.test.mocks.JavaMockitoHelper; 55 import android.car.testapi.FakeRefactoredCarPowerPolicyDaemon; 56 import android.content.Context; 57 import android.content.pm.PackageManager; 58 import android.content.res.Resources; 59 import android.frameworks.automotive.powerpolicy.internal.ICarPowerPolicySystemNotification; 60 import android.hardware.automotive.vehicle.VehicleApPowerStateReq; 61 import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam; 62 import android.os.IInterface; 63 import android.os.UserManager; 64 import android.util.AtomicFile; 65 import android.util.Log; 66 import android.util.SparseBooleanArray; 67 68 import androidx.test.filters.SmallTest; 69 import androidx.test.platform.app.InstrumentationRegistry; 70 71 import com.android.car.R; 72 import com.android.car.hal.MockedPowerHalService; 73 import com.android.car.hal.PowerHalService; 74 import com.android.car.hal.PowerHalService.PowerState; 75 import com.android.car.power.CarPowerManagementService; 76 import com.android.car.power.PowerComponentHandler; 77 import com.android.car.systeminterface.DisplayInterface; 78 import com.android.car.systeminterface.SystemInterface; 79 import com.android.car.systeminterface.SystemStateInterface; 80 import com.android.car.user.CarUserService; 81 import com.android.compatibility.common.util.PollingCheck; 82 import com.android.internal.annotations.GuardedBy; 83 84 import org.junit.After; 85 import org.junit.Before; 86 import org.junit.Rule; 87 import org.junit.Test; 88 import org.junit.rules.TemporaryFolder; 89 import org.mockito.Mock; 90 import org.mockito.Spy; 91 92 import java.io.File; 93 import java.time.Duration; 94 import java.util.ArrayList; 95 import java.util.List; 96 import java.util.concurrent.CountDownLatch; 97 import java.util.concurrent.Executor; 98 import java.util.concurrent.Semaphore; 99 import java.util.concurrent.TimeUnit; 100 101 @SmallTest 102 public final class CarPowerManagerUnitTest extends AbstractExtendedMockitoTestCase { 103 private static final String TAG = CarPowerManagerUnitTest.class.getSimpleName(); 104 private static final long WAIT_TIMEOUT_MS = 5_000; 105 private static final long WAIT_TIMEOUT_LONG_MS = 10_000; 106 // A shorter value for use when the test is expected to time out 107 private static final long WAIT_WHEN_TIMEOUT_EXPECTED_MS = 100; 108 109 @Rule 110 public final TemporaryFolder temporaryFolder = new TemporaryFolder(); 111 112 private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface(); 113 private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface(); 114 private final ICarPowerPolicyDelegate mRefactoredPowerPolicyDaemon = 115 new FakeRefactoredCarPowerPolicyDaemon( 116 /* fileKernelSilentMode= */ new File("KERNEL_SILENT_FILE"), 117 /* customComponents= */ null); 118 119 @Spy 120 private final Context mContext = 121 InstrumentationRegistry.getInstrumentation().getTargetContext(); 122 private final Executor mExecutor = mContext.getMainExecutor(); 123 124 private File mComponentStateFile; 125 private MockedPowerHalService mPowerHal; 126 private SystemInterface mSystemInterface; 127 private CarPowerManagementService mService; 128 private CarPowerManager mCarPowerManager; 129 private PowerComponentHandler mPowerComponentHandler; 130 131 private static final Object sLock = new Object(); 132 133 @Mock 134 private Resources mResources; 135 @Mock 136 private Car mCar; 137 @Mock 138 private UserManager mUserManager; 139 @Mock 140 private CarUserService mCarUserService; 141 //TODO(286303350): replace this with refactored power policy daemon once refactor is complete 142 @Mock 143 private ICarPowerPolicySystemNotification mPowerPolicyDaemon; 144 CarPowerManagerUnitTest()145 public CarPowerManagerUnitTest() throws Exception { 146 super(CarPowerManager.TAG); 147 } 148 149 @Before setUp()150 public void setUp() throws Exception { 151 mComponentStateFile = temporaryFolder.newFile("COMPONENT_STATE_FILE"); 152 mPowerHal = new MockedPowerHalService(/*isPowerStateSupported=*/true, 153 /*isDeepSleepAllowed=*/true, 154 /*isHibernationAllowed=*/true, 155 /*isTimedWakeupAllowed=*/true); 156 mSystemInterface = SystemInterface.Builder.defaultSystemInterface(mContext) 157 .withDisplayInterface(mDisplayInterface) 158 .withSystemStateInterface(mSystemStateInterface) 159 .build(); 160 setService(); 161 mCarPowerManager = new CarPowerManager(mCar, mService); 162 } 163 164 @After tearDown()165 public void tearDown() throws Exception { 166 if (mService != null) { 167 mService.release(); 168 } 169 } 170 171 @Test testRequestShutdownOnNextSuspend_positive()172 public void testRequestShutdownOnNextSuspend_positive() throws Exception { 173 setPowerOn(); 174 // Tell it to shutdown 175 mCarPowerManager.requestShutdownOnNextSuspend(); 176 // Request suspend 177 setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 178 VehicleApPowerStateShutdownParam.CAN_SLEEP); 179 // Verify shutdown 180 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, 0); 181 } 182 183 @Test testRequestShutdownOnNextSuspend_negative()184 public void testRequestShutdownOnNextSuspend_negative() throws Exception { 185 setPowerOn(); 186 187 // Do not tell it to shutdown 188 189 // Request suspend 190 setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 191 VehicleApPowerStateShutdownParam.CAN_SLEEP); 192 // Verify suspend 193 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0); 194 } 195 196 @Test testScheduleNextWakeupTime()197 public void testScheduleNextWakeupTime() throws Exception { 198 setPowerOn(); 199 200 int wakeTime = 1234; 201 mCarPowerManager.scheduleNextWakeupTime(wakeTime); 202 203 setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 204 VehicleApPowerStateShutdownParam.CAN_SLEEP); 205 206 // Verify that we suspended with the requested wake-up time 207 assertStateReceivedForShutdownOrSleepWithPostpone( 208 PowerHalService.SET_DEEP_SLEEP_ENTRY, wakeTime); 209 } 210 211 @Test testSetListener()212 public void testSetListener() throws Exception { 213 setPowerOn(); 214 215 WaitablePowerStateListener listener = new WaitablePowerStateListener(3); 216 217 setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 218 VehicleApPowerStateShutdownParam.CAN_SLEEP); 219 220 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0); 221 222 List<Integer> states = listener.await(); 223 checkThatStatesReceivedInOrder("Check that events were received in order", states, 224 List.of(CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE, 225 CarPowerManager.STATE_SHUTDOWN_PREPARE, 226 CarPowerManager.STATE_SUSPEND_ENTER)); 227 } 228 229 @Test testSetListenerWithCompletion()230 public void testSetListenerWithCompletion() throws Exception { 231 grantAdjustShutdownProcessPermission(); 232 List<Integer> expectedStates = List.of(CarPowerManager.STATE_ON, 233 CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE, 234 CarPowerManager.STATE_SHUTDOWN_PREPARE, 235 CarPowerManager.STATE_SUSPEND_ENTER); 236 WaitablePowerStateListenerWithCompletion listener = 237 new WaitablePowerStateListenerWithCompletion(/* initialCount= */ 4); 238 239 setPowerOn(); 240 setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 241 VehicleApPowerStateShutdownParam.CAN_SLEEP); 242 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0); 243 244 List<Integer> states = listener.await(); 245 checkThatStatesReceivedInOrder("Check that events were received in order", states, 246 expectedStates); 247 } 248 249 @Test testClearListener()250 public void testClearListener() throws Exception { 251 setPowerOn(); 252 253 // Set a listener with a short timeout, because we expect the timeout to happen 254 WaitablePowerStateListener listener = 255 new WaitablePowerStateListener(1, WAIT_WHEN_TIMEOUT_EXPECTED_MS); 256 257 mCarPowerManager.clearListener(); 258 259 setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 260 VehicleApPowerStateShutdownParam.CAN_SLEEP); 261 262 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0); 263 // Verify that the listener didn't run 264 assertThrows(IllegalStateException.class, () -> listener.await()); 265 } 266 267 @Test testGetPowerState()268 public void testGetPowerState() throws Exception { 269 setPowerOn(); 270 assertThat(mCarPowerManager.getPowerState()).isEqualTo(PowerHalService.SET_ON); 271 272 // Request suspend 273 setPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 274 VehicleApPowerStateShutdownParam.CAN_SLEEP); 275 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0); 276 assertThat(mCarPowerManager.getPowerState()) 277 .isEqualTo(PowerHalService.SET_DEEP_SLEEP_ENTRY); 278 } 279 280 @Test testGetCurrentPowerPolicy()281 public void testGetCurrentPowerPolicy() throws Exception { 282 grantPowerPolicyPermission(); 283 CarPowerPolicy expected = new CarPowerPolicy("test_policy4", 284 new int[]{AUDIO, MEDIA, DISPLAY, INPUT, CPU}, 285 new int[]{BLUETOOTH, CELLULAR, ETHERNET, LOCATION, MICROPHONE, NFC, PROJECTION, 286 TRUSTED_DEVICE_DETECTION, VISUAL_INTERACTION, VOICE_INTERACTION, WIFI}); 287 PolicyDefinition[] policyDefinitions = new PolicyDefinition[]{ 288 new PolicyDefinition("test_policy1", new String[]{"WIFI"}, new String[]{"AUDIO"}), 289 new PolicyDefinition("test_policy2", new String[]{"WIFI", "DISPLAY"}, 290 new String[]{"NFC"}), 291 new PolicyDefinition("test_policy3", new String[]{"CPU", "INPUT"}, 292 new String[]{"WIFI"}), 293 new PolicyDefinition("test_policy4", new String[]{"MEDIA", "AUDIO"}, 294 new String[]{})}; 295 for (PolicyDefinition definition : policyDefinitions) { 296 mService.definePowerPolicy(definition.policyId, definition.enabledComponents, 297 definition.disabledComponents); 298 } 299 300 for (PolicyDefinition definition : policyDefinitions) { 301 mCarPowerManager.applyPowerPolicy(definition.policyId); 302 } 303 304 assertPolicyIdentical(expected, mCarPowerManager.getCurrentPowerPolicy()); 305 } 306 307 @Test testApplyPowerPolicy()308 public void testApplyPowerPolicy() throws Exception { 309 grantPowerPolicyPermission(); 310 String policyId = "no_change_policy"; 311 mService.definePowerPolicy(policyId, new String[0], new String[0]); 312 313 mCarPowerManager.applyPowerPolicy(policyId); 314 315 assertThat(mCarPowerManager.getCurrentPowerPolicy().getPolicyId()).isEqualTo(policyId); 316 } 317 318 @Test testApplyPowerPolicy_invalidId()319 public void testApplyPowerPolicy_invalidId() throws Exception { 320 grantPowerPolicyPermission(); 321 String policyId = "invalid_power_policy"; 322 323 assertThrows(IllegalArgumentException.class, 324 () -> mCarPowerManager.applyPowerPolicy(policyId)); 325 } 326 327 @Test testApplyPowerPolicy_nullPolicyId()328 public void testApplyPowerPolicy_nullPolicyId() throws Exception { 329 grantPowerPolicyPermission(); 330 assertThrows(IllegalArgumentException.class, () -> mCarPowerManager.applyPowerPolicy(null)); 331 } 332 333 @Test testAddPowerPolicyListener()334 public void testAddPowerPolicyListener() throws Exception { 335 grantPowerPolicyPermission(); 336 337 // Prepare for test 338 applyInitialPolicyForTest(/* policyName= */ "audio_off", /* enabledComponents= */ 339 new String[]{}, /* disabledComponents= */ new String[]{"AUDIO"}); 340 341 String policyId = "audio_on_wifi_off"; 342 mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"}); 343 MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener(); 344 MockedPowerPolicyListener listenerWifi = new MockedPowerPolicyListener(); 345 MockedPowerPolicyListener listenerLocation = new MockedPowerPolicyListener(); 346 CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder() 347 .setComponents(PowerComponent.AUDIO).build(); 348 CarPowerPolicyFilter filterWifi = new CarPowerPolicyFilter.Builder() 349 .setComponents(PowerComponent.WIFI).build(); 350 CarPowerPolicyFilter filterLocation = new CarPowerPolicyFilter.Builder() 351 .setComponents(PowerComponent.LOCATION).build(); 352 353 mCarPowerManager.addPowerPolicyListener(mExecutor, filterAudio, listenerAudio); 354 mCarPowerManager.addPowerPolicyListener(mExecutor, filterWifi, listenerWifi); 355 mCarPowerManager.addPowerPolicyListener(mExecutor, filterLocation, listenerLocation); 356 mCarPowerManager.applyPowerPolicy(policyId); 357 358 assertPowerPolicyId(listenerAudio, policyId, "Current policy ID of listenerAudio is not " 359 + policyId); 360 assertPowerPolicyId(listenerWifi, policyId, "Current policy ID of listenerWifi is not " 361 + policyId); 362 assertThat(listenerLocation.getCurrentPolicyId()).isNull(); 363 } 364 365 @Test testAddPowerPolicyListener_Twice_WithDifferentFilters()366 public void testAddPowerPolicyListener_Twice_WithDifferentFilters() throws Exception { 367 grantPowerPolicyPermission(); 368 String policyId = "audio_on_wifi_off"; 369 mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"}); 370 MockedPowerPolicyListener listener = new MockedPowerPolicyListener(); 371 CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder() 372 .setComponents(PowerComponent.AUDIO).build(); 373 CarPowerPolicyFilter filterLocation = new CarPowerPolicyFilter.Builder() 374 .setComponents(PowerComponent.LOCATION).build(); 375 376 mCarPowerManager.addPowerPolicyListener(mExecutor, filterAudio, listener); 377 mCarPowerManager.addPowerPolicyListener(mExecutor, filterLocation, listener); 378 mCarPowerManager.applyPowerPolicy(policyId); 379 380 assertThat(listener.getCurrentPolicyId()).isNull(); 381 } 382 383 @Test testAddPowerPolicyListener_nullListener()384 public void testAddPowerPolicyListener_nullListener() throws Exception { 385 MockedPowerPolicyListener listener = new MockedPowerPolicyListener(); 386 CarPowerPolicyFilter filter = new CarPowerPolicyFilter.Builder() 387 .setComponents(PowerComponent.AUDIO).build(); 388 389 assertThrows(NullPointerException.class, 390 () -> mCarPowerManager.addPowerPolicyListener(null, filter, listener)); 391 assertThrows(NullPointerException.class, 392 () -> mCarPowerManager.addPowerPolicyListener(mExecutor, filter, null)); 393 assertThrows(NullPointerException.class, 394 () -> mCarPowerManager.addPowerPolicyListener(mExecutor, null, listener)); 395 } 396 397 @Test testRemovePowerPolicyListener()398 public void testRemovePowerPolicyListener() throws Exception { 399 grantPowerPolicyPermission(); 400 401 String initialPolicyId = "audio_off"; 402 applyInitialPolicyForTest(initialPolicyId, /* enabledComponents= */ 403 new String[]{}, /* disabledComponents= */ new String[]{"AUDIO"}); 404 405 String policyId = "audio_on_wifi_off"; 406 mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"}); 407 MockedPowerPolicyListener listenerOne = new MockedPowerPolicyListener(); 408 MockedPowerPolicyListener listenerTwo = new MockedPowerPolicyListener(); 409 CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder() 410 .setComponents(PowerComponent.AUDIO).build(); 411 412 mCarPowerManager.addPowerPolicyListener(mExecutor, filterAudio, listenerOne); 413 mCarPowerManager.addPowerPolicyListener(mExecutor, filterAudio, listenerTwo); 414 mCarPowerManager.removePowerPolicyListener(listenerOne); 415 mCarPowerManager.applyPowerPolicy(policyId); 416 417 String receivedPolicyId = listenerOne.getCurrentPolicyId(); 418 assertWithMessage("Policy ID received after removing listeners") 419 .that(receivedPolicyId == null || receivedPolicyId.equals(initialPolicyId)) 420 .isTrue(); 421 assertPowerPolicyId(listenerTwo, policyId, "Current policy ID of listenerTwo is not " 422 + policyId); 423 } 424 applyInitialPolicyForTest(String policyName, String[] enabledComponents, String[] disabledComponents)425 private void applyInitialPolicyForTest(String policyName, String[] enabledComponents, 426 String[] disabledComponents) { 427 mService.definePowerPolicy(policyName, enabledComponents, disabledComponents); 428 mCarPowerManager.applyPowerPolicy(policyName); 429 } 430 431 @Test testRemovePowerPolicyListener_Twice()432 public void testRemovePowerPolicyListener_Twice() throws Exception { 433 grantPowerPolicyPermission(); 434 MockedPowerPolicyListener listener = new MockedPowerPolicyListener(); 435 CarPowerPolicyFilter filter = new CarPowerPolicyFilter.Builder() 436 .setComponents(PowerComponent.AUDIO).build(); 437 438 // Remove unregistered listener should not throw an exception. 439 mCarPowerManager.removePowerPolicyListener(listener); 440 441 mCarPowerManager.addPowerPolicyListener(mExecutor, filter, listener); 442 mCarPowerManager.removePowerPolicyListener(listener); 443 // Remove the same listener twice should nont throw an exception. 444 mCarPowerManager.removePowerPolicyListener(listener); 445 } 446 447 @Test testRemovePowerPolicyListener_nullListener()448 public void testRemovePowerPolicyListener_nullListener() throws Exception { 449 assertThrows(NullPointerException.class, 450 () -> mCarPowerManager.removePowerPolicyListener(null)); 451 } 452 453 /** 454 * Helper method to create mService and initialize a test case 455 */ setService()456 private void setService() throws Exception { 457 Log.i(TAG, "setService(): overridden overlay properties: " 458 + ", maxGarageModeRunningDurationInSecs=" 459 + mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs)); 460 doReturn(mResources).when(mContext).getResources(); 461 doReturn(false).when(mResources).getBoolean( 462 R.bool.config_enablePassengerDisplayPowerSaving); 463 mPowerComponentHandler = new PowerComponentHandler(mContext, mSystemInterface, 464 new AtomicFile(mComponentStateFile)); 465 IInterface powerPolicyDaemon; 466 if (Flags.carPowerPolicyRefactoring()) { 467 powerPolicyDaemon = mRefactoredPowerPolicyDaemon; 468 } else { 469 powerPolicyDaemon = mPowerPolicyDaemon; 470 } 471 mService = new CarPowerManagementService.Builder().setContext(mContext) 472 .setResources(mResources).setPowerHalService(mPowerHal) 473 .setSystemInterface(mSystemInterface).setUserManager(mUserManager) 474 .setCarUserService(mCarUserService).setPowerPolicyDaemon(powerPolicyDaemon) 475 .setPowerComponentHandler(mPowerComponentHandler).build(); 476 mService.init(); 477 if (Flags.carPowerPolicyRefactoring()) { 478 mService.initializePowerPolicy(); 479 } 480 mService.setShutdownTimersForTest(0, 0); 481 assertStateReceived(PowerHalService.SET_WAIT_FOR_VHAL, 0); 482 } 483 assertStateReceived(int expectedState, int expectedParam)484 private void assertStateReceived(int expectedState, int expectedParam) throws Exception { 485 int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_MS); 486 assertThat(state).asList().containsExactly(expectedState, expectedParam).inOrder(); 487 } 488 489 /** 490 * Helper method to get the system into ON 491 */ setPowerOn()492 private void setPowerOn() throws Exception { 493 setPowerState(VehicleApPowerStateReq.ON, 0); 494 int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_MS); 495 assertThat(state[0]).isEqualTo(PowerHalService.SET_ON); 496 } 497 498 /** 499 * Helper to set the PowerHal state 500 * 501 * @param stateEnum Requested state enum 502 * @param stateParam Addition state parameter 503 */ setPowerState(int stateEnum, int stateParam)504 private void setPowerState(int stateEnum, int stateParam) { 505 mPowerHal.setCurrentPowerState(new PowerState(stateEnum, stateParam)); 506 } 507 assertStateReceivedForShutdownOrSleepWithPostpone( int lastState, int stateParameter)508 private void assertStateReceivedForShutdownOrSleepWithPostpone( 509 int lastState, int stateParameter) throws Exception { 510 long startTime = System.currentTimeMillis(); 511 while (true) { 512 int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_LONG_MS); 513 if (state[0] == lastState) { 514 assertThat(state[1]).isEqualTo(stateParameter); 515 return; 516 } 517 assertThat(state[0]).isEqualTo(PowerHalService.SET_SHUTDOWN_POSTPONE); 518 assertThat(System.currentTimeMillis() - startTime).isLessThan(WAIT_TIMEOUT_LONG_MS); 519 } 520 } 521 grantPowerPolicyPermission()522 private void grantPowerPolicyPermission() { 523 when(mCar.getContext()).thenReturn(mContext); 524 doReturn(PackageManager.PERMISSION_GRANTED).when(mContext) 525 .checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY); 526 doReturn(PackageManager.PERMISSION_GRANTED).when(mContext) 527 .checkCallingOrSelfPermission(Car.PERMISSION_READ_CAR_POWER_POLICY); 528 } 529 grantAdjustShutdownProcessPermission()530 private void grantAdjustShutdownProcessPermission() { 531 when(mCar.getContext()).thenReturn(mContext); 532 doReturn(PackageManager.PERMISSION_GRANTED).when(mContext) 533 .checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_SHUTDOWN_PROCESS); 534 } 535 checkThatStatesReceivedInOrder(String message, List<Integer> states, List<Integer> referenceStates)536 private static void checkThatStatesReceivedInOrder(String message, List<Integer> states, 537 List<Integer> referenceStates) { 538 assertWithMessage(message).that(states).containsExactlyElementsIn( 539 referenceStates).inOrder(); 540 } 541 assertPowerPolicyId(MockedPowerPolicyListener listener, String policyId, String errorMsg)542 private static void assertPowerPolicyId(MockedPowerPolicyListener listener, String policyId, 543 String errorMsg) throws Exception { 544 PollingCheck.check(errorMsg, WAIT_TIMEOUT_MS, 545 () -> policyId.equals(listener.getCurrentPolicyId())); 546 } 547 isCompletionAllowed(@arPowerManager.CarPowerState int state)548 private static boolean isCompletionAllowed(@CarPowerManager.CarPowerState int state) { 549 switch (state) { 550 case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE: 551 case CarPowerManager.STATE_SHUTDOWN_PREPARE: 552 case CarPowerManager.STATE_SHUTDOWN_ENTER: 553 case CarPowerManager.STATE_SUSPEND_ENTER: 554 case CarPowerManager.STATE_HIBERNATION_ENTER: 555 case CarPowerManager.STATE_POST_SHUTDOWN_ENTER: 556 case CarPowerManager.STATE_POST_SUSPEND_ENTER: 557 case CarPowerManager.STATE_POST_HIBERNATION_ENTER: 558 return true; 559 default: 560 return false; 561 } 562 } 563 564 private static final class MockDisplayInterface implements DisplayInterface { 565 @GuardedBy("sLock") 566 private final SparseBooleanArray mDisplayOn = new SparseBooleanArray(); 567 private final Semaphore mDisplayStateWait = new Semaphore(0); 568 569 @Override init(CarPowerManagementService carPowerManagementService, CarUserService carUserService)570 public void init(CarPowerManagementService carPowerManagementService, 571 CarUserService carUserService) {} 572 573 @Override setDisplayBrightness(int brightness)574 public void setDisplayBrightness(int brightness) {} 575 576 @Override setDisplayBrightness(int displayId, int brightness)577 public void setDisplayBrightness(int displayId, int brightness) {} 578 579 @Override setDisplayState(int displayId, boolean on)580 public void setDisplayState(int displayId, boolean on) { 581 synchronized (sLock) { 582 mDisplayOn.put(displayId, on); 583 } 584 mDisplayStateWait.release(); 585 } 586 587 @Override setAllDisplayState(boolean on)588 public void setAllDisplayState(boolean on) { 589 synchronized (sLock) { 590 for (int i = 0; i < mDisplayOn.size(); i++) { 591 int displayId = mDisplayOn.keyAt(i); 592 setDisplayState(displayId, on); 593 } 594 } 595 } 596 597 @Override startDisplayStateMonitoring()598 public void startDisplayStateMonitoring() {} 599 600 @Override stopDisplayStateMonitoring()601 public void stopDisplayStateMonitoring() {} 602 603 @Override refreshDisplayBrightness()604 public void refreshDisplayBrightness() {} 605 606 @Override refreshDisplayBrightness(int displayId)607 public void refreshDisplayBrightness(int displayId) {} 608 609 @Override isAnyDisplayEnabled()610 public boolean isAnyDisplayEnabled() { 611 synchronized (sLock) { 612 for (int i = 0; i < mDisplayOn.size(); i++) { 613 int displayId = mDisplayOn.keyAt(i); 614 if (isDisplayEnabled(displayId)) { 615 return true; 616 } 617 } 618 } 619 return false; 620 } 621 622 @Override isDisplayEnabled(int displayId)623 public boolean isDisplayEnabled(int displayId) { 624 synchronized (sLock) { 625 return mDisplayOn.get(displayId); 626 } 627 } 628 } 629 630 /** 631 * Helper class to set a power-state listener, 632 * verify that the listener gets called the 633 * right number of times, and return the final 634 * power state. 635 */ 636 private final class WaitablePowerStateListener { 637 private final CountDownLatch mLatch; 638 private List<Integer> mReceivedStates = new ArrayList<Integer>(); 639 private long mTimeoutValue = WAIT_TIMEOUT_MS; 640 WaitablePowerStateListener(int initialCount, long customTimeout)641 WaitablePowerStateListener(int initialCount, long customTimeout) { 642 this(initialCount); 643 mTimeoutValue = customTimeout; 644 } 645 WaitablePowerStateListener(int initialCount)646 WaitablePowerStateListener(int initialCount) { 647 mLatch = new CountDownLatch(initialCount); 648 mCarPowerManager.setListener(mContext.getMainExecutor(), 649 (state) -> { 650 mReceivedStates.add(state); 651 mLatch.countDown(); 652 }); 653 } 654 await()655 List<Integer> await() throws Exception { 656 JavaMockitoHelper.await(mLatch, mTimeoutValue); 657 return List.copyOf(mReceivedStates); 658 } 659 } 660 661 /** 662 * Helper class to set a power-state listener with completion, 663 * verify that the listener gets called the right number of times, 664 * verify that the CompletablePowerStateChangeFuture is provided, complete the 665 * CompletablePowerStateChangeFuture, and return the all listened states in order. 666 */ 667 private final class WaitablePowerStateListenerWithCompletion { 668 private final CountDownLatch mLatch; 669 private final List<Integer> mReceivedStates = new ArrayList<>(); 670 private int mRemainingCount; 671 WaitablePowerStateListenerWithCompletion(int initialCount)672 WaitablePowerStateListenerWithCompletion(int initialCount) { 673 mRemainingCount = initialCount; 674 mLatch = new CountDownLatch(initialCount); 675 mCarPowerManager.setListenerWithCompletion(mContext.getMainExecutor(), 676 (state, future) -> { 677 mReceivedStates.add(state); 678 mRemainingCount--; 679 if (isCompletionAllowed(state)) { 680 assertThat(future).isNotNull(); 681 future.complete(); 682 } else { 683 assertThat(future).isNull(); 684 } 685 mLatch.countDown(); 686 }); 687 } 688 await()689 List<Integer> await() throws Exception { 690 JavaMockitoHelper.await(mLatch, WAIT_TIMEOUT_MS); 691 assertThat(mRemainingCount).isEqualTo(0); 692 return mReceivedStates; 693 } 694 } 695 696 private static final class MockSystemStateInterface implements SystemStateInterface { 697 private final Semaphore mShutdownWait = new Semaphore(0); 698 private final Semaphore mSleepWait = new Semaphore(0); 699 private final Semaphore mSleepExitWait = new Semaphore(0); 700 701 @Override shutdown()702 public void shutdown() { 703 mShutdownWait.release(); 704 } 705 706 @Override enterDeepSleep()707 public boolean enterDeepSleep() { 708 return simulateSleep(); 709 } 710 711 @Override enterHibernation()712 public boolean enterHibernation() { 713 return simulateSleep(); 714 } 715 simulateSleep()716 private boolean simulateSleep() { 717 mSleepWait.release(); 718 try { 719 mSleepExitWait.acquire(); 720 } catch (InterruptedException e) { 721 } 722 return true; 723 } 724 725 @Override scheduleActionForBootCompleted(Runnable action, Duration delay, Duration delayRange)726 public void scheduleActionForBootCompleted(Runnable action, Duration delay, 727 Duration delayRange) {} 728 729 @Override isWakeupCausedByTimer()730 public boolean isWakeupCausedByTimer() { 731 Log.i(TAG, "isWakeupCausedByTimer: false"); 732 return false; 733 } 734 735 @Override isSystemSupportingDeepSleep()736 public boolean isSystemSupportingDeepSleep() { 737 return true; 738 } 739 } 740 741 private static final class MockedPowerPolicyListener implements 742 CarPowerManager.CarPowerPolicyListener { 743 private static final int MAX_LISTENER_WAIT_TIME_SEC = 1; 744 745 private final CountDownLatch mLatch = new CountDownLatch(1); 746 private String mCurrentPolicyId; 747 748 @Override onPolicyChanged(@onNull CarPowerPolicy policy)749 public void onPolicyChanged(@NonNull CarPowerPolicy policy) { 750 mCurrentPolicyId = policy.getPolicyId(); 751 mLatch.countDown(); 752 } 753 getCurrentPolicyId()754 public String getCurrentPolicyId() throws Exception { 755 if (mLatch.await(MAX_LISTENER_WAIT_TIME_SEC, TimeUnit.SECONDS)) { 756 return mCurrentPolicyId; 757 } 758 return null; 759 } 760 } 761 762 private static final class PolicyDefinition { 763 public final String policyId; 764 public final String[] enabledComponents; 765 public final String[] disabledComponents; 766 PolicyDefinition(String policyId, String[] enabledComponents, String[] disabledComponents)767 private PolicyDefinition(String policyId, String[] enabledComponents, 768 String[] disabledComponents) { 769 this.policyId = policyId; 770 this.enabledComponents = enabledComponents; 771 this.disabledComponents = disabledComponents; 772 } 773 } 774 } 775