• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 package com.android.car.power;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.fail;
22 
23 import android.car.Car;
24 import android.car.feature.Flags;
25 import android.car.hardware.power.CarPowerManager;
26 import android.car.hardware.power.CarPowerPolicy;
27 import android.car.hardware.power.CarPowerPolicyFilter;
28 import android.car.hardware.power.ICarPowerPolicyListener;
29 import android.car.hardware.power.ICarPowerStateListener;
30 import android.car.hardware.power.PowerComponent;
31 import android.car.hardware.property.VehicleHalStatusCode;
32 import android.car.test.mocks.JavaMockitoHelper;
33 import android.frameworks.automotive.powerpolicy.internal.ICarPowerPolicySystemNotification;
34 import android.hardware.automotive.vehicle.VehicleApPowerStateConfigFlag;
35 import android.hardware.automotive.vehicle.VehicleApPowerStateReport;
36 import android.hardware.automotive.vehicle.VehicleApPowerStateReq;
37 import android.hardware.automotive.vehicle.VehicleApPowerStateReqIndex;
38 import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam;
39 import android.hardware.automotive.vehicle.VehiclePropValue;
40 import android.hardware.automotive.vehicle.VehicleProperty;
41 import android.hardware.automotive.vehicle.VehiclePropertyAccess;
42 import android.hardware.automotive.vehicle.VehiclePropertyChangeMode;
43 import android.os.Handler;
44 import android.os.Looper;
45 import android.os.ServiceSpecificException;
46 import android.os.SystemClock;
47 import android.util.SparseBooleanArray;
48 import android.view.Display;
49 
50 import androidx.test.ext.junit.runners.AndroidJUnit4;
51 import androidx.test.filters.MediumTest;
52 
53 import com.android.car.MockedCarTestBase;
54 import com.android.car.hal.test.AidlMockedVehicleHal.VehicleHalPropertyHandler;
55 import com.android.car.hal.test.AidlVehiclePropValueBuilder;
56 import com.android.car.systeminterface.SystemInterface;
57 import com.android.car.systeminterface.SystemStateInterface;
58 import com.android.car.systeminterface.test.DisplayInterfaceEmptyImpl;
59 import com.android.car.user.CarUserService;
60 import com.android.internal.annotations.GuardedBy;
61 
62 import com.google.android.collect.Lists;
63 
64 import org.junit.Test;
65 import org.junit.runner.RunWith;
66 import org.mockito.Mockito;
67 
68 import java.time.Duration;
69 import java.util.Arrays;
70 import java.util.LinkedList;
71 import java.util.Objects;
72 import java.util.concurrent.CountDownLatch;
73 import java.util.concurrent.Semaphore;
74 import java.util.concurrent.TimeUnit;
75 import java.util.concurrent.atomic.AtomicBoolean;
76 
77 @RunWith(AndroidJUnit4.class)
78 @MediumTest
79 public class CarPowerManagementServiceTest extends MockedCarTestBase {
80 
81     private static final int STATE_POLLING_INTERVAL_MS = 1; // Milliseconds
82     private static final int STATE_TRANSITION_MAX_WAIT_MS = 5 * STATE_POLLING_INTERVAL_MS;
83     private static final int TEST_SHUTDOWN_TIMEOUT_MS = 100 * STATE_POLLING_INTERVAL_MS;
84     private static final int POLICY_APPLICATION_TIMEOUT_MS = 10_000;
85     private static final String POWER_POLICY_S2R = "system_power_policy_suspend_prep";
86 
87     private final PowerStatePropertyHandler mPowerStateHandler = new PowerStatePropertyHandler();
88     private final MockDisplayInterface mMockDisplayInterface = new MockDisplayInterface();
89     private final SystemStateInterfaceForSuspend mMockSystemStateInterface =
90             new SystemStateInterfaceForSuspend();
91 
92     @Override
getSystemInterfaceBuilder()93     protected SystemInterface.Builder getSystemInterfaceBuilder() {
94         SystemInterface.Builder builder = super.getSystemInterfaceBuilder();
95         return builder.withDisplayInterface(mMockDisplayInterface)
96                 .withSystemStateInterface(mMockSystemStateInterface);
97     }
98 
99     @Override
configureMockedHal()100     protected void configureMockedHal() {
101         addAidlProperty(VehicleProperty.AP_POWER_STATE_REQ, mPowerStateHandler)
102                 .setConfigArray(Lists.newArrayList(
103                         VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG
104                                 | VehicleApPowerStateConfigFlag.ENABLE_HIBERNATION_FLAG))
105                 .setChangeMode(VehiclePropertyChangeMode.ON_CHANGE).build();
106         addAidlProperty(VehicleProperty.AP_POWER_STATE_REPORT, mPowerStateHandler)
107                 .setAccess(VehiclePropertyAccess.WRITE)
108                 .setChangeMode(VehiclePropertyChangeMode.ON_CHANGE).build();
109     }
110 
111     @Override
configureResourceOverrides(MockResources resources)112     protected void configureResourceOverrides(MockResources resources) {
113         super.configureResourceOverrides(resources);
114         resources.overrideResource(com.android.car.R.integer.config_maxSuspendWaitDuration, 10000);
115     }
116 
117     /**********************************************************************************************
118      * Test immediate shutdown
119      **********************************************************************************************/
120     @Test
testImmediateShutdownFromWaitForVhal()121     public void testImmediateShutdownFromWaitForVhal() throws Exception {
122         assertWaitForVhal();
123         mPowerStateHandler.sendStateAndCheckResponse(
124                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
125                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY,
126                 VehicleApPowerStateReport.SHUTDOWN_START);
127     }
128 
129     @Test
testImmediateShutdownFromWaitForVhal_ErrorCodeFromVhal()130     public void testImmediateShutdownFromWaitForVhal_ErrorCodeFromVhal() throws Exception {
131         // The exceptions from VHAL should be handled in PowerHalService and not propagated.
132 
133         assertWaitForVhal();
134 
135         mPowerStateHandler.setStatus(VehicleHalStatusCode.STATUS_TRY_AGAIN);
136 
137         mPowerStateHandler.sendStateAndExpectNoResponse(
138                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
139                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
140 
141         mPowerStateHandler.setStatus(VehicleHalStatusCode.STATUS_ACCESS_DENIED);
142 
143         mPowerStateHandler.sendStateAndExpectNoResponse(
144                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
145                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
146 
147         mPowerStateHandler.setStatus(VehicleHalStatusCode.STATUS_NOT_AVAILABLE);
148 
149         mPowerStateHandler.sendStateAndExpectNoResponse(
150                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
151                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
152 
153         mPowerStateHandler.setStatus(VehicleHalStatusCode.STATUS_INTERNAL_ERROR);
154 
155         mPowerStateHandler.sendStateAndExpectNoResponse(
156                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
157                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
158 
159         // Clear status code.
160         mPowerStateHandler.setStatus(VehicleHalStatusCode.STATUS_OK);
161     }
162 
163     @Test
testImmediateShutdownFromOn()164     public void testImmediateShutdownFromOn() throws Exception {
165         assertWaitForVhal();
166         // Transition to ON state first
167         mPowerStateHandler.sendStateAndCheckResponse(
168                 VehicleApPowerStateReq.ON,
169                 /* param= */ 0,
170                 VehicleApPowerStateReport.ON);
171         // Send immediate shutdown from ON state
172         mPowerStateHandler.sendStateAndCheckResponse(
173                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
174                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY,
175                 VehicleApPowerStateReport.SHUTDOWN_START);
176     }
177 
178     @Test
testImmediateShutdownFromShutdownPrepare()179     public void testImmediateShutdownFromShutdownPrepare() throws Exception {
180         assertWaitForVhal();
181         registerListenerToFakeGarageMode();
182 
183         // Put device into SHUTDOWN_PREPARE
184         mPowerStateHandler.sendStateAndCheckResponse(
185                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
186                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
187                 VehicleApPowerStateReport.SHUTDOWN_PREPARE);
188         // Initiate shutdown immediately while in SHUTDOWN_PREPARE
189         mPowerStateHandler.sendStateAndCheckResponse(
190                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
191                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY,
192                 VehicleApPowerStateReport.SHUTDOWN_START);
193     }
194 
195     @Test
testDeepSleepEntryAfterGarageMode()196     public void testDeepSleepEntryAfterGarageMode() throws Exception {
197         assertWaitForVhal();
198 
199         registerListenerToFakeGarageMode();
200 
201         // Put device into SHUTDOWN_PREPARE
202         mPowerStateHandler.sendStateAndCheckResponse(
203                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
204                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
205                 VehicleApPowerStateReport.SHUTDOWN_PREPARE);
206 
207         mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
208                 VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
209     }
210 
211     /**********************************************************************************************
212      * Test cancelling of shutdown.
213      **********************************************************************************************/
214     @Test
testCancelShutdownFromShutdownPrepare()215     public void testCancelShutdownFromShutdownPrepare() throws Exception {
216         assertWaitForVhal();
217         mPowerStateHandler.sendStateAndCheckResponse(
218                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
219                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
220                 VehicleApPowerStateReport.SHUTDOWN_PREPARE);
221         // Shutdown may only be cancelled from SHUTDOWN_PREPARE
222         mPowerStateHandler.sendStateAndCheckResponse(
223                 VehicleApPowerStateReq.CANCEL_SHUTDOWN,
224                 /* param= */  0,
225                 VehicleApPowerStateReport.SHUTDOWN_CANCELLED);
226     }
227 
228     @Test
testCancelShutdownFromWaitForFinish()229     public void testCancelShutdownFromWaitForFinish() throws Exception {
230         assertWaitForVhal();
231         mPowerStateHandler.sendStateAndCheckResponse(
232                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
233                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
234                 VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
235         // After DEEP_SLEEP_ENTRY, we're in WAIT_FOR_FINISH
236         mPowerStateHandler.sendStateAndCheckResponse(
237                 VehicleApPowerStateReq.CANCEL_SHUTDOWN,
238                 /* param= */ 0,
239                 VehicleApPowerStateReport.SHUTDOWN_CANCELLED);
240     }
241 
242     /**********************************************************************************************
243      * Test for invalid state transtions
244      **********************************************************************************************/
245     @Test
testInvalidTransitionsFromWaitForVhal()246     public void testInvalidTransitionsFromWaitForVhal() throws Exception {
247         assertWaitForVhal();
248         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0);
249         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.FINISHED, 0);
250     }
251 
252     @Test
testInvalidTransitionsFromOn()253     public void testInvalidTransitionsFromOn() throws Exception {
254         assertWaitForVhal();
255         // Transition to ON state first
256         mPowerStateHandler.sendStateAndCheckResponse(
257                 VehicleApPowerStateReq.ON,
258                 /* param= */ 0,
259                 VehicleApPowerStateReport.ON);
260         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0);
261         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.FINISHED, 0);
262     }
263 
264     @Test
testInvalidTransitionsFromPrepareShutdown()265     public void testInvalidTransitionsFromPrepareShutdown() throws Exception {
266         assertWaitForVhal();
267         registerListenerToFakeGarageMode();
268 
269         // Transition to SHUTDOWN_PREPARE first
270         mPowerStateHandler.sendStateAndCheckResponse(
271                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
272                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
273                 VehicleApPowerStateReport.SHUTDOWN_PREPARE);
274         // Cannot go back to ON state from here
275         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.ON, 0);
276         // SHUTDOWN_PREPARE should not generate state transitions unless it's an IMMEDIATE_SHUTDOWN
277         mPowerStateHandler.sendStateAndExpectNoResponse(
278                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
279                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
280         mPowerStateHandler.sendStateAndExpectNoResponse(
281                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
282                 VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY);
283         // Test the FINISH message last, in case SHUTDOWN_PREPARE finishes early and this test
284         // should be failing.
285         mPowerStateHandler.sendStateAndExpectNoResponse(VehicleApPowerStateReq.FINISHED, 0);
286     }
287 
288     @Test
testInvalidTransitionsFromWaitForFinish()289     public void testInvalidTransitionsFromWaitForFinish() throws Exception {
290         assertWaitForVhal();
291         mPowerStateHandler.sendStateAndCheckResponse(
292                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
293                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
294                 VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
295         mPowerStateHandler.sendStateAndExpectNoResponse(
296                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
297                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
298         mPowerStateHandler.sendStateAndExpectNoResponse(
299                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
300                 VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY);
301         // TODO:  This state may be allowed in the future, if we decide it's necessary
302         mPowerStateHandler.sendStateAndExpectNoResponse(
303                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
304                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
305     }
306 
307     @Test
testInvalidTransitionsFromWaitForFinish2()308     public void testInvalidTransitionsFromWaitForFinish2() throws Exception {
309         assertWaitForVhal();
310         mPowerStateHandler.sendStateAndCheckResponse(
311                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
312                 VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY,
313                 VehicleApPowerStateReport.SHUTDOWN_START);
314         mPowerStateHandler.sendStateAndExpectNoResponse(
315                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
316                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
317         mPowerStateHandler.sendStateAndExpectNoResponse(
318                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
319                 VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY);
320         // TODO:  This state may be allowed in the future, if we decide it's necessary
321         mPowerStateHandler.sendStateAndExpectNoResponse(
322                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
323                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
324     }
325 
326     /**********************************************************************************************
327      * Test sleep entry
328      **********************************************************************************************/
329     // This test also verifies the display state as the device goes in and out of suspend.
330     @Test
testSleepEntry()331     public void testSleepEntry() throws Exception {
332         PowerPolicyListener powerPolicyListener = new PowerPolicyListener(POWER_POLICY_S2R);
333         CarPowerPolicyFilter filter = new CarPowerPolicyFilter.Builder()
334                 .setComponents(PowerComponent.WIFI).build();
335         CarPowerManagementService cpms = getCarPowerManagementService();
336         cpms.addPowerPolicyListener(filter, powerPolicyListener);
337 
338         assertWaitForVhal();
339         mMockDisplayInterface.waitForAllDisplayState(false);
340         mPowerStateHandler.sendStateAndCheckResponse(
341                 VehicleApPowerStateReq.ON,
342                 /* param= */ 0,
343                 VehicleApPowerStateReport.ON);
344         mMockDisplayInterface.waitForAllDisplayState(true);
345         mPowerStateHandler.sendPowerState(
346                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
347                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
348         // The state machine should go to SHUTDOWN_PREPARE, but may
349         // quickly transition to SHUTDOWN_POSTPONE. Report success
350         // if we got to SHUTDOWN_PREPARE, even if we're not there now.
351         assertResponseTransient(VehicleApPowerStateReport.SHUTDOWN_PREPARE, 0, true);
352 
353         mMockDisplayInterface.waitForAllDisplayState(false);
354         assertResponse(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, 0, false);
355         mMockDisplayInterface.waitForAllDisplayState(false);
356         mPowerStateHandler.sendPowerState(VehicleApPowerStateReq.FINISHED, 0);
357         powerPolicyListener.waitForPowerPolicy();
358         assertResponse(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, 0, true);
359         mMockDisplayInterface.waitForAllDisplayState(false);
360 
361         cpms.removePowerPolicyListener(powerPolicyListener);
362     }
363 
364     @Test
testSleepImmediateEntry()365     public void testSleepImmediateEntry() throws Exception {
366         assertWaitForVhal();
367         mMockDisplayInterface.waitForAllDisplayState(false);
368         mPowerStateHandler.sendStateAndCheckResponse(
369                 VehicleApPowerStateReq.ON,
370                 /* param= */ 0,
371                 VehicleApPowerStateReport.ON);
372         mMockDisplayInterface.waitForAllDisplayState(true);
373         mPowerStateHandler.sendPowerState(
374                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
375                 VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
376         assertResponseTransient(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, 0, true);
377     }
378 
379     @Test
testInvalidPowerStateEvent()380     public void testInvalidPowerStateEvent() throws Exception {
381         assertWaitForVhal();
382 
383         // No param in the event, should be ignored.
384         getAidlMockedVehicleHal().injectEvent(
385                     AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.AP_POWER_STATE_REQ)
386                             .setTimestamp(SystemClock.elapsedRealtimeNanos())
387                             .addIntValues(0)
388                             .build());
389 
390         assertEquals(mPowerStateHandler.getSetWaitSemaphore().availablePermits(), 0);
391     }
392 
393     @Test
testUnallowedPowerStateEventAtSuspend()394     public void testUnallowedPowerStateEventAtSuspend() throws Exception {
395         PowerPolicyListener powerPolicyListener = new PowerPolicyListener(POWER_POLICY_S2R);
396         CarPowerPolicyFilter filter = new CarPowerPolicyFilter.Builder()
397                 .setComponents(PowerComponent.WIFI).build();
398         CarPowerManagementService cpms = getCarPowerManagementService();
399         cpms.addPowerPolicyListener(filter, powerPolicyListener);
400 
401         assertWaitForVhal();
402 
403         mPowerStateHandler.sendStateAndCheckResponse(
404                 VehicleApPowerStateReq.ON,
405                 /* param= */ 0,
406                 VehicleApPowerStateReport.ON);
407         mMockDisplayInterface.waitForAllDisplayState(true);
408         // Makes the suspend unsuccessful.
409         mMockSystemStateInterface.setExpectedSuspendStatus(
410                 SystemStateInterface.SUSPEND_RESULT_RETRY);
411         mPowerStateHandler.sendPowerState(
412                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
413                 VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
414 
415         assertResponse(VehicleApPowerStateReport.DEEP_SLEEP_ENTRY, /* expectedParam= */ 0,
416                 /* checkParam= */ false);
417 
418         mPowerStateHandler.sendPowerState(VehicleApPowerStateReq.FINISHED, /* param= */ 0);
419         powerPolicyListener.waitForPowerPolicy();
420 
421         // Sends unallowed power state request.
422         mPowerStateHandler.sendPowerState(
423                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
424                 VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY);
425 
426         // Makes the suspend successful.
427         mMockSystemStateInterface.setExpectedSuspendStatus(
428                 SystemStateInterface.SUSPEND_RESULT_SUCCESS);
429 
430         assertResponseTransient(VehicleApPowerStateReport.DEEP_SLEEP_EXIT, /* expectedParam= */ 0,
431                 /* checkParam= */ true);
432 
433         cpms.removePowerPolicyListener(powerPolicyListener);
434     }
435 
436     @Test
testShutdownPostponeDuringHibernationEnter()437     public void testShutdownPostponeDuringHibernationEnter() throws Exception {
438         testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_HIBERNATION_ENTER,
439                 VehicleApPowerStateShutdownParam.CAN_HIBERNATE,
440                 VehicleApPowerStateReport.HIBERNATION_ENTRY);
441     }
442 
443     @Test
testShutdownPostponeDuringShutdownEnter()444     public void testShutdownPostponeDuringShutdownEnter() throws Exception {
445         testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_SHUTDOWN_ENTER,
446                 VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY,
447                 VehicleApPowerStateReport.SHUTDOWN_START);
448     }
449 
450     @Test
testShutdownPostponeDuringSuspendEnter()451     public void testShutdownPostponeDuringSuspendEnter() throws Exception {
452         testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_SUSPEND_ENTER,
453                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
454                 VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
455     }
456 
457     @Test
testShutdownPostponeDuringPreShutdownPrepare()458     public void testShutdownPostponeDuringPreShutdownPrepare() throws Exception {
459         testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE,
460                 VehicleApPowerStateShutdownParam.CAN_SLEEP,
461                 VehicleApPowerStateReport.DEEP_SLEEP_ENTRY);
462     }
463 
464     @Test
testShutdownPostponeDuringPreShutdownPrepareWithImmediately()465     public void testShutdownPostponeDuringPreShutdownPrepareWithImmediately() throws Exception {
466         testShutdownPostponeWhileListenerPendingInState(CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE,
467                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY,
468                 VehicleApPowerStateReport.SHUTDOWN_START);
469     }
470 
471     @Test
testSleepShutdownFromPreShutdownPrepare()472     public void testSleepShutdownFromPreShutdownPrepare() throws Exception {
473         assertWaitForVhal();
474 
475         registerListenerToFakeGarageMode();
476 
477         AtomicBoolean errorOccurred = new AtomicBoolean(false);
478 
479         // Semaphore to signal receive of PRE_SHUTDOWN_PREPARE
480         Semaphore eventWaitSemaphore = new Semaphore(0);
481         // Semaphore to signal completion of PRE_SHUTDOWN_PREPARE
482         Semaphore completionSemaphore = new Semaphore(0);
483 
484         CarPowerManagementService cpms = getCarPowerManagementService();
485         ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
486             @Override
487             public void onStateChanged(int state, long expirationTimeMs) {
488                 if (!CarPowerManagementService.isCompletionAllowed(state)) {
489                     return;
490                 }
491 
492                 Handler handler = new Handler(Looper.getMainLooper());
493                 ICarPowerStateListener cpmsListener = this;
494                 Runnable completionRunnable = () -> cpms.completeHandlingPowerStateChange(state,
495                         cpmsListener);
496 
497                 if (state == CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE) {
498                     new Thread(() -> {
499                         try {
500                             eventWaitSemaphore.release();
501                             if (completionSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
502                                     TimeUnit.MILLISECONDS)) {
503                                 handler.post(completionRunnable);
504                             } else {
505                                 errorOccurred.set(true);
506                             }
507                         } catch (InterruptedException e) {
508                             errorOccurred.set(true);
509                         }
510                         completionSemaphore.drainPermits();
511                     }).start();
512                 } else {
513                     cpms.completeHandlingPowerStateChange(state, this);
514                 }
515             }
516         };
517         cpms.registerInternalListener(listener);
518 
519         mPowerStateHandler.sendPowerState(
520                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
521                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
522 
523         assertThat(eventWaitSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
524                 TimeUnit.MILLISECONDS)).isTrue();
525 
526         mPowerStateHandler.sendPowerState(
527                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
528                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
529 
530         completionSemaphore.release();
531 
532         mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
533                 VehicleApPowerStateReport.SHUTDOWN_START);
534         assertThat(errorOccurred.get()).isFalse();
535     }
536 
537     @Test
testShutdownImmediatelyFromPreShutdownPrepare()538     public void testShutdownImmediatelyFromPreShutdownPrepare() throws Exception {
539         assertWaitForVhal();
540 
541         registerListenerToFakeGarageMode();
542 
543         AtomicBoolean errorOccurred = new AtomicBoolean(false);
544 
545         // Semaphore to signal receive of PRE_SHUTDOWN_PREPARE
546         Semaphore eventWaitSemaphore = new Semaphore(0);
547         // Semaphore to signal completion of PRE_SHUTDOWN_PREPARE
548         Semaphore completionSemaphore = new Semaphore(0);
549 
550         CarPowerManagementService cpms = getCarPowerManagementService();
551         ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
552             @Override
553             public void onStateChanged(int state, long expirationTimeMs) {
554                 if (!CarPowerManagementService.isCompletionAllowed(state)) {
555                     return;
556                 }
557 
558                 ICarPowerStateListener cpmsListener = this;
559 
560                 if (state == CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE) {
561                     new Thread(() -> {
562                         try {
563                             eventWaitSemaphore.release();
564                             if (completionSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
565                                     TimeUnit.MILLISECONDS)) {
566                                 cpms.completeHandlingPowerStateChange(state, cpmsListener);
567                             } else {
568                                 errorOccurred.set(true);
569                             }
570                         } catch (InterruptedException e) {
571                             errorOccurred.set(true);
572                         }
573                         completionSemaphore.drainPermits();
574                     }).start();
575                 } else {
576                     cpms.completeHandlingPowerStateChange(state, this);
577                 }
578             }
579         };
580         cpms.registerInternalListener(listener);
581 
582         mPowerStateHandler.sendPowerState(
583                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
584                 VehicleApPowerStateShutdownParam.CAN_SLEEP);
585 
586         assertThat(eventWaitSemaphore.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
587                 TimeUnit.MILLISECONDS)).isTrue();
588 
589         mPowerStateHandler.sendPowerState(
590                 VehicleApPowerStateReq.SHUTDOWN_PREPARE,
591                 VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
592 
593         completionSemaphore.release();
594 
595         mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
596                 VehicleApPowerStateReport.SHUTDOWN_START);
597         assertThat(errorOccurred.get()).isFalse();
598     }
599 
600     @Test
testApplyPowerPolicy_vhalPropertyUpdated()601     public void testApplyPowerPolicy_vhalPropertyUpdated() throws Exception {
602         String policyIdWifiOff = "policy_id_wifi_off";
603         String policyIdWifiOn = "policy_id_wifi_on";
604         // This is how the other test cases in this file interact w/CPMS, but would it make sense
605         // to just define mService = (CarPowerManagementService) getCarService(Car.POWER_SERVICE)?
606         CarPowerManagementService cpms = getCarPowerManagementService();
607         cpms.definePowerPolicy(policyIdWifiOff, new String[]{}, new String[]{"WIFI"});
608         cpms.definePowerPolicy(policyIdWifiOn, new String[]{"WIFI"}, new String[]{});
609         PowerPolicyListener wifiOffListener = new PowerPolicyListener(policyIdWifiOff);
610         PowerPolicyListener wifiOnListener = new PowerPolicyListener(policyIdWifiOn);
611         CarPowerPolicyFilter filterWifi = new CarPowerPolicyFilter.Builder()
612                 .setComponents(PowerComponent.WIFI).build();
613         cpms.addPowerPolicyListener(filterWifi, wifiOffListener);
614         cpms.addPowerPolicyListener(filterWifi, wifiOnListener);
615 
616         cpms.applyPowerPolicy(policyIdWifiOn);
617         wifiOnListener.waitForPowerPolicy();
618         cpms.applyPowerPolicy(policyIdWifiOff);
619         wifiOffListener.waitForPowerPolicy();
620 
621         if (!Flags.carPowerPolicyRefactoring()) {
622             Mockito.verify((ICarPowerPolicySystemNotification) getMockedPowerManagementDaemon())
623                     .notifyPowerPolicyChange(policyIdWifiOff, /* force= */ false);
624         }
625     }
626 
testShutdownPostponeWhileListenerPendingInState(final int targetState, int stateRequestParam, int finalPowerState)627     private void testShutdownPostponeWhileListenerPendingInState(final int targetState,
628             int stateRequestParam, int finalPowerState) throws Exception {
629         assertWaitForVhal();
630 
631         Semaphore notificationSem = new Semaphore(0);
632 
633         AtomicBoolean errorOccurred = new AtomicBoolean(false);
634         CarPowerManagementService cpms = getCarPowerManagementService();
635 
636         ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
637             @Override
638             public void onStateChanged(int state, long expirationTimeMs) {
639                 if (!CarPowerManagementService.isCompletionAllowed(state)) {
640                     return;
641                 }
642 
643                 ICarPowerStateListener cpmsListener = this;
644                 if (state == targetState) {
645                     new Thread(() -> {
646                         try {
647                             if (!notificationSem.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS,
648                                     TimeUnit.MILLISECONDS)) {
649                                 errorOccurred.set(true);
650                             }
651                             cpms.completeHandlingPowerStateChange(state, cpmsListener);
652                         } catch (InterruptedException e) {
653                             errorOccurred.set(true);
654                         }
655                     }).start();
656                 } else {
657                     cpms.completeHandlingPowerStateChange(state, this);
658                 }
659             }
660         };
661         cpms.registerInternalListener(listener);
662 
663         //start shutown prepare
664         mPowerStateHandler.sendPowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
665                 stateRequestParam);
666         // wait for SHUTDOWN_POSTPONE
667         mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
668                 VehicleApPowerStateReport.SHUTDOWN_POSTPONE);
669         // complete listener
670         notificationSem.release();
671 
672         mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS, finalPowerState);
673         assertThat(errorOccurred.get()).isFalse();
674     }
675 
676     // Check that 'expectedState' was reached and is the current state.
assertResponse(int expectedState, int expectedParam, boolean checkParam)677     private void assertResponse(int expectedState, int expectedParam, boolean checkParam)
678             throws Exception {
679         LinkedList<int[]> setEvents = mPowerStateHandler.waitForStateSetAndGetAll(
680                 DEFAULT_WAIT_TIMEOUT_MS, expectedState);
681         int[] last = setEvents.getLast();
682         assertEquals(expectedState, last[0]);
683         if (checkParam) {
684             assertEquals(expectedParam, last[1]);
685         }
686     }
687 
688     // Check that 'expectedState' was reached. (But it's OK if it is not still current.)
assertResponseTransient(int expectedState, int expectedParam, boolean checkParam)689     private void assertResponseTransient(int expectedState, int expectedParam, boolean checkParam)
690             throws Exception {
691         LinkedList<int[]> setEvents = mPowerStateHandler.waitForStateSetAndGetAll(
692                 DEFAULT_WAIT_TIMEOUT_MS, expectedState);
693         for (int[] aState : setEvents) {
694             if (expectedState != aState[0]) continue;
695             if (checkParam) {
696                 assertEquals(expectedParam, aState[1]);
697             }
698             return; // Success
699         }
700         fail("Did not find expected state: " + expectedState);
701     }
702 
assertWaitForVhal()703     private void assertWaitForVhal() throws Exception {
704         mPowerStateHandler.waitForSubscription(DEFAULT_WAIT_TIMEOUT_MS);
705         LinkedList<int[]> setEvents = mPowerStateHandler.waitForStateSetAndGetAll(
706                 DEFAULT_WAIT_TIMEOUT_MS, VehicleApPowerStateReport.WAIT_FOR_VHAL);
707         int[] first = setEvents.getFirst();
708         assertEquals(VehicleApPowerStateReport.WAIT_FOR_VHAL, first[0]);
709         assertEquals(0, first[1]);
710     }
711 
registerListenerToFakeGarageMode()712     private void registerListenerToFakeGarageMode() {
713         CarPowerManagementService cpms = getCarPowerManagementService();
714         ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
715             @Override
716             public void onStateChanged(int state, long expirationTimeMs) {
717                 if (CarPowerManagementService.isCompletionAllowed(state)) {
718                     // Do not call finished() to stay in shutdown prepare, when Garage Mode is
719                     // supposed to be running.
720                     if (state == CarPowerManager.STATE_SHUTDOWN_PREPARE
721                             && !cpms.garageModeShouldExitImmediately()) {
722                         return;
723                     }
724                     cpms.completeHandlingPowerStateChange(state, this);
725                 }
726             }
727         };
728         cpms.registerInternalListener(listener);
729     }
730 
getCarPowerManagementService()731     private CarPowerManagementService getCarPowerManagementService() {
732         CarPowerManagementService cpms =
733                 (CarPowerManagementService) getCarService(Car.POWER_SERVICE);
734         if (Flags.carPowerPolicyRefactoring()) {
735             cpms.initializePowerPolicy();
736         }
737         return cpms;
738     }
739 
740     private static final class MockDisplayInterface extends DisplayInterfaceEmptyImpl {
741         private final Object mLock = new Object();
742         @GuardedBy("mLock")
743         private final SparseBooleanArray mDisplayOn = new SparseBooleanArray();
744         private final Semaphore mDisplayStateWait = new Semaphore(0);
745         private CarPowerManagementService mCarPowerManagementService;
746 
747         @Override
init(CarPowerManagementService carPowerManagementService, CarUserService carUserService)748         public void init(CarPowerManagementService carPowerManagementService,
749                 CarUserService carUserService) {
750             mCarPowerManagementService = carPowerManagementService;
751             synchronized (mLock) {
752                 mDisplayOn.put(Display.DEFAULT_DISPLAY, true);
753             }
754         }
755 
756         @Override
setDisplayState(int displayId, boolean on)757         public void setDisplayState(int displayId, boolean on) {
758             synchronized (mLock) {
759                 mDisplayOn.put(displayId, on);
760             }
761             mDisplayStateWait.release();
762         }
763 
764         @Override
setAllDisplayState(boolean on)765         public void setAllDisplayState(boolean on) {
766             synchronized (mLock) {
767                 for (int i = 0; i < mDisplayOn.size(); i++) {
768                     int displayId = mDisplayOn.keyAt(i);
769                     setDisplayState(displayId, on);
770                 }
771             }
772         }
773 
waitForDisplayState(int displayId, boolean expectedState)774         boolean waitForDisplayState(int displayId, boolean expectedState) throws Exception {
775             boolean enabled = false;
776             synchronized (mLock) {
777                 enabled = mDisplayOn.get(displayId);
778             }
779             if (expectedState == enabled) {
780                 return true;
781             }
782             mDisplayStateWait.tryAcquire(MockedCarTestBase.SHORT_WAIT_TIMEOUT_MS,
783                     TimeUnit.MILLISECONDS);
784             return expectedState == enabled;
785         }
786 
waitForAllDisplayState(boolean expectedState)787         void waitForAllDisplayState(boolean expectedState) throws Exception {
788             SparseBooleanArray displayOn;
789             synchronized (mLock) {
790                 displayOn = mDisplayOn.clone();
791             }
792             for (int i = 0; i < displayOn.size(); i++) {
793                 int displayId = displayOn.keyAt(i);
794                 waitForDisplayState(displayId, expectedState);
795             }
796         }
797 
798         @Override
startDisplayStateMonitoring()799         public void startDisplayStateMonitoring() {
800             // To reduce test duration, decrease the polling interval and the
801             // time to wait for a shutdown
802             mCarPowerManagementService.setShutdownTimersForTest(STATE_POLLING_INTERVAL_MS,
803                     TEST_SHUTDOWN_TIMEOUT_MS);
804         }
805 
806         @Override
stopDisplayStateMonitoring()807         public void stopDisplayStateMonitoring() {}
808 
809         @Override
refreshDefaultDisplayBrightness()810         public void refreshDefaultDisplayBrightness() {}
811 
812         @Override
refreshDisplayBrightness(int displayId)813         public void refreshDisplayBrightness(int displayId) {}
814 
815         @Override
isAnyDisplayEnabled()816         public boolean isAnyDisplayEnabled() {
817             synchronized (mLock) {
818                 for (int i = 0; i < mDisplayOn.size(); i++) {
819                     int displayId = mDisplayOn.keyAt(i);
820                     if (isDisplayEnabled(displayId)) {
821                         return true;
822                     }
823                 }
824             }
825             return false;
826         }
827 
828         @Override
isDisplayEnabled(int displayId)829         public boolean isDisplayEnabled(int displayId) {
830             synchronized (mLock) {
831                 return mDisplayOn.get(displayId);
832             }
833         }
834     }
835 
836     private class PowerStatePropertyHandler implements VehicleHalPropertyHandler {
837 
838         private int mPowerState = VehicleApPowerStateReq.ON;
839         private int mPowerParam = 0;
840         private int mStatus = VehicleHalStatusCode.STATUS_OK;
841 
842         private final Semaphore mSubscriptionWaitSemaphore = new Semaphore(0);
843         private final Semaphore mSetWaitSemaphore = new Semaphore(0);
844         private final LinkedList<int[]> mSetStates = new LinkedList<>();
845 
getSetWaitSemaphore()846         public Semaphore getSetWaitSemaphore() {
847             return mSetWaitSemaphore;
848         }
849 
setStatus(int status)850         public void setStatus(int status) {
851             mStatus = status;
852         }
853 
854         @Override
onPropertySet(VehiclePropValue value)855         public void onPropertySet(VehiclePropValue value) {
856             if (mStatus != VehicleHalStatusCode.STATUS_OK) {
857                 throw new ServiceSpecificException(mStatus);
858             }
859             int[] v = value.value.int32Values;
860             synchronized (this) {
861                 mSetStates.add(new int[] {
862                         v[VehicleApPowerStateReqIndex.STATE],
863                         v[VehicleApPowerStateReqIndex.ADDITIONAL]
864                 });
865             }
866             mSetWaitSemaphore.release();
867         }
868 
869         @Override
onPropertyGet(VehiclePropValue value)870         public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
871             if (mStatus != VehicleHalStatusCode.STATUS_OK) {
872                 throw new ServiceSpecificException(mStatus);
873             }
874             return AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.AP_POWER_STATE_REQ)
875                     .setTimestamp(SystemClock.elapsedRealtimeNanos())
876                     .addIntValues(mPowerState, mPowerParam)
877                     .build();
878         }
879 
880         @Override
onPropertySubscribe(int property, float sampleRate)881         public void onPropertySubscribe(int property, float sampleRate) {
882             mSubscriptionWaitSemaphore.release();
883         }
884 
885         @Override
onPropertyUnsubscribe(int property)886         public void onPropertyUnsubscribe(int property) {
887             //ignore
888         }
889 
waitForSubscription(long timeoutMs)890         private void waitForSubscription(long timeoutMs) throws Exception {
891             if (!mSubscriptionWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
892                 fail("waitForSubscription timeout");
893             }
894         }
895 
waitForStateSetAndGetAll(long timeoutMs, int expectedState)896         private LinkedList<int[]> waitForStateSetAndGetAll(long timeoutMs, int expectedState)
897                 throws Exception {
898             while (true) {
899                 if (!mSetWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
900                     fail("waitForStateSetAndGetAll timeout");
901                 }
902                 LinkedList<int[]> result = new LinkedList<>();
903                 synchronized (this) {
904                     boolean found = false;
905 
906                     while (!mSetStates.isEmpty()) {
907                         int[] state = mSetStates.pop();
908                         result.add(state);
909                         if (state[0] == expectedState) {
910                             found = true;
911                             break;
912                         }
913                     }
914                     if (found) {
915                         // update semaphore to actual number of events in the list
916                         mSetWaitSemaphore.drainPermits();
917                         mSetWaitSemaphore.release(mSetStates.size());
918                         return result;
919                     }
920                 }
921             }
922         }
923 
sendStateAndCheckResponse(int state, int param, int expectedState)924         private void sendStateAndCheckResponse(int state, int param, int expectedState)
925                 throws Exception {
926             sendPowerState(state, param);
927             waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS, expectedState);
928         }
929 
930         /**
931          * Checks that a power state transition does NOT occur. If any state does occur during
932          * the timeout period (other than a POSTPONE), then the test fails.
933          */
sendStateAndExpectNoResponse(int state, int param)934         private void sendStateAndExpectNoResponse(int state, int param) throws Exception {
935             sendPowerState(state, param);
936             // Wait to see if a state transition occurs
937             long startTime = SystemClock.elapsedRealtime();
938             while (true) {
939                 long timeWaitingMs = SystemClock.elapsedRealtime() - startTime;
940                 if (timeWaitingMs > STATE_TRANSITION_MAX_WAIT_MS) {
941                     // No meaningful state transition: this is a success!
942                     return;
943                 }
944                 if (!mSetWaitSemaphore.tryAcquire(STATE_TRANSITION_MAX_WAIT_MS,
945                         TimeUnit.MILLISECONDS)) {
946                     // No state transition, this is a success!
947                     return;
948                 }
949                 synchronized (this) {
950                     while (!mSetStates.isEmpty()) {
951                         int[] newState = mSetStates.pop();
952                         if (newState[0] != VehicleApPowerStateReport.SHUTDOWN_POSTPONE) {
953                             fail("Unexpected state change occurred, state="
954                                     + Arrays.toString(newState));
955                         }
956                     }
957                     mSetWaitSemaphore.drainPermits();
958                 }
959             }
960         }
961 
sendPowerState(int state, int param)962         private void sendPowerState(int state, int param) {
963             getAidlMockedVehicleHal().injectEvent(
964                     AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.AP_POWER_STATE_REQ)
965                             .setTimestamp(SystemClock.elapsedRealtimeNanos())
966                             .addIntValues(state, param)
967                             .build());
968         }
969     }
970 
971     private static final class PowerPolicyListener extends ICarPowerPolicyListener.Stub {
972         private final CountDownLatch mLatch = new CountDownLatch(1);
973         private final String mWaitingPolicyId;
974 
PowerPolicyListener(String policyId)975         private PowerPolicyListener(String policyId) {
976             mWaitingPolicyId = policyId;
977         }
978 
979         @Override
onPolicyChanged(CarPowerPolicy appliedPolicy, CarPowerPolicy accumulatedPolicy)980         public void onPolicyChanged(CarPowerPolicy appliedPolicy,
981                 CarPowerPolicy accumulatedPolicy) {
982             if (Objects.equals(appliedPolicy.getPolicyId(), mWaitingPolicyId)) {
983                 mLatch.countDown();
984             }
985         }
986 
waitForPowerPolicy()987         public void waitForPowerPolicy() throws Exception {
988             JavaMockitoHelper.await(mLatch, POLICY_APPLICATION_TIMEOUT_MS);
989         }
990     }
991 
992     private static final class SystemStateInterfaceForSuspend implements SystemStateInterface {
993 
994         private final Object mLock = new Object();
995 
996         @GuardedBy("mLock")
997         private int mExpectedSuspendStatus = SUSPEND_RESULT_SUCCESS;
998 
999         @Override
shutdown()1000         public void shutdown() {}
1001 
1002         @Override
enterDeepSleep()1003         public int enterDeepSleep() {
1004             synchronized (mLock) {
1005                 return mExpectedSuspendStatus;
1006             }
1007         }
1008 
1009         @Override
enterHibernation()1010         public int enterHibernation() {
1011             synchronized (mLock) {
1012                 return mExpectedSuspendStatus;
1013             }
1014         }
1015 
1016         @Override
scheduleActionForBootCompleted(Runnable action, Duration delay, Duration delayRange)1017         public void scheduleActionForBootCompleted(Runnable action, Duration delay,
1018                 Duration delayRange) {}
1019 
setExpectedSuspendStatus(int expectedStatus)1020         public void setExpectedSuspendStatus(int expectedStatus) {
1021             synchronized (mLock) {
1022                 mExpectedSuspendStatus = expectedStatus;
1023             }
1024         }
1025     }
1026 }
1027