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