• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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