blob: e748cc2ffd9f145ece7e6159caa7e2b529d81464 [file] [log] [blame]
keunyoung4b0212c2015-10-29 17:11:57 -07001/*
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 */
16package com.android.car;
17
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080018import android.annotation.NonNull;
keunyoung4b0212c2015-10-29 17:11:57 -070019import android.content.Context;
20import android.hardware.display.DisplayManager;
21import android.os.Handler;
22import android.os.HandlerThread;
23import android.os.Looper;
24import android.os.Message;
25import android.os.PowerManager;
26import android.os.PowerManager.WakeLock;
27import android.os.SystemClock;
Pavel Maltsev75623ce2016-01-20 16:02:59 -080028import android.support.car.CarSystemTest;
keunyoung4b0212c2015-10-29 17:11:57 -070029import android.util.Log;
30import android.view.Display;
31
32import com.android.car.hal.PowerHalService;
33import com.android.car.hal.PowerHalService.PowerState;
34import com.android.car.hal.VehicleHal;
35import com.android.internal.annotations.GuardedBy;
Yao Chendacd7242016-01-26 14:42:42 -080036import com.android.internal.annotations.VisibleForTesting;
keunyoung4b0212c2015-10-29 17:11:57 -070037
38import java.io.PrintWriter;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080039import java.util.LinkedList;
keunyoung4b0212c2015-10-29 17:11:57 -070040import java.util.Timer;
41import java.util.TimerTask;
42import java.util.concurrent.CopyOnWriteArrayList;
43
44public class CarPowerManagementService implements CarServiceBase,
45 PowerHalService.PowerEventListener {
46
47 /**
48 * Listener for other services to monitor power events.
49 */
50 public interface PowerServiceEventListener {
51 /**
52 * Shutdown is happening
53 */
54 void onShutdown();
55
56 /**
57 * Entering deep sleep.
58 */
59 void onSleepEntry();
60
61 /**
62 * Got out of deep sleep.
63 */
64 void onSleepExit();
65 }
66
67 /**
68 * Interface for components requiring processing time before shutting-down or
69 * entering sleep, and wake-up after shut-down.
70 */
71 public interface PowerEventProcessingHandler {
72 /**
73 * Called before shutdown or sleep entry to allow running some processing. This call
74 * should only queue such task in different thread and should return quickly.
75 * Blocking inside this call can trigger watchdog timer which can terminate the
76 * whole system.
77 * @param shuttingDown whether system is shutting down or not (= sleep entry).
78 * @return time necessary to run processing in ms. should return 0 if there is no
79 * processing necessary.
80 */
Keun-young Park303ea1d2016-01-21 11:26:16 -080081 long onPrepareShutdown(boolean shuttingDown);
82
83 /**
84 * Called when power state is changed to ON state. Display can be either on or off.
85 * @param displayOn
86 */
87 void onPowerOn(boolean displayOn);
keunyoung4b0212c2015-10-29 17:11:57 -070088
89 /**
90 * Returns wake up time after system is fully shutdown. Power controller will power on
91 * the system after this time. This power on is meant for regular maintenance kind of
92 * operation.
93 * @return 0 of wake up is not necessary.
94 */
95 int getWakeupTime();
96 }
97
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080098 /** Interface to abstract all system interaction. Separated for testing. */
99 public interface SystemInteface {
100 void setDisplayState(boolean on);
101 void releaseAllWakeLocks();
102 void shutdown();
103 void enterDeepSleep(int wakeupTimeSec);
104 void switchToPartialWakeLock();
105 void switchToFullWakeLock();
106 void startDisplayStateMonitoring(CarPowerManagementService service);
107 void stopDisplayStateMonitoring();
108 boolean isSystemSupportingDeepSleep();
109 boolean isWakeupCausedByTimer();
110 }
111
keunyoung4b0212c2015-10-29 17:11:57 -0700112 private final Context mContext;
113 private final PowerHalService mHal;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800114 private final SystemInteface mSystemInterface;
keunyoung4b0212c2015-10-29 17:11:57 -0700115 private final HandlerThread mHandlerThread;
116 private final PowerHandler mHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800117
keunyoung4b0212c2015-10-29 17:11:57 -0700118 private final CopyOnWriteArrayList<PowerServiceEventListener> mListeners =
119 new CopyOnWriteArrayList<>();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800120 private final CopyOnWriteArrayList<PowerEventProcessingHandlerWrapper>
121 mPowerEventProcessingHandlers = new CopyOnWriteArrayList<>();
122
123 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700124 private PowerState mCurrentState;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800125 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700126 private Timer mTimer;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800127 @GuardedBy("this")
128 private long mProcessingStartTime;
129 @GuardedBy("this")
130 private long mLastSleepEntryTime;
131 @GuardedBy("this")
132 private final LinkedList<PowerState> mPendingPowerStates = new LinkedList<>();
keunyoung4b0212c2015-10-29 17:11:57 -0700133
134 private final int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
135 private final int SHUTDOWN_EXTEND_MAX_MS = 5000;
136
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800137 /**
138 * Constructor for full functionality.
139 */
140 public CarPowerManagementService(@NonNull Context context) {
141 this(context, VehicleHal.getInstance().getPowerHal(),
142 new SystemIntefaceImpl(context));
keunyoung4b0212c2015-10-29 17:11:57 -0700143 }
144
Yao Chendacd7242016-01-26 14:42:42 -0800145 /**
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800146 * Constructor for full functionality. Can inject external interfaces
147 */
148 public CarPowerManagementService(@NonNull Context context, @NonNull PowerHalService powerHal,
149 @NonNull SystemInteface systemInterface) {
150 mContext = context;
151 mHal = powerHal;
152 mSystemInterface = systemInterface;
153 mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
154 mHandlerThread.start();
155 mHandler = new PowerHandler(mHandlerThread.getLooper());
156 }
157
158 /**
159 * Create a dummy instance for unit testing purpose only. Instance constructed in this way
160 * is not safe as members expected to be non-null are null.
Yao Chendacd7242016-01-26 14:42:42 -0800161 */
162 @VisibleForTesting
163 protected CarPowerManagementService() {
164 mContext = null;
165 mHal = null;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800166 mSystemInterface = null;
Yao Chendacd7242016-01-26 14:42:42 -0800167 mHandlerThread = null;
Keun-young Parkca013ae2016-02-10 16:22:25 -0800168 mHandler = new PowerHandler(Looper.getMainLooper());
Yao Chendacd7242016-01-26 14:42:42 -0800169 }
170
keunyoung4b0212c2015-10-29 17:11:57 -0700171 @Override
172 public void init() {
173 mHal.setListener(this);
174 if (mHal.isPowerStateSupported()) {
175 mHal.sendBootComplete();
176 PowerState currentState = mHal.getCurrentPowerState();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800177 onApPowerStateChange(currentState);
keunyoung4b0212c2015-10-29 17:11:57 -0700178 } else {
179 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet.");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800180 mSystemInterface.switchToFullWakeLock();
keunyoung4b0212c2015-10-29 17:11:57 -0700181 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800182 mSystemInterface.startDisplayStateMonitoring(this);
keunyoung4b0212c2015-10-29 17:11:57 -0700183 }
184
185 @Override
186 public void release() {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800187 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700188 releaseTimerLocked();
189 mCurrentState = null;
190 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800191 mSystemInterface.stopDisplayStateMonitoring();
keunyoung4b0212c2015-10-29 17:11:57 -0700192 mHandler.cancelAll();
193 mListeners.clear();
Keun-young Park303ea1d2016-01-21 11:26:16 -0800194 mPowerEventProcessingHandlers.clear();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800195 mSystemInterface.releaseAllWakeLocks();
keunyoung4b0212c2015-10-29 17:11:57 -0700196 }
197
198 /**
199 * Register listener to monitor power event. There is no unregister counter-part and the list
200 * will be cleared when the service is released.
201 * @param listener
202 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800203 public synchronized void registerPowerEventListener(PowerServiceEventListener listener) {
keunyoung4b0212c2015-10-29 17:11:57 -0700204 mListeners.add(listener);
205 }
206
207 /**
208 * Register PowerEventPreprocessingHandler to run pre-processing before shutdown or
209 * sleep entry. There is no unregister counter-part and the list
210 * will be cleared when the service is released.
211 * @param handler
212 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800213 public synchronized void registerPowerEventProcessingHandler(
214 PowerEventProcessingHandler handler) {
215 mPowerEventProcessingHandlers.add(new PowerEventProcessingHandlerWrapper(handler));
216 // onPowerOn will not be called if power on notification is already done inside the
217 // handler thread. So request it once again here. Wrapper will have its own
218 // gatekeeping to prevent calling onPowerOn twice.
219 mHandler.handlePowerOn();
keunyoung4b0212c2015-10-29 17:11:57 -0700220 }
221
222 /**
223 * Notifies earlier completion of power event processing. PowerEventProcessingHandler quotes
224 * time necessary from onPrePowerEvent() call, but actual processing can finish earlier than
225 * that, and this call can be called in such case to trigger shutdown without waiting further.
226 *
227 * @param handler PowerEventProcessingHandler that was already registered with
228 * {@link #registerPowerEventListener(PowerServiceEventListener)} call. If it was not
229 * registered before, this call will be ignored.
230 */
231 public void notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800232 long processingTime = 0;
233 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
234 if (wrapper.handler == handler) {
235 wrapper.markProcessingDone();
236 } else if (!wrapper.isProcessingDone()) {
237 processingTime = Math.max(processingTime, wrapper.getProcessingTime());
238 }
239 }
240 long now = SystemClock.elapsedRealtime();
241 long startTime;
242 boolean shouldShutdown = true;
243 synchronized (this) {
244 startTime = mProcessingStartTime;
245 if (mCurrentState == null) {
246 return;
247 }
248 if (mCurrentState.state != PowerHalService.STATE_SHUTDOWN_PREPARE) {
249 return;
250 }
251 if (mCurrentState.canEnterDeepSleep()) {
252 shouldShutdown = false;
253 if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < now) {
254 // already slept
255 return;
256 }
257 }
258 }
259 if ((startTime + processingTime) <= now) {
260 Log.i(CarLog.TAG_POWER, "Processing all done");
261 mHandler.handleProcessingComplete(shouldShutdown);
262 }
keunyoung4b0212c2015-10-29 17:11:57 -0700263 }
264
265 @Override
266 public void dump(PrintWriter writer) {
267 writer.println("*PowerManagementService*");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800268 writer.print("mCurrentState:" + mCurrentState);
269 writer.print(",mProcessingStartTime:" + mProcessingStartTime);
270 writer.println(",mLastSleepEntryTime:" + mLastSleepEntryTime);
271 writer.println("**PowerEventProcessingHandlers");
272 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
273 writer.println(wrapper.toString());
274 }
keunyoung4b0212c2015-10-29 17:11:57 -0700275 }
276
277 @Override
278 public void onApPowerStateChange(PowerState state) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800279 synchronized (this) {
280 mPendingPowerStates.addFirst(state);
281 }
282 mHandler.handlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700283 }
284
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800285 private void doHandlePowerStateChange() {
286 PowerState state = null;
287 synchronized (this) {
288 state = mPendingPowerStates.peekFirst();
289 mPendingPowerStates.clear();
290 if (state == null) {
291 return;
292 }
293 if (!needPowerStateChange(state)) {
294 return;
295 }
296 // now real power change happens. Whatever was queued before should be all cancelled.
297 releaseTimerLocked();
298 mHandler.cancelProcessingComplete();
keunyoung4b0212c2015-10-29 17:11:57 -0700299 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800300
keunyoung4b0212c2015-10-29 17:11:57 -0700301 Log.i(CarLog.TAG_POWER, "Power state change:" + state);
302 switch (state.state) {
303 case PowerHalService.STATE_ON_DISP_OFF:
304 handleDisplayOff(state);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800305 notifyPowerOn(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700306 break;
307 case PowerHalService.STATE_ON_FULL:
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800308 handleFullOn(state);
309 notifyPowerOn(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700310 break;
311 case PowerHalService.STATE_SHUTDOWN_PREPARE:
312 handleShutdownPrepare(state);
313 break;
314 }
315 }
316
317 private void handleDisplayOff(PowerState newState) {
318 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800319 mSystemInterface.setDisplayState(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700320 }
321
322 private void handleFullOn(PowerState newState) {
323 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800324 mSystemInterface.setDisplayState(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700325 }
326
Yao Chendacd7242016-01-26 14:42:42 -0800327 @VisibleForTesting
328 protected void notifyPowerOn(boolean displayOn) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800329 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
330 wrapper.callOnPowerOn(displayOn);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800331 }
332 }
333
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800334 @VisibleForTesting
335 protected long notifyPrepareShutdown(boolean shuttingDown) {
336 long processingTimeMs = 0;
337 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
338 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
339 if (handlerProcessingTime > processingTimeMs) {
340 processingTimeMs = handlerProcessingTime;
341 }
342 }
343 return processingTimeMs;
344 }
345
keunyoung4b0212c2015-10-29 17:11:57 -0700346 private void handleShutdownPrepare(PowerState newState) {
347 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800348 mSystemInterface.setDisplayState(false);;
keunyoung4b0212c2015-10-29 17:11:57 -0700349 boolean shouldShutdown = true;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800350 if (mHal.isDeepSleepAllowed() && mSystemInterface.isSystemSupportingDeepSleep() &&
keunyoung4b0212c2015-10-29 17:11:57 -0700351 newState.canEnterDeepSleep()) {
352 Log.i(CarLog.TAG_POWER, "starting sleep");
353 shouldShutdown = false;
354 doHandlePreprocessing(shouldShutdown);
355 return;
356 } else if (newState.canPostponeShutdown()) {
357 Log.i(CarLog.TAG_POWER, "starting shutdown with processing");
358 doHandlePreprocessing(shouldShutdown);
359 } else {
360 Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800361 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700362 releaseTimerLocked();
363 }
364 doHandleShutdown();
365 }
366 }
367
368 private void releaseTimerLocked() {
369 if (mTimer != null) {
370 mTimer.cancel();
371 }
372 mTimer = null;
373 }
374
375 private void doHandlePreprocessing(boolean shuttingDown) {
376 long processingTimeMs = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800377 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
378 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
379 if (handlerProcessingTime > 0) {
380 wrapper.setProcessingTimeAndResetProcessingDone(handlerProcessingTime);
381 }
keunyoung4b0212c2015-10-29 17:11:57 -0700382 if (handlerProcessingTime > processingTimeMs) {
383 processingTimeMs = handlerProcessingTime;
384 }
385 }
386 if (processingTimeMs > 0) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800387 int pollingCount = (int)(processingTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
keunyoung4b0212c2015-10-29 17:11:57 -0700388 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for :" + processingTimeMs +
389 " ms, adding polling:" + pollingCount);
390 synchronized (this) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800391 mProcessingStartTime = SystemClock.elapsedRealtime();
keunyoung4b0212c2015-10-29 17:11:57 -0700392 releaseTimerLocked();
393 mTimer = new Timer();
394 mTimer.scheduleAtFixedRate(new ShutdownProcessingTimerTask(shuttingDown,
395 pollingCount),
396 0 /*delay*/,
397 SHUTDOWN_POLLING_INTERVAL_MS);
398 }
399 } else {
400 mHandler.handleProcessingComplete(shuttingDown);
401 }
402 }
403
404 private void doHandleDeepSleep() {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800405 mHandler.cancelProcessingComplete();
keunyoung4b0212c2015-10-29 17:11:57 -0700406 for (PowerServiceEventListener listener : mListeners) {
407 listener.onSleepEntry();
408 }
409 int wakeupTimeSec = getWakeupTime();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800410 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
411 wrapper.resetPowerOnSent();
keunyoung4b0212c2015-10-29 17:11:57 -0700412 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800413 mHal.sendSleepEntry();
414 synchronized (this) {
415 mLastSleepEntryTime = SystemClock.elapsedRealtime();
416 }
417 if (!shouldDoFakeShutdown()) { // if it is mocked, do not enter sleep.
418 mSystemInterface.enterDeepSleep(wakeupTimeSec);
419 }
420 mSystemInterface.releaseAllWakeLocks();
421 mSystemInterface.switchToPartialWakeLock();
keunyoung4b0212c2015-10-29 17:11:57 -0700422 mHal.sendSleepExit();
423 for (PowerServiceEventListener listener : mListeners) {
424 listener.onSleepExit();
425 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800426 if (mSystemInterface.isWakeupCausedByTimer()) {
keunyoung4b0212c2015-10-29 17:11:57 -0700427 doHandlePreprocessing(false /*shuttingDown*/);
428 } else {
429 PowerState currentState = mHal.getCurrentPowerState();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800430 if (needPowerStateChange(currentState)) {
431 onApPowerStateChange(currentState);
keunyoung4b0212c2015-10-29 17:11:57 -0700432 } else { // power controller woke-up but no power state change. Just shutdown.
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800433 Log.w(CarLog.TAG_POWER, "external sleep wake up, but no power state change:" +
keunyoung4b0212c2015-10-29 17:11:57 -0700434 currentState);
435 doHandleShutdown();
436 }
437 }
438 }
439
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800440 private void doHandleNotifyPowerOn() {
441 boolean displayOn = false;
442 synchronized (this) {
443 if (mCurrentState != null && mCurrentState.state == PowerHalService.SET_DISPLAY_ON) {
444 displayOn = true;
445 }
446 }
447 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
448 // wrapper will not send it forward if it is already called.
449 wrapper.callOnPowerOn(displayOn);
450 }
451 }
452
453 private boolean needPowerStateChange(PowerState newState) {
454 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700455 if (mCurrentState != null && mCurrentState.equals(newState)) {
456 return false;
457 }
458 return true;
459 }
460 }
461
keunyoung4b0212c2015-10-29 17:11:57 -0700462 private void doHandleShutdown() {
463 // now shutdown
464 for (PowerServiceEventListener listener : mListeners) {
465 listener.onShutdown();
466 }
467 int wakeupTimeSec = 0;
468 if (mHal.isTimedWakeupAllowed()) {
469 wakeupTimeSec = getWakeupTime();
470 }
471 mHal.sendShutdownStart(wakeupTimeSec);
472 if (!shouldDoFakeShutdown()) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800473 mSystemInterface.shutdown();
keunyoung4b0212c2015-10-29 17:11:57 -0700474 }
475 }
476
477 private int getWakeupTime() {
478 int wakeupTimeSec = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800479 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
480 int t = wrapper.handler.getWakeupTime();
keunyoung4b0212c2015-10-29 17:11:57 -0700481 if (t > wakeupTimeSec) {
482 wakeupTimeSec = t;
483 }
484 }
485 return wakeupTimeSec;
486 }
487
488 private void doHandleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800489 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700490 releaseTimerLocked();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800491 if (!shutdownWhenCompleted && mLastSleepEntryTime > mProcessingStartTime) {
492 // entered sleep after processing start. So this could be duplicate request.
493 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
494 return;
495 }
keunyoung4b0212c2015-10-29 17:11:57 -0700496 }
497 if (shutdownWhenCompleted) {
498 doHandleShutdown();
499 } else {
500 doHandleDeepSleep();
501 }
502 }
503
keunyoung4b0212c2015-10-29 17:11:57 -0700504 private synchronized void setCurrentState(PowerState state) {
505 mCurrentState = state;
506 }
507
508 @Override
509 public void onDisplayBrightnessChange(int brightness) {
510 // TODO
511 }
512
513 private void doHandleDisplayBrightnessChange(int brightness) {
514 //TODO
515 }
516
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800517 private void doHandleMainDisplayStateChange(boolean on) {
keunyoung4b0212c2015-10-29 17:11:57 -0700518 //TODO
519 }
520
keunyoung4b0212c2015-10-29 17:11:57 -0700521 private boolean shouldDoFakeShutdown() {
522 ICarImpl carImpl = ICarImpl.getInstance(mContext);
523 if (!carImpl.isInMocking()) {
524 return false;
525 }
526 CarTestService testService = (CarTestService) carImpl.getCarService(
527 CarSystemTest.TEST_SERVICE);
528 return !testService.shouldDoRealShutdownInMocking();
529 }
530
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800531 public void handleMainDisplayChanged(boolean on) {
532 mHandler.handleMainDisplayStateChange(on);
533 }
534
535 public Handler getHandler() {
536 return mHandler;
537 }
538
keunyoung4b0212c2015-10-29 17:11:57 -0700539 private class PowerHandler extends Handler {
540
541 private final int MSG_POWER_STATE_CHANGE = 0;
542 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
543 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
544 private final int MSG_PROCESSING_COMPLETE = 3;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800545 private final int MSG_NOTIFY_POWER_ON = 4;
keunyoung4b0212c2015-10-29 17:11:57 -0700546
547 // Do not handle this immediately but with some delay as there can be a race between
548 // display off due to rear view camera and delivery to here.
549 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
550
551 private PowerHandler(Looper looper) {
552 super(looper);
553 }
554
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800555 private void handlePowerStateChange() {
556 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
keunyoung4b0212c2015-10-29 17:11:57 -0700557 sendMessage(msg);
558 }
559
560 private void handleDisplayBrightnessChange(int brightness) {
561 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
562 sendMessage(msg);
563 }
564
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800565 private void handleMainDisplayStateChange(boolean on) {
keunyoung4b0212c2015-10-29 17:11:57 -0700566 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800567 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on));
keunyoung4b0212c2015-10-29 17:11:57 -0700568 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS);
569 }
570
571 private void handleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800572 removeMessages(MSG_PROCESSING_COMPLETE);
keunyoung4b0212c2015-10-29 17:11:57 -0700573 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE, shutdownWhenCompleted ? 1 : 0, 0);
574 sendMessage(msg);
575 }
576
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800577 private void handlePowerOn() {
578 Message msg = obtainMessage(MSG_NOTIFY_POWER_ON);
579 sendMessage(msg);
580 }
581
582 private void cancelProcessingComplete() {
583 removeMessages(MSG_PROCESSING_COMPLETE);
584 }
585
keunyoung4b0212c2015-10-29 17:11:57 -0700586 private void cancelAll() {
587 removeMessages(MSG_POWER_STATE_CHANGE);
588 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
589 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
590 removeMessages(MSG_PROCESSING_COMPLETE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800591 removeMessages(MSG_NOTIFY_POWER_ON);
keunyoung4b0212c2015-10-29 17:11:57 -0700592 }
593
594 @Override
595 public void handleMessage(Message msg) {
596 switch (msg.what) {
597 case MSG_POWER_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800598 doHandlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700599 break;
600 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
601 doHandleDisplayBrightnessChange(msg.arg1);
602 break;
603 case MSG_MAIN_DISPLAY_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800604 doHandleMainDisplayStateChange((Boolean) msg.obj);
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800605 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700606 case MSG_PROCESSING_COMPLETE:
607 doHandleProcessingComplete(msg.arg1 == 1);
608 break;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800609 case MSG_NOTIFY_POWER_ON:
610 doHandleNotifyPowerOn();
611 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700612 }
613 }
614 }
615
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800616 private static class SystemIntefaceImpl implements SystemInteface {
keunyoung4b0212c2015-10-29 17:11:57 -0700617
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800618 private final PowerManager mPowerManager;
619 private final DisplayManager mDisplayManager;
620 private final WakeLock mFullWakeLock;
621 private final WakeLock mPartialWakeLock;
622 private final DisplayStateListener mDisplayListener;
623 private CarPowerManagementService mService;
624 private boolean mDisplayStateSet;
625
626 private SystemIntefaceImpl(Context context) {
627 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
628 mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
629 mFullWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, CarLog.TAG_POWER);
630 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
631 CarLog.TAG_POWER);
632 mDisplayListener = new DisplayStateListener();
keunyoung4b0212c2015-10-29 17:11:57 -0700633 }
634
635 @Override
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800636 public void startDisplayStateMonitoring(CarPowerManagementService service) {
637 synchronized (this) {
638 mService = service;
639 mDisplayStateSet = isMainDisplayOn();
640 }
641 mDisplayManager.registerDisplayListener(mDisplayListener, service.getHandler());
642 }
643
644 @Override
645 public void stopDisplayStateMonitoring() {
646 mDisplayManager.unregisterDisplayListener(mDisplayListener);
647 }
648
649 @Override
650 public void setDisplayState(boolean on) {
651 synchronized (this) {
652 mDisplayStateSet = on;
653 }
654 if (on) {
655 switchToFullWakeLock();
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800656 Log.i(CarLog.TAG_POWER, "on display");
657 mPowerManager.wakeUp(SystemClock.uptimeMillis());
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800658 } else {
659 switchToPartialWakeLock();
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800660 Log.i(CarLog.TAG_POWER, "off display");
661 mPowerManager.goToSleep(SystemClock.uptimeMillis());
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800662 }
663 }
664
665 private boolean isMainDisplayOn() {
666 Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800667 return disp.getState() == Display.STATE_ON;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800668 }
669
670 @Override
671 public void shutdown() {
672 mPowerManager.shutdown(false /* no confirm*/, null, true /* true */);
673 }
674
675 @Override
676 public void enterDeepSleep(int wakeupTimeSec) {
677 //TODO
678 }
679
680 @Override
681 public boolean isSystemSupportingDeepSleep() {
682 //TODO should return by checking some kernel suspend control sysfs
683 return false;
684 }
685
686 @Override
687 public void switchToPartialWakeLock() {
688 if (!mPartialWakeLock.isHeld()) {
689 mPartialWakeLock.acquire();
690 }
691 if (mFullWakeLock.isHeld()) {
692 mFullWakeLock.release();
keunyoung4b0212c2015-10-29 17:11:57 -0700693 }
694 }
695
696 @Override
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800697 public void switchToFullWakeLock() {
698 if (!mFullWakeLock.isHeld()) {
699 mFullWakeLock.acquire();
700 }
701 if (mPartialWakeLock.isHeld()) {
702 mPartialWakeLock.release();
703 }
704 }
705
706 @Override
707 public void releaseAllWakeLocks() {
708 if (mPartialWakeLock.isHeld()) {
709 mPartialWakeLock.release();
710 }
711 if (mFullWakeLock.isHeld()) {
712 mFullWakeLock.release();
713 }
714 }
715
716 @Override
717 public boolean isWakeupCausedByTimer() {
718 //TODO check wake up reason and do necessary operation information should come from
719 // kernel. it can be either power on or wake up for maintenance
720 // power on will involve GPIO trigger from power controller
721 // its own wakeup will involve timer expiration.
722 return false;
723 }
724
725 private void handleMainDisplayChanged() {
726 boolean isOn = isMainDisplayOn();
727 CarPowerManagementService service;
728 synchronized (this) {
729 if (mDisplayStateSet == isOn) { // same as what is set
730 return;
731 }
732 service = mService;
733 }
734 service.handleMainDisplayChanged(isOn);
735 }
736
737 private class DisplayStateListener implements DisplayManager.DisplayListener {
738
739 @Override
740 public void onDisplayAdded(int displayId) {
741 //ignore
742 }
743
744 @Override
745 public void onDisplayChanged(int displayId) {
746 if (displayId == Display.DEFAULT_DISPLAY) {
747 handleMainDisplayChanged();
748 }
749 }
750
751 @Override
752 public void onDisplayRemoved(int displayId) {
753 //ignore
754 }
keunyoung4b0212c2015-10-29 17:11:57 -0700755 }
756 }
757
758 private class ShutdownProcessingTimerTask extends TimerTask {
759 private final boolean mShutdownWhenCompleted;
760 private final int mExpirationCount;
761 private int mCurrentCount;
762
763 private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) {
764 mShutdownWhenCompleted = shutdownWhenCompleted;
765 mExpirationCount = expirationCount;
766 mCurrentCount = 0;
767 }
768
769 @Override
770 public void run() {
771 mCurrentCount++;
772 if (mCurrentCount > mExpirationCount) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800773 synchronized (CarPowerManagementService.this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700774 releaseTimerLocked();
775 }
776 mHandler.handleProcessingComplete(mShutdownWhenCompleted);
777 } else {
778 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
779 }
780 }
781 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800782
783 private static class PowerEventProcessingHandlerWrapper {
784 public final PowerEventProcessingHandler handler;
785 private long mProcessingTime = 0;
786 private boolean mProcessingDone = true;
787 private boolean mPowerOnSent = false;
788
789 public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) {
790 this.handler = handler;
791 }
792
793 public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) {
794 mProcessingTime = processingTime;
795 mProcessingDone = false;
796 }
797
798 public synchronized long getProcessingTime() {
799 return mProcessingTime;
800 }
801
802 public synchronized void markProcessingDone() {
803 mProcessingDone = true;
804 }
805
806 public synchronized boolean isProcessingDone() {
807 return mProcessingDone;
808 }
809
810 public void callOnPowerOn(boolean displayOn) {
811 boolean shouldCall = false;
812 synchronized (this) {
813 if (!mPowerOnSent) {
814 shouldCall = true;
815 mPowerOnSent = true;
816 }
817 }
818 if (shouldCall) {
819 handler.onPowerOn(displayOn);
820 }
821 }
822
823 public synchronized void resetPowerOnSent() {
824 mPowerOnSent = false;
825 }
826
827 @Override
828 public String toString() {
829 return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime="
830 + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]";
831 }
832 }
keunyoung4b0212c2015-10-29 17:11:57 -0700833}