• 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.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