1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.test; 18 19 import android.test.AndroidTestCase; 20 import android.util.Log; 21 22 import com.android.car.CarPowerManagementService; 23 import com.android.car.CarPowerManagementService.PowerEventProcessingHandler; 24 import com.android.car.CarPowerManagementService.PowerServiceEventListener; 25 import com.android.car.hal.PowerHalService; 26 import com.android.car.hal.PowerHalService.PowerState; 27 28 import java.util.concurrent.Semaphore; 29 import java.util.concurrent.TimeUnit; 30 31 public class CarPowerManagementServiceTest extends AndroidTestCase { 32 private static final String TAG = CarPowerManagementServiceTest.class.getSimpleName(); 33 private static final long WAIT_TIMEOUT_MS = 2000; 34 private static final long WAIT_TIMEOUT_LONG_MS = 5000; 35 private MockedPowerHalService mPowerHal; 36 private SystemIntefaceImpl mSystemInterface; 37 private CarPowerManagementService mService; 38 private final PowerEventListener mPowerEventListener = new PowerEventListener(); 39 private PowerEventProcessingHandlerImpl mPowerEventProcessingHandler; 40 41 @Override 42 protected void setUp() throws Exception { 43 super.setUp(); 44 mPowerHal = new MockedPowerHalService(true /*isPowerStateSupported*/, 45 true /*isDeepSleepAllowed*/, true /*isTimedWakeupAllowed*/); 46 mSystemInterface = new SystemIntefaceImpl(); 47 } 48 49 @Override 50 protected void tearDown() throws Exception { 51 super.tearDown(); 52 if (mService != null) { 53 mService.release(); 54 } 55 } 56 57 public void testBootComplete() throws Exception { 58 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 59 mService.init(); 60 mService.registerPowerEventListener(mPowerEventListener); 61 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(0, 0); 62 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 63 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 64 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 65 } 66 67 public void testDisplayOff() throws Exception { 68 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 69 mService.init(); 70 mService.registerPowerEventListener(mPowerEventListener); 71 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(0, 0); 72 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 73 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 74 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 75 // it will call display on for initial state 76 assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 77 mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_ON_DISP_OFF, 0)); 78 assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 79 } 80 81 public void testDisplayOn() throws Exception { 82 // start with display off 83 mSystemInterface.setDisplayState(false); 84 mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS); 85 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 86 mService.init(); 87 mService.registerPowerEventListener(mPowerEventListener); 88 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(0, 0); 89 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 90 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 91 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 92 93 // display should be turned on as it started with off state. 94 assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 95 } 96 97 public void testShutdown() throws Exception { 98 final int wakeupTime = 100; 99 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 100 mService.init(); 101 mService.registerPowerEventListener(mPowerEventListener); 102 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(0, wakeupTime); 103 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 104 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 105 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 106 assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 107 108 mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, 109 PowerHalService.FLAG_SHUTDOWN_IMMEDIATELY)); 110 assertStateReceived(PowerHalService.SET_SHUTDOWN_START, wakeupTime); 111 assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 112 mPowerEventListener.waitForShutdown(WAIT_TIMEOUT_MS); 113 mSystemInterface.waitForShutdown(WAIT_TIMEOUT_MS); 114 } 115 116 public void testShutdownWithProcessing() throws Exception { 117 final long processingTimeMs = 3000; 118 final int wakeupTime = 100; 119 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 120 mService.init(); 121 mService.registerPowerEventListener(mPowerEventListener); 122 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(processingTimeMs, 123 wakeupTime); 124 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 125 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 126 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 127 assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 128 129 mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, 0)); 130 mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); 131 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, 132 WAIT_TIMEOUT_LONG_MS, wakeupTime); 133 assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 134 mPowerEventListener.waitForShutdown(WAIT_TIMEOUT_MS); 135 mSystemInterface.waitForShutdown(WAIT_TIMEOUT_MS); 136 } 137 138 public void testSleepEntryAndWakeup() throws Exception { 139 final int wakeupTime = 100; 140 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 141 mService.init(); 142 mService.registerPowerEventListener(mPowerEventListener); 143 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(0, wakeupTime); 144 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 145 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 146 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 147 assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 148 149 mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, 150 PowerHalService.FLAG_SHUTDOWN_PARAM_CAN_SLEEP)); 151 assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 152 assertStateReceived(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0); 153 mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); 154 int wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); 155 assertEquals(wakeupTime, wakeupTimeReceived); 156 assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); 157 mPowerEventListener.waitForSleepExit(WAIT_TIMEOUT_MS); 158 159 } 160 161 public void testSleepEntryAndPowerOnWithProcessing() throws Exception { 162 final long processingTimeMs = 3000; 163 final int wakeupTime = 100; 164 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 165 mService.init(); 166 mService.registerPowerEventListener(mPowerEventListener); 167 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(processingTimeMs, 168 wakeupTime); 169 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 170 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 171 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 172 assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 173 174 mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, 175 PowerHalService.FLAG_SHUTDOWN_PARAM_CAN_SLEEP)); 176 mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); 177 assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 178 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 179 WAIT_TIMEOUT_LONG_MS, 0); 180 mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); 181 // set power on here without notification. PowerManager should check the state after sleep 182 // exit 183 mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_ON_DISP_OFF, 0), false); 184 int wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); 185 assertEquals(wakeupTime, wakeupTimeReceived); 186 assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); 187 mPowerEventListener.waitForSleepExit(WAIT_TIMEOUT_MS); 188 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 189 } 190 191 public void testSleepEntryAndWakeUpForProcessing() throws Exception { 192 final long processingTimeMs = 3000; 193 final int wakeupTime = 100; 194 mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface); 195 mService.init(); 196 mService.registerPowerEventListener(mPowerEventListener); 197 mPowerEventProcessingHandler = new PowerEventProcessingHandlerImpl(processingTimeMs, 198 wakeupTime); 199 mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); 200 assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); 201 mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); 202 assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 203 204 mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, 205 PowerHalService.FLAG_SHUTDOWN_PARAM_CAN_SLEEP)); 206 mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); 207 assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); 208 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 209 WAIT_TIMEOUT_LONG_MS, 0); 210 mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); 211 mSystemInterface.setWakeupCausedByTimer(true); 212 int wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); 213 assertEquals(wakeupTime, wakeupTimeReceived); 214 assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); 215 mPowerEventListener.waitForSleepExit(WAIT_TIMEOUT_MS); 216 // second processing after wakeup 217 assertFalse(mSystemInterface.getDisplayState()); 218 mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); 219 assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 220 WAIT_TIMEOUT_LONG_MS, 0); 221 mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); 222 // PM will shutdown system as it was not woken-up due to timer and it is not power on. 223 mSystemInterface.setWakeupCausedByTimer(false); 224 wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); 225 assertEquals(wakeupTime, wakeupTimeReceived); 226 assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); 227 assertStateReceived(PowerHalService.SET_SHUTDOWN_START, wakeupTime); 228 mPowerEventListener.waitForShutdown(WAIT_TIMEOUT_MS); 229 mSystemInterface.waitForShutdown(WAIT_TIMEOUT_MS); 230 assertFalse(mSystemInterface.getDisplayState()); 231 } 232 233 private void assertStateReceived(int expectedState, int expectedParam) throws Exception { 234 int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_MS); 235 assertEquals(expectedState, state[0]); 236 assertEquals(expectedParam, state[1]); 237 } 238 239 private void assertStateReceivedForShutdownOrSleepWithPostpone(int lastState, long timeoutMs, 240 int expectedParamForShutdown) throws Exception { 241 while (true) { 242 int[] state = mPowerHal.waitForSend(timeoutMs); 243 if (state[0] == PowerHalService.SET_SHUTDOWN_POSTPONE) { 244 continue; 245 } 246 if (state[0] == lastState) { 247 assertEquals(expectedParamForShutdown, state[1]); 248 return; 249 } 250 } 251 } 252 253 private static void waitForSemaphore(Semaphore semaphore, long timeoutMs) 254 throws InterruptedException { 255 if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 256 throw new IllegalStateException("timeout"); 257 } 258 } 259 260 private class SystemIntefaceImpl implements CarPowerManagementService.SystemInteface { 261 262 private boolean mDisplayOn = true; 263 private final Semaphore mDisplayStateWait = new Semaphore(0); 264 private final Semaphore mShutdownWait = new Semaphore(0); 265 private final Semaphore mSleepWait = new Semaphore(0); 266 private final Semaphore mSleepExitWait = new Semaphore(0); 267 private int mWakeupTime; 268 private boolean mWakeupCausedByTimer = false; 269 270 @Override 271 public synchronized void setDisplayState(boolean on) { 272 Log.i(TAG, "SystemIntefaceImpl.setDisplayState " + on); 273 mDisplayOn = on; 274 mDisplayStateWait.release(); 275 } 276 277 public synchronized boolean getDisplayState() { 278 return mDisplayOn; 279 } 280 281 public boolean waitForDisplayStateChange(long timeoutMs) throws Exception { 282 waitForSemaphore(mDisplayStateWait, timeoutMs); 283 return mDisplayOn; 284 } 285 286 @Override 287 public void releaseAllWakeLocks() { 288 } 289 290 @Override 291 public void shutdown() { 292 mShutdownWait.release(); 293 } 294 295 public void waitForShutdown(long timeoutMs) throws Exception { 296 waitForSemaphore(mShutdownWait, timeoutMs); 297 } 298 299 @Override 300 public void enterDeepSleep(int wakeupTimeSec) { 301 mWakeupTime = wakeupTimeSec; 302 mSleepWait.release(); 303 try { 304 mSleepExitWait.acquire(); 305 } catch (InterruptedException e) { 306 } 307 } 308 309 @Override 310 public boolean isSystemSupportingDeepSleep() { 311 return true; 312 } 313 314 public int waitForSleepEntryAndWakeup(long timeoutMs) throws Exception { 315 waitForSemaphore(mSleepWait, timeoutMs); 316 mSleepExitWait.release(); 317 return mWakeupTime; 318 } 319 320 @Override 321 public void switchToPartialWakeLock() { 322 } 323 324 @Override 325 public void switchToFullWakeLock() { 326 } 327 328 @Override 329 public void startDisplayStateMonitoring(CarPowerManagementService service) { 330 } 331 332 @Override 333 public void stopDisplayStateMonitoring() { 334 } 335 336 @Override 337 public synchronized boolean isWakeupCausedByTimer() { 338 Log.i(TAG, "isWakeupCausedByTimer:" + mWakeupCausedByTimer); 339 return mWakeupCausedByTimer; 340 } 341 342 public synchronized void setWakeupCausedByTimer(boolean set) { 343 mWakeupCausedByTimer = set; 344 } 345 } 346 347 private class PowerEventListener implements PowerServiceEventListener { 348 private final Semaphore mShutdownWait = new Semaphore(0); 349 private final Semaphore mSleepEntryWait = new Semaphore(0); 350 private final Semaphore mSleepExitWait = new Semaphore(0); 351 352 @Override 353 public void onShutdown() { 354 mShutdownWait.release(); 355 } 356 357 public void waitForShutdown(long timeoutMs) throws Exception { 358 waitForSemaphore(mShutdownWait, timeoutMs); 359 } 360 361 @Override 362 public void onSleepEntry() { 363 mSleepEntryWait.release(); 364 } 365 366 public void waitForSleepEntry(long timeoutMs) throws Exception { 367 waitForSemaphore(mSleepEntryWait, timeoutMs); 368 } 369 370 @Override 371 public void onSleepExit() { 372 mSleepExitWait.release(); 373 } 374 375 public void waitForSleepExit(long timeoutMs) throws Exception { 376 waitForSemaphore(mSleepExitWait, timeoutMs); 377 } 378 } 379 380 private class PowerEventProcessingHandlerImpl implements PowerEventProcessingHandler { 381 private final long mProcessingTime; 382 private final int mWakeupTime; 383 private final Semaphore mPrepareShutdownWait = new Semaphore(0); 384 private final Semaphore mOnPowerOnWait = new Semaphore(0); 385 private boolean mShuttingDown; 386 private boolean mDisplayOn; 387 388 private PowerEventProcessingHandlerImpl(long processingTime, int wakeupTime) { 389 mProcessingTime = processingTime; 390 mWakeupTime = wakeupTime; 391 } 392 393 @Override 394 public long onPrepareShutdown(boolean shuttingDown) { 395 mShuttingDown = shuttingDown; 396 mPrepareShutdownWait.release(); 397 return mProcessingTime; 398 } 399 public boolean waitForPrepareShutdown(long timeoutMs) throws Exception { 400 waitForSemaphore(mPrepareShutdownWait, timeoutMs); 401 return mShuttingDown; 402 } 403 404 @Override 405 public void onPowerOn(boolean displayOn) { 406 mDisplayOn = displayOn; 407 mOnPowerOnWait.release(); 408 } 409 410 public boolean waitForPowerOn(long timeoutMs) throws Exception { 411 waitForSemaphore(mOnPowerOnWait, timeoutMs); 412 return mDisplayOn; 413 } 414 415 @Override 416 public int getWakeupTime() { 417 return mWakeupTime; 418 } 419 } 420 } 421