blob: b6b2493cc58d5c41cc0d3708542da287a1e2bcc8 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.power;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.car.Car;
import android.car.ICarResultReceiver;
import android.car.builtin.app.VoiceInteractionHelper;
import android.car.hardware.power.CarPowerManager;
import android.car.hardware.power.CarPowerPolicy;
import android.car.hardware.power.CarPowerPolicyFilter;
import android.car.hardware.power.ICarPowerPolicyListener;
import android.car.hardware.power.ICarPowerStateListener;
import android.car.hardware.power.PowerComponent;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.frameworks.automotive.powerpolicy.internal.ICarPowerPolicySystemNotification;
import android.frameworks.automotive.powerpolicy.internal.PolicyState;
import android.hardware.automotive.vehicle.VehicleApPowerStateReq;
import android.hardware.automotive.vehicle.VehicleApPowerStateShutdownParam;
import android.net.wifi.WifiManager;
import android.os.UserManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.AtomicFile;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.car.CarLocalServices;
import com.android.car.CarServiceUtils;
import com.android.car.R;
import com.android.car.hal.MockedPowerHalService;
import com.android.car.hal.PowerHalService;
import com.android.car.hal.PowerHalService.PowerState;
import com.android.car.internal.util.IndentingPrintWriter;
import com.android.car.systeminterface.DisplayInterface;
import com.android.car.systeminterface.IOInterface;
import com.android.car.systeminterface.SystemInterface;
import com.android.car.systeminterface.SystemStateInterface;
import com.android.car.systeminterface.WakeLockInterface;
import com.android.car.test.utils.TemporaryDirectory;
import com.android.car.test.utils.TemporaryFile;
import com.android.car.user.CarUserService;
import com.android.compatibility.common.util.PollingCheck;
import com.android.internal.annotations.GuardedBy;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Spy;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@SmallTest
public final class CarPowerManagementServiceUnitTest extends AbstractExtendedMockitoTestCase {
private static final String TAG = CarPowerManagementServiceUnitTest.class.getSimpleName();
private static final long WAIT_TIMEOUT_MS = 2000;
private static final long WAIT_TIMEOUT_LONG_MS = 5000;
private static final int WAKE_UP_DELAY = 100;
private static final String NONSILENT_STRING = "0";
private static final String NORMAL_BOOT = "reboot,shell";
private static final int CURRENT_USER_ID = 42;
private static final int CURRENT_GUEST_ID = 108; // must be different than CURRENT_USER_ID;
private static final int NEW_GUEST_ID = 666;
public static final String SYSTEM_POWER_POLICY_ALL_ON = "system_power_policy_all_on";
public static final String SYSTEM_POWER_POLICY_NO_USER_INTERACTION =
"system_power_policy_no_user_interaction";
public static final String SYSTEM_POWER_POLICY_INITIAL_ON = "system_power_policy_initial_on";
private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface();
private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface();
private final MockWakeLockInterface mWakeLockInterface = new MockWakeLockInterface();
private final MockIOInterface mIOInterface = new MockIOInterface();
private final PowerSignalListener mPowerSignalListener = new PowerSignalListener();
@Spy
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
private final TemporaryFile mComponentStateFile;
private MockedPowerHalService mPowerHal;
private SystemInterface mSystemInterface;
private PowerComponentHandler mPowerComponentHandler;
private CarPowerManagementService mService;
private CompletableFuture<Void> mFuture;
private TemporaryFile mFileHwStateMonitoring;
private TemporaryFile mFileKernelSilentMode;
private FakeCarPowerPolicyDaemon mPowerPolicyDaemon;
private boolean mVoiceInteractionEnabled;
@Mock
private UserManager mUserManager;
@Mock
private Resources mResources;
@Mock
private CarUserService mUserService;
@Mock
private WifiManager mWifiManager;
public CarPowerManagementServiceUnitTest() throws Exception {
super(CarPowerManagementService.TAG);
mComponentStateFile = new TemporaryFile("COMPONENT_STATE_FILE");
}
@Override
protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
session
.spyStatic(ActivityManager.class)
.spyStatic(VoiceInteractionHelper.class);
}
@Before
public void setUp() throws Exception {
mPowerHal = new MockedPowerHalService(/*isPowerStateSupported=*/true,
/*isDeepSleepAllowed=*/true,
/*isHibernationAllowed=*/true,
/*isTimedWakeupAllowed=*/true);
mSystemInterface = SystemInterface.Builder.defaultSystemInterface(mContext)
.withDisplayInterface(mDisplayInterface)
.withSystemStateInterface(mSystemStateInterface)
.withWakeLockInterface(mWakeLockInterface)
.withIOInterface(mIOInterface).build();
setCurrentUser(CURRENT_USER_ID, /* isGuest= */ false);
setService();
}
@After
public void tearDown() throws Exception {
if (mService != null) {
mService.release();
}
CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
CarServiceUtils.finishAllHandlerTasks();
mIOInterface.tearDown();
}
/**
* Helper method to create mService and initialize a test case
*/
private void setService() throws Exception {
doReturn(mResources).when(mContext).getResources();
// During the test, changing Wifi state according to a power policy takes long time, leading
// to timeout. Also, we don't want to actually change Wifi state.
doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class);
when(mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs))
.thenReturn(900);
when(mResources.getInteger(R.integer.config_maxSuspendWaitDuration))
.thenReturn(WAKE_UP_DELAY);
doReturn(true).when(() -> VoiceInteractionHelper.isAvailable());
doAnswer(invocation -> {
mVoiceInteractionEnabled = (boolean) invocation.getArguments()[0];
return null;
}).when(() -> VoiceInteractionHelper.setEnabled(anyBoolean()));
Log.i(TAG, "setService(): overridden overlay properties: "
+ ", maxGarageModeRunningDurationInSecs="
+ mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs));
mFileHwStateMonitoring = new TemporaryFile("HW_STATE_MONITORING");
mFileKernelSilentMode = new TemporaryFile("KERNEL_SILENT_MODE");
mFileHwStateMonitoring.write(NONSILENT_STRING);
mPowerPolicyDaemon = new FakeCarPowerPolicyDaemon();
mPowerComponentHandler = new PowerComponentHandler(mContext, mSystemInterface,
new AtomicFile(mComponentStateFile.getFile()));
mService = new CarPowerManagementService(mContext, mResources, mPowerHal, mSystemInterface,
mUserManager, mUserService, mPowerPolicyDaemon, mPowerComponentHandler,
mFileHwStateMonitoring.getFile().getPath(),
mFileKernelSilentMode.getFile().getPath(), NORMAL_BOOT);
CarLocalServices.addService(CarPowerManagementService.class, mService);
mService.init();
mService.setShutdownTimersForTest(0, 0);
mPowerHal.setSignalListener(mPowerSignalListener);
mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
assertStateReceived(MockedPowerHalService.SET_WAIT_FOR_VHAL, 0);
}
@Test
public void testShutdown() throws Exception {
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
assertThat(mService.garageModeShouldExitImmediately()).isFalse();
mDisplayInterface.waitForDisplayOff(WAIT_TIMEOUT_MS);
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
// Send the finished signal
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
@Test
public void testCanHibernate() throws Exception {
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_HIBERNATE));
assertThat(mService.garageModeShouldExitImmediately()).isFalse();
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_HIBERNATION_ENTRY);
mPowerSignalListener.waitFor(PowerHalService.SET_HIBERNATION_ENTRY, WAIT_TIMEOUT_MS);
verify(mUserService).onSuspend();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.setWakeupCausedByTimer(true);
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
assertStateReceived(PowerHalService.SET_HIBERNATION_EXIT, 0);
mPowerSignalListener.waitFor(PowerHalService.SET_HIBERNATION_EXIT, WAIT_TIMEOUT_MS);
}
@Test
public void testHibernateImmediately() throws Exception {
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.HIBERNATE_IMMEDIATELY));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_HIBERNATION_ENTRY, 0);
assertThat(mService.garageModeShouldExitImmediately()).isTrue();
mPowerSignalListener.waitFor(PowerHalService.SET_HIBERNATION_ENTRY, WAIT_TIMEOUT_MS);
verify(mUserService).onSuspend();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.setWakeupCausedByTimer(true);
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
assertStateReceived(PowerHalService.SET_HIBERNATION_EXIT, 0);
mPowerSignalListener.waitFor(PowerHalService.SET_HIBERNATION_EXIT, WAIT_TIMEOUT_MS);
}
@Test
public void testShutdownImmediately() throws Exception {
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY));
// Since modules have to manually schedule next wakeup, we should not schedule next wakeup
// To test module behavior, we need to actually implement mock listener module.
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, 0);
assertThat(mService.garageModeShouldExitImmediately()).isTrue();
mDisplayInterface.waitForDisplayOff(WAIT_TIMEOUT_MS);
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
// Send the finished signal
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
@Test
public void testSuspend() throws Exception {
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
// Request suspend
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
// Verify suspend
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
assertThat(mService.garageModeShouldExitImmediately()).isFalse();
}
@Test
public void testShutdownOnSuspend() throws Exception {
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
// Tell it to shutdown
mService.requestShutdownOnNextSuspend();
// Request suspend
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
// Verify shutdown
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
// Send the finished signal
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
// Cancel the shutdown
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_CANCELLED);
// Request suspend again
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
// Verify suspend
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
}
@Test
public void testShutdownCancel() throws Exception {
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
// Start shutting down
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, 0);
// Cancel the shutdown
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_CANCELLED);
// Go to suspend
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
}
@Test
public void testSleepImmediately() throws Exception {
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
assertThat(mService.garageModeShouldExitImmediately()).isTrue();
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_MS);
// Send the finished signal from HAL to CPMS
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
}
@Test
public void testShutdownWithProcessing() throws Exception {
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
// Send the finished signal
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
@Test
public void testSleepEntryAndWakeup() throws Exception {
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_MS);
// Send the finished signal from HAL to CPMS
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
}
@Test
public void testShutdownPostponeAfterSuspend() throws Exception {
grantPowerPolicyPermission();
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
mDisplayInterface.waitForDisplayOff(WAIT_TIMEOUT_MS);
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_MS);
// Send the finished signal
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.setWakeupCausedByTimer(true);
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
// Second processing after wakeup
assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
assertThat(mService.getCurrentPowerPolicy().getPolicyId())
.isEqualTo(SYSTEM_POWER_POLICY_INITIAL_ON);
mService.setStateForWakeUp();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mDisplayInterface.waitForDisplayOn(WAIT_TIMEOUT_MS);
// Should wait until Handler has finished ON processing
CarServiceUtils.runOnLooperSync(mService.getHandlerThread().getLooper(), () -> { });
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
// Should suspend within timeout
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_MS);
}
/**
* This test case tests the same scenario as {@link #testUserSwitchingOnResume_differentUser()},
* but indirectly triggering {@code switchUserOnResumeIfNecessary()} through HAL events.
*/
@Test
public void testSleepEntryAndWakeUpForProcessing() throws Exception {
mService.handleOn();
// Speed up the polling for power state transitions
mService.setShutdownTimersForTest(10, 40);
suspendAndResume();
}
@Test
public void testRegisterListenerWithCompletion() throws Exception {
grantAdjustShutdownProcessPermission();
SparseBooleanArray stateMapToCompletion = new SparseBooleanArray();
ICarPowerStateListener listenerRegistered = new ICarPowerStateListener.Stub() {
@Override
public void onStateChanged(int state, long expirationTimeMs) {
stateMapToCompletion.put(state, true);
if (CarPowerManagementService.isCompletionAllowed(state)) {
mService.finished(state, this);
}
}
};
mService.registerListenerWithCompletion(listenerRegistered);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
assertWithMessage("WAIT_FOR_VHAL notification").that(stateMapToCompletion
.get(CarPowerManager.STATE_WAIT_FOR_VHAL)).isFalse();
assertWithMessage("ON notification").that(stateMapToCompletion
.get(CarPowerManager.STATE_ON)).isTrue();
assertWithMessage("PRE_SHUTDOWN_PREPARE notification").that(stateMapToCompletion
.get(CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE)).isTrue();
assertWithMessage("SHUTDOWN_PREPARE notification").that(stateMapToCompletion
.get(CarPowerManager.STATE_SHUTDOWN_PREPARE)).isTrue();
assertWithMessage("SHUTDOWN_ENTER notification").that(stateMapToCompletion
.get(CarPowerManager.STATE_SHUTDOWN_ENTER)).isTrue();
assertWithMessage("POST_SHUTDOWN_ENTER notification").that(stateMapToCompletion
.get(CarPowerManager.STATE_POST_SHUTDOWN_ENTER)).isTrue();
}
@Test
public void testUnregisterListenerWithCompletion() throws Exception {
grantAdjustShutdownProcessPermission();
ICarPowerStateListener listenerUnregistered = new ICarPowerStateListener.Stub() {
@Override
public void onStateChanged(int state, long expirationTimeMs) {
fail("No notification should be sent to unregistered listener");
}
};
mService.registerListenerWithCompletion(listenerUnregistered);
mService.unregisterListener(listenerUnregistered);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
@Test
public void testShutdownPrepareWithCompletion_timeout() throws Exception {
grantAdjustShutdownProcessPermission();
// Shortens the timeout for listen completion
when(mResources.getInteger(R.integer.config_preShutdownPrepareTimeout))
.thenReturn(10);
mService.setShutdownTimersForTest(1000, 1000);
ICarPowerStateListener listener = new ICarPowerStateListener.Stub() {
@Override
public void onStateChanged(int state, long expirationTimeMs) {
// Does nothing to make timeout occur
}
};
mService.registerListenerWithCompletion(listener);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
// Power state should reach SHUTDOWN_ENTER because waiting for listeners to complete is done
// after timeout.
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS);
}
@Test
public void testFactoryResetOnResume() throws Exception {
ICarResultReceiver callback = mock(ICarResultReceiver.class);
mService.setFactoryResetCallback(callback);
// TODO: shouldn't need to expose handleOn() but rather emulate the steps as it's done on
// suspendAndResume(), but that method is making too many expectations that won't happen
// it's factory reset
mService.handleOn();
// Arguments don't matter
verify(callback).send(anyInt(), any());
}
@Test
public void testDefinePowerPolicyFromCommand() throws Exception {
String policyId = "policy_id_valid";
int status = mService.definePowerPolicy(policyId, new String[]{"AUDIO", "BLUETOOTH"},
new String[]{"WIFI"});
assertThat(status).isEqualTo(PolicyOperationStatus.OK);
assertThat(mPowerPolicyDaemon.getLastDefinedPolicyId()).isEqualTo(policyId);
status = mService.definePowerPolicy(policyId, new String[]{"AUDIO", "BLUTTOOTH"},
new String[]{"WIFI", "NFC"});
assertThat(status).isEqualTo(PolicyOperationStatus.ERROR_DEFINE_POWER_POLICY);
status = mService.definePowerPolicy(policyId, new String[]{"AUDIO", "INVALID_COMPONENT"},
new String[]{"WIFI"});
assertThat(status).isEqualTo(PolicyOperationStatus.ERROR_DEFINE_POWER_POLICY);
}
@Test
public void testApplyPowerPolicy() throws Exception {
grantPowerPolicyPermission();
String policyId = "policy_id_audio_off";
mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO"});
MockedPowerPolicyListener listenerToWait = new MockedPowerPolicyListener();
CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.AUDIO).build();
mService.addPowerPolicyListener(filterAudio, listenerToWait);
mService.applyPowerPolicy(policyId);
CarPowerPolicy policy = mService.getCurrentPowerPolicy();
assertThat(policy).isNotNull();
assertThat(policy.getPolicyId()).isEqualTo(policyId);
assertThat(mPowerComponentHandler.getAccumulatedPolicy().getPolicyId()).isEqualTo(policyId);
assertThat(listenerToWait.getCurrentPowerPolicy()).isNotNull();
assertThat(mPowerPolicyDaemon.getLastNotifiedPolicyId()).isEqualTo(policyId);
}
@Test
public void testApplyInvalidPowerPolicy() {
grantPowerPolicyPermission();
// Power policy which doesn't exist.
String policyId = "policy_id_not_available";
assertThrows(IllegalArgumentException.class, () -> mService.applyPowerPolicy(policyId));
}
@Test
public void testApplySystemPowerPolicyFromApps() {
grantPowerPolicyPermission();
String policyId = "system_power_policy_no_user_interaction";
assertThrows(IllegalArgumentException.class, () -> mService.applyPowerPolicy(policyId));
}
@Test
public void testDefinePowerPolicyGroupFromCommand() throws Exception {
String policyIdOne = "policy_id_valid1";
String policyIdTwo = "policy_id_valid2";
mService.definePowerPolicy(policyIdOne, new String[0], new String[0]);
mService.definePowerPolicy(policyIdTwo, new String[0], new String[0]);
String policyGroupId = "policy_group_id_valid";
String[] args = new String[]{"define-power-policy-group", policyGroupId,
"WaitForVHAL:policy_id_valid1", "On:policy_id_valid2"};
StringWriter stringWriter = new StringWriter();
try (IndentingPrintWriter writer = new IndentingPrintWriter(stringWriter, " ")) {
boolean isSuccess = mService.definePowerPolicyGroupFromCommand(args, writer);
assertThat(isSuccess).isTrue();
args = new String[]{"set-power-policy-group", policyGroupId};
isSuccess = mService.setPowerPolicyGroupFromCommand(args, writer);
assertThat(isSuccess).isTrue();
}
}
@Test
public void testDefinePowerPolicyGroupFromCommand_noPolicyDefined() throws Exception {
String policyGroupId = "policy_group_id_invalid";
String[] args = new String[]{"define-power-policy-group", policyGroupId,
"On:policy_id_not_exist"};
StringWriter stringWriter = new StringWriter();
try (IndentingPrintWriter writer = new IndentingPrintWriter(stringWriter, " ")) {
boolean isSuccess = mService.definePowerPolicyGroupFromCommand(args, writer);
assertThat(isSuccess).isFalse();
}
}
@Test
public void testDefinePowerPolicyGroupFromCommand_invalidStateName() throws Exception {
String policyId = "policy_id_valid";
mService.definePowerPolicy(policyId, new String[0], new String[0]);
String policyGroupId = "policy_group_id_invalid";
String[] args = new String[]{"define-power-policy-group", policyGroupId,
"InvalidStateName:policy_id_valid"};
StringWriter stringWriter = new StringWriter();
IndentingPrintWriter writer = new IndentingPrintWriter(stringWriter, " ");
boolean isSuccess = mService.definePowerPolicyGroupFromCommand(args, writer);
assertThat(isSuccess).isFalse();
writer.close();
}
@Test
public void testAddPowerPolicyListener() throws Exception {
grantPowerPolicyPermission();
String policyIdEnableAudioWifi = "policy_id_enable_audio_wifi";
MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
MockedPowerPolicyListener listenerWifi = new MockedPowerPolicyListener();
MockedPowerPolicyListener listenerLocation = new MockedPowerPolicyListener();
CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.AUDIO).build();
CarPowerPolicyFilter filterWifi = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.WIFI).build();
CarPowerPolicyFilter filterLocation = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.LOCATION).build();
mService.addPowerPolicyListener(filterAudio, listenerAudio);
mService.addPowerPolicyListener(filterWifi, listenerWifi);
String policyIdAllOff = "all_off";
mService.definePowerPolicy(policyIdAllOff, new String[]{},
new String[]{"AUDIO", "WIFI", "DISPLAY"});
mService.applyPowerPolicy(policyIdAllOff);
assertThat(mService.getCurrentPowerPolicy().isComponentEnabled(
PowerComponent.AUDIO)).isFalse();
assertThat(
mService.getCurrentPowerPolicy().isComponentEnabled(PowerComponent.WIFI)).isFalse();
assertThat(mService.getCurrentPowerPolicy().isComponentEnabled(
PowerComponent.DISPLAY)).isFalse();
mService.definePowerPolicy(policyIdEnableAudioWifi, new String[]{"AUDIO", "WIFI"},
new String[]{});
mService.applyPowerPolicy(policyIdEnableAudioWifi);
waitForPolicyId(listenerAudio, policyIdEnableAudioWifi,
"Current power policy of listenerAudio is not " + policyIdEnableAudioWifi);
assertThat(
mService.getCurrentPowerPolicy().isComponentEnabled(PowerComponent.AUDIO)).isTrue();
waitForPolicyId(listenerWifi, policyIdEnableAudioWifi,
"Current power policy of listenerWifi is not " + policyIdEnableAudioWifi);
assertThat(listenerLocation.getCurrentPowerPolicy()).isNull();
}
@Test
public void testRemovePowerPolicyListener() throws Exception {
grantPowerPolicyPermission();
String policyId = "policy_id_disable_audio";
mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO", "WIFI"});
MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
MockedPowerPolicyListener referenceListenerAudio = new MockedPowerPolicyListener();
CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.AUDIO).build();
mService.addPowerPolicyListener(filterAudio, listenerAudio);
mService.addPowerPolicyListener(filterAudio, referenceListenerAudio);
mService.removePowerPolicyListener(listenerAudio);
mService.applyPowerPolicy(policyId);
waitForPolicyId(referenceListenerAudio, policyId,
"Current power policy of referenceListenerAudio is not " + policyId);
assertThat(listenerAudio.getCurrentPowerPolicy()).isNull();
}
/**
* This test case increases the code coverage to cover methods
* {@code describeContents()} and {@code newArray()}. They are public APIs
* can not be marked out as BOILERPLATE_CODE.
*/
@Test
public void testParcelableCreation() throws Exception {
grantPowerPolicyPermission();
CarPowerPolicy policy = mService.getCurrentPowerPolicy();
assertThat(policy.describeContents()).isEqualTo(0);
CarPowerPolicy[] policies = CarPowerPolicy.CREATOR.newArray(1);
assertThat(policies.length).isEqualTo(1);
CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.AUDIO).build();
assertThat(filterAudio.describeContents()).isEqualTo(0);
CarPowerPolicyFilter[] filters = CarPowerPolicyFilter.CREATOR.newArray(1);
assertThat(filters.length).isEqualTo(1);
}
@Test
public void testPowerPolicyAfterShutdownCancel() throws Exception {
grantPowerPolicyPermission();
assertThat(mService.getCurrentPowerPolicy().getPolicyId())
.isEqualTo(SYSTEM_POWER_POLICY_INITIAL_ON);
mPowerHal.setCurrentPowerState(
new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, /* param= */ 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_CANCELLED);
mPowerSignalListener.waitFor(PowerHalService.SET_WAIT_FOR_VHAL, WAIT_TIMEOUT_MS);
assertThat(mService.getCurrentPowerPolicy().getPolicyId())
.isEqualTo(SYSTEM_POWER_POLICY_INITIAL_ON);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, /* param= */ 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_ON);
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
assertThat(mService.getCurrentPowerPolicy().getPolicyId())
.isEqualTo(SYSTEM_POWER_POLICY_ALL_ON);
}
@Test
public void testSuspendFailure() throws Exception {
suspendWithFailure(/* nextPowerState= */ null);
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
@Test
public void testSuspendFailureWithForbiddenTransition() throws Exception {
suspendWithFailure(/* nextPowerState= */ VehicleApPowerStateReq.ON);
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
@Test
public void testSuspendFailureWithAllowedTransition() throws Exception {
suspendWithFailure(/* nextPowerState= */ VehicleApPowerStateReq.CANCEL_SHUTDOWN);
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_CANCELLED, WAIT_TIMEOUT_MS);
}
@Test
public void testPowerPolicyOnSilentBoot() throws Exception {
grantPowerPolicyPermission();
mService.setSilentMode(SilentModeHandler.SILENT_MODE_FORCED_SILENT);
assertThat(mService.getCurrentPowerPolicy().getPolicyId())
.isEqualTo(SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, /* param= */ 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_ON);
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
assertThat(mService.getCurrentPowerPolicy().getPolicyId())
.isEqualTo(SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
mService.setSilentMode(SilentModeHandler.SILENT_MODE_FORCED_NON_SILENT);
assertThat(mService.getCurrentPowerPolicy().getPolicyId())
.isEqualTo(SYSTEM_POWER_POLICY_ALL_ON);
}
private void suspendWithFailure(Integer nextPowerState) throws Exception {
mSystemStateInterface.setSleepEntryResult(false);
mSystemStateInterface.setSimulateSleep(false);
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(
new PowerState(
VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
assertThat(mService.garageModeShouldExitImmediately()).isTrue();
mPowerSignalListener.waitFor(PowerHalService.SET_WAIT_FOR_VHAL, WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForDeepSleepEntry(WAIT_TIMEOUT_MS);
if (nextPowerState != null) {
mPowerHal.setCurrentPowerState(new PowerState(nextPowerState, 0));
}
}
private void suspendAndResume() throws Exception {
grantPowerPolicyPermission();
Log.d(TAG, "suspend()");
mVoiceInteractionEnabled = true;
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
mDisplayInterface.waitForDisplayOff(WAIT_TIMEOUT_MS);
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
assertVoiceInteractionDisabled();
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_MS);
verify(mUserService).onSuspend();
// Send the finished signal
Log.d(TAG, "resume()");
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.setWakeupCausedByTimer(true);
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
// second processing after wakeup
assertThat(mService.getCurrentPowerPolicy().getPolicyId()).isEqualTo(
SYSTEM_POWER_POLICY_INITIAL_ON);
assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
mFileHwStateMonitoring.write(NONSILENT_STRING); // Wake non-silently
mService.setStateForWakeUp();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
assertVoiceInteractionEnabled();
mDisplayInterface.waitForDisplayOn(WAIT_TIMEOUT_MS);
// Should wait until Handler has finished ON processing.
CarServiceUtils.runOnLooperSync(mService.getHandlerThread().getLooper(), () -> { });
verify(mUserService).onResume();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_MS);
verify(mUserService, times(2)).onSuspend();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
// PM will shutdown system as it was not woken-up due timer and it is not power on.
mSystemStateInterface.setWakeupCausedByTimer(false);
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
// Since we just woke up from shutdown, wake up time will be 0
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
}
private void assertStateReceived(int expectedState, int expectedParam) throws Exception {
int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_MS);
assertThat(state[0]).isEqualTo(expectedState);
assertThat(state[1]).isEqualTo(expectedParam);
}
private void assertStateReceivedForShutdownOrSleepWithPostpone(int lastState,
int expectedSecondParameter)
throws Exception {
while (true) {
if (mFuture != null && !mFuture.isDone()) {
mFuture.complete(null);
}
int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_LONG_MS);
if (state[0] == PowerHalService.SET_SHUTDOWN_POSTPONE) {
continue;
}
if (state[0] == lastState) {
assertThat(state[1]).isEqualTo(expectedSecondParameter);
return;
}
}
}
private void assertStateReceivedForShutdownOrSleepWithPostpone(int lastState) throws Exception {
int expectedSecondParameter =
(lastState == MockedPowerHalService.SET_DEEP_SLEEP_ENTRY
|| lastState == MockedPowerHalService.SET_SHUTDOWN_START
|| lastState == MockedPowerHalService.SET_HIBERNATION_ENTRY)
? WAKE_UP_DELAY : 0;
assertStateReceivedForShutdownOrSleepWithPostpone(lastState, expectedSecondParameter);
}
private void assertVoiceInteractionEnabled() throws Exception {
PollingCheck.check("Voice interaction is not enabled", WAIT_TIMEOUT_LONG_MS,
() -> {
return mVoiceInteractionEnabled;
});
}
private void assertVoiceInteractionDisabled() throws Exception {
PollingCheck.check("Voice interaction is not disabled", WAIT_TIMEOUT_LONG_MS,
() -> {
return !mVoiceInteractionEnabled;
});
}
private static void waitForPolicyId(MockedPowerPolicyListener listener, String policyId,
String errorMsg) throws Exception {
PollingCheck.check(errorMsg, WAIT_TIMEOUT_LONG_MS,
() -> {
CarPowerPolicy policy = listener.getCurrentPowerPolicy();
return policy != null && policyId.equals(policy.getPolicyId());
});
}
private static void waitForSemaphore(Semaphore semaphore, long timeoutMs)
throws InterruptedException {
if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
throw new IllegalStateException("timeout");
}
}
private UserInfo setCurrentUser(int userId, boolean isGuest) {
mockGetCurrentUser(userId);
final UserInfo userInfo = new UserInfo();
userInfo.id = userId;
userInfo.userType = isGuest
? UserManager.USER_TYPE_FULL_GUEST
: UserManager.USER_TYPE_FULL_SECONDARY;
Log.v(TAG, "UM.getUserInfo(" + userId + ") will return " + userInfo.toFullString());
when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
return userInfo;
}
private void grantPowerPolicyPermission() {
doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_CAR_POWER_POLICY);
doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
.checkCallingOrSelfPermission(Car.PERMISSION_READ_CAR_POWER_POLICY);
}
private void grantAdjustShutdownProcessPermission() {
doReturn(PackageManager.PERMISSION_GRANTED).when(mContext)
.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_SHUTDOWN_PROCESS);
}
private static final class MockDisplayInterface implements DisplayInterface {
private final Object mLock = new Object();
@GuardedBy("mLock")
private boolean mDisplayOn = true;
private final Semaphore mDisplayStateWait = new Semaphore(0);
@Override
public void init(CarPowerManagementService carPowerManagementService,
CarUserService carUserService) {}
@Override
public void setDisplayBrightness(int brightness) {}
@Override
public void setDisplayState(boolean on) {
synchronized (mLock) {
mDisplayOn = on;
}
mDisplayStateWait.release();
}
private void waitForDisplayOn(long timeoutMs) throws Exception {
waitForDisplayState(true, timeoutMs);
}
private void waitForDisplayOff(long timeoutMs) throws Exception {
waitForDisplayState(false, timeoutMs);
}
private void waitForDisplayState(boolean desiredState, long timeoutMs) throws Exception {
int nTries = 0;
while (true) {
synchronized (mLock) {
if (mDisplayOn == desiredState) {
break;
}
}
if (nTries > 5) throw new IllegalStateException("timeout");
waitForSemaphore(mDisplayStateWait, timeoutMs);
nTries++;
}
}
@Override
public void startDisplayStateMonitoring() {}
@Override
public void stopDisplayStateMonitoring() {}
@Override
public void refreshDisplayBrightness() {}
@Override
public boolean isDisplayEnabled() {
synchronized (mLock) {
return mDisplayOn;
}
}
}
private static final class MockSystemStateInterface implements SystemStateInterface {
private final Semaphore mShutdownWait = new Semaphore(0);
private final Semaphore mSleepWait = new Semaphore(0);
private final Semaphore mSleepExitWait = new Semaphore(0);
private boolean mSleepEntryResult = true;
private boolean mSimulateSleep = true;
private boolean mWakeupCausedByTimer = false;
@Override
public void shutdown() {
mShutdownWait.release();
}
public void waitForShutdown(long timeoutMs) throws Exception {
waitForSemaphore(mShutdownWait, timeoutMs);
}
@Override
public boolean enterDeepSleep() {
if (mSimulateSleep) {
return simulateSleep();
}
mSleepWait.release();
return mSleepEntryResult;
}
@Override
public boolean enterHibernation() {
return simulateSleep();
}
private boolean simulateSleep() {
mSleepWait.release();
try {
mSleepExitWait.tryAcquire(WAIT_TIMEOUT_MS , TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
return mSleepEntryResult;
}
public void waitForSleepEntryAndWakeup(long timeoutMs) throws Exception {
waitForSemaphore(mSleepWait, timeoutMs);
mSleepExitWait.release();
}
@Override
public void scheduleActionForBootCompleted(Runnable action, Duration delay) {}
@Override
public boolean isWakeupCausedByTimer() {
Log.i(TAG, "isWakeupCausedByTimer:" + mWakeupCausedByTimer);
return mWakeupCausedByTimer;
}
public synchronized void setWakeupCausedByTimer(boolean set) {
mWakeupCausedByTimer = set;
}
@Override
public boolean isSystemSupportingDeepSleep() {
return true;
}
@Override
public boolean isSystemSupportingHibernation() {
return true;
}
public void setSleepEntryResult(boolean sleepEntryResult) {
mSleepEntryResult = sleepEntryResult;
}
public void setSimulateSleep(boolean simulateSleep) {
mSimulateSleep = simulateSleep;
}
public void waitForDeepSleepEntry(long waitTimeoutMs) throws InterruptedException {
waitForSemaphore(mSleepWait, waitTimeoutMs);
}
}
private static final class MockWakeLockInterface implements WakeLockInterface {
@Override
public void releaseAllWakeLocks() {}
@Override
public void switchToPartialWakeLock() {}
@Override
public void switchToFullWakeLock() {}
}
private static final class MockIOInterface implements IOInterface {
private TemporaryDirectory mFilesDir;
@Override
public File getSystemCarDir() {
if (mFilesDir == null) {
try {
mFilesDir = new TemporaryDirectory(TAG);
} catch (IOException e) {
Log.e(TAG, "failed to create temporary directory", e);
fail("failed to create temporary directory. exception was: " + e);
}
}
return mFilesDir.getDirectory();
}
public void tearDown() {
if (mFilesDir != null) {
try {
mFilesDir.close();
} catch (Exception e) {
Log.w(TAG, "could not remove temporary directory", e);
}
}
}
}
private class PowerSignalListener implements MockedPowerHalService.SignalListener {
private final SparseArray<Semaphore> mSemaphores;
private PowerSignalListener() {
mSemaphores = new SparseArray<>();
mSemaphores.put(PowerHalService.SET_ON, new Semaphore(0));
mSemaphores.put(PowerHalService.SET_SHUTDOWN_START, new Semaphore(0));
mSemaphores.put(PowerHalService.SET_DEEP_SLEEP_ENTRY, new Semaphore(0));
mSemaphores.put(PowerHalService.SET_DEEP_SLEEP_EXIT, new Semaphore(0));
mSemaphores.put(PowerHalService.SET_WAIT_FOR_VHAL, new Semaphore(0));
mSemaphores.put(PowerHalService.SET_SHUTDOWN_CANCELLED, new Semaphore(0));
mSemaphores.put(PowerHalService.SET_HIBERNATION_ENTRY, new Semaphore(0));
mSemaphores.put(PowerHalService.SET_HIBERNATION_EXIT, new Semaphore(0));
}
public void waitFor(int signal, long timeoutMs) throws Exception {
Semaphore semaphore = mSemaphores.get(signal);
if (semaphore == null) {
throw new IllegalArgumentException("no semaphore registered for event = " + signal);
}
waitForSemaphore(semaphore, timeoutMs);
}
@Override
public void sendingSignal(int signal) {
Semaphore semaphore = mSemaphores.get(signal);
if (semaphore == null) {
return;
}
semaphore.release();
}
}
static final class FakeCarPowerPolicyDaemon extends ICarPowerPolicySystemNotification.Stub {
private String mLastNotifiedPolicyId;
private String mLastDefinedPolicyId;
@Override
public PolicyState notifyCarServiceReady() {
// do nothing
return null;
}
@Override
public void notifyPowerPolicyChange(String policyId, boolean force) {
mLastNotifiedPolicyId = policyId;
}
@Override
public void notifyPowerPolicyDefinition(String policyId, String[] enabledComponents,
String[] disabledComponents) {
mLastDefinedPolicyId = policyId;
}
public String getLastNotifiedPolicyId() {
return mLastNotifiedPolicyId;
}
public String getLastDefinedPolicyId() {
return mLastDefinedPolicyId;
}
@Override
public String getInterfaceHash() {
return ICarPowerPolicySystemNotification.HASH;
}
@Override
public int getInterfaceVersion() {
return ICarPowerPolicySystemNotification.VERSION;
}
}
private final class MockedPowerPolicyListener extends ICarPowerPolicyListener.Stub {
private final Object mLock = new Object();
private CarPowerPolicy mCurrentPowerPolicy;
@Override
public void onPolicyChanged(CarPowerPolicy appliedPolicy,
CarPowerPolicy accumulatedPolicy) {
synchronized (mLock) {
mCurrentPowerPolicy = accumulatedPolicy;
}
}
@Nullable
public CarPowerPolicy getCurrentPowerPolicy() throws Exception {
synchronized (mLock) {
return mCurrentPowerPolicy;
}
}
}
}