blob: 4eb04b46c5a6b2db140601229532feb052323ed3 [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
keunyoung4b0212c2015-10-29 17:11:57 -070018import android.os.Handler;
19import android.os.HandlerThread;
20import android.os.Looper;
21import android.os.Message;
keunyoung4b0212c2015-10-29 17:11:57 -070022import android.os.SystemClock;
keunyoung4b0212c2015-10-29 17:11:57 -070023import android.util.Log;
keunyoung4b0212c2015-10-29 17:11:57 -070024
25import com.android.car.hal.PowerHalService;
26import com.android.car.hal.PowerHalService.PowerState;
keunyoung4b0212c2015-10-29 17:11:57 -070027import com.android.internal.annotations.GuardedBy;
Yao Chendacd7242016-01-26 14:42:42 -080028import com.android.internal.annotations.VisibleForTesting;
keunyoung4b0212c2015-10-29 17:11:57 -070029
30import java.io.PrintWriter;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080031import java.util.LinkedList;
keunyoung4b0212c2015-10-29 17:11:57 -070032import java.util.Timer;
33import java.util.TimerTask;
34import java.util.concurrent.CopyOnWriteArrayList;
35
36public class CarPowerManagementService implements CarServiceBase,
37 PowerHalService.PowerEventListener {
38
39 /**
40 * Listener for other services to monitor power events.
41 */
42 public interface PowerServiceEventListener {
43 /**
44 * Shutdown is happening
45 */
46 void onShutdown();
47
48 /**
49 * Entering deep sleep.
50 */
51 void onSleepEntry();
52
53 /**
54 * Got out of deep sleep.
55 */
56 void onSleepExit();
57 }
58
59 /**
60 * Interface for components requiring processing time before shutting-down or
61 * entering sleep, and wake-up after shut-down.
62 */
63 public interface PowerEventProcessingHandler {
64 /**
65 * Called before shutdown or sleep entry to allow running some processing. This call
66 * should only queue such task in different thread and should return quickly.
67 * Blocking inside this call can trigger watchdog timer which can terminate the
68 * whole system.
69 * @param shuttingDown whether system is shutting down or not (= sleep entry).
70 * @return time necessary to run processing in ms. should return 0 if there is no
71 * processing necessary.
72 */
Keun-young Park303ea1d2016-01-21 11:26:16 -080073 long onPrepareShutdown(boolean shuttingDown);
74
75 /**
76 * Called when power state is changed to ON state. Display can be either on or off.
77 * @param displayOn
78 */
79 void onPowerOn(boolean displayOn);
keunyoung4b0212c2015-10-29 17:11:57 -070080
81 /**
82 * Returns wake up time after system is fully shutdown. Power controller will power on
83 * the system after this time. This power on is meant for regular maintenance kind of
84 * operation.
85 * @return 0 of wake up is not necessary.
86 */
87 int getWakeupTime();
88 }
89
keunyoung4b0212c2015-10-29 17:11:57 -070090 private final PowerHalService mHal;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070091 private final SystemInterface mSystemInterface;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080092
keunyoung4b0212c2015-10-29 17:11:57 -070093 private final CopyOnWriteArrayList<PowerServiceEventListener> mListeners =
94 new CopyOnWriteArrayList<>();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -080095 private final CopyOnWriteArrayList<PowerEventProcessingHandlerWrapper>
96 mPowerEventProcessingHandlers = new CopyOnWriteArrayList<>();
97
98 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -070099 private PowerState mCurrentState;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800100 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700101 private Timer mTimer;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800102 @GuardedBy("this")
103 private long mProcessingStartTime;
104 @GuardedBy("this")
105 private long mLastSleepEntryTime;
106 @GuardedBy("this")
107 private final LinkedList<PowerState> mPendingPowerStates = new LinkedList<>();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700108 @GuardedBy("this")
109 private HandlerThread mHandlerThread;
110 @GuardedBy("this")
111 private PowerHandler mHandler;
keunyoung4b0212c2015-10-29 17:11:57 -0700112
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700113 private final static int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
114 private final static int SHUTDOWN_EXTEND_MAX_MS = 5000;
keunyoung4b0212c2015-10-29 17:11:57 -0700115
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700116 public CarPowerManagementService(PowerHalService powerHal, SystemInterface systemInterface) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800117 mHal = powerHal;
118 mSystemInterface = systemInterface;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800119 }
120
121 /**
122 * Create a dummy instance for unit testing purpose only. Instance constructed in this way
123 * is not safe as members expected to be non-null are null.
Yao Chendacd7242016-01-26 14:42:42 -0800124 */
125 @VisibleForTesting
126 protected CarPowerManagementService() {
Yao Chendacd7242016-01-26 14:42:42 -0800127 mHal = null;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800128 mSystemInterface = null;
Yao Chendacd7242016-01-26 14:42:42 -0800129 mHandlerThread = null;
Keun-young Parkca013ae2016-02-10 16:22:25 -0800130 mHandler = new PowerHandler(Looper.getMainLooper());
Yao Chendacd7242016-01-26 14:42:42 -0800131 }
132
keunyoung4b0212c2015-10-29 17:11:57 -0700133 @Override
134 public void init() {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700135 synchronized (this) {
136 mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
137 mHandlerThread.start();
138 mHandler = new PowerHandler(mHandlerThread.getLooper());
139 }
140
keunyoung4b0212c2015-10-29 17:11:57 -0700141 mHal.setListener(this);
142 if (mHal.isPowerStateSupported()) {
143 mHal.sendBootComplete();
144 PowerState currentState = mHal.getCurrentPowerState();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700145 if (currentState != null) {
146 onApPowerStateChange(currentState);
147 } else {
148 Log.w(CarLog.TAG_POWER, "Unable to get get current power state during "
149 + "initialization");
150 }
keunyoung4b0212c2015-10-29 17:11:57 -0700151 } else {
152 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet.");
Keun-young Parkfad57922016-04-21 11:00:45 -0700153 onApPowerStateChange(new PowerState(PowerHalService.STATE_ON_FULL, 0));
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800154 mSystemInterface.switchToFullWakeLock();
keunyoung4b0212c2015-10-29 17:11:57 -0700155 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800156 mSystemInterface.startDisplayStateMonitoring(this);
keunyoung4b0212c2015-10-29 17:11:57 -0700157 }
158
159 @Override
160 public void release() {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700161 HandlerThread handlerThread;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800162 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700163 releaseTimerLocked();
164 mCurrentState = null;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700165 mHandler.cancelAll();
166 handlerThread = mHandlerThread;
167 }
168 handlerThread.quitSafely();
169 try {
170 handlerThread.join(1000);
171 } catch (InterruptedException e) {
172 Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join.");
keunyoung4b0212c2015-10-29 17:11:57 -0700173 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800174 mSystemInterface.stopDisplayStateMonitoring();
keunyoung4b0212c2015-10-29 17:11:57 -0700175 mListeners.clear();
Keun-young Park303ea1d2016-01-21 11:26:16 -0800176 mPowerEventProcessingHandlers.clear();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800177 mSystemInterface.releaseAllWakeLocks();
keunyoung4b0212c2015-10-29 17:11:57 -0700178 }
179
180 /**
181 * Register listener to monitor power event. There is no unregister counter-part and the list
182 * will be cleared when the service is released.
183 * @param listener
184 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800185 public synchronized void registerPowerEventListener(PowerServiceEventListener listener) {
keunyoung4b0212c2015-10-29 17:11:57 -0700186 mListeners.add(listener);
187 }
188
189 /**
190 * Register PowerEventPreprocessingHandler to run pre-processing before shutdown or
191 * sleep entry. There is no unregister counter-part and the list
192 * will be cleared when the service is released.
193 * @param handler
194 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800195 public synchronized void registerPowerEventProcessingHandler(
196 PowerEventProcessingHandler handler) {
197 mPowerEventProcessingHandlers.add(new PowerEventProcessingHandlerWrapper(handler));
198 // onPowerOn will not be called if power on notification is already done inside the
199 // handler thread. So request it once again here. Wrapper will have its own
200 // gatekeeping to prevent calling onPowerOn twice.
201 mHandler.handlePowerOn();
keunyoung4b0212c2015-10-29 17:11:57 -0700202 }
203
204 /**
205 * Notifies earlier completion of power event processing. PowerEventProcessingHandler quotes
206 * time necessary from onPrePowerEvent() call, but actual processing can finish earlier than
207 * that, and this call can be called in such case to trigger shutdown without waiting further.
208 *
209 * @param handler PowerEventProcessingHandler that was already registered with
210 * {@link #registerPowerEventListener(PowerServiceEventListener)} call. If it was not
211 * registered before, this call will be ignored.
212 */
213 public void notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800214 long processingTime = 0;
215 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
216 if (wrapper.handler == handler) {
217 wrapper.markProcessingDone();
218 } else if (!wrapper.isProcessingDone()) {
219 processingTime = Math.max(processingTime, wrapper.getProcessingTime());
220 }
221 }
222 long now = SystemClock.elapsedRealtime();
223 long startTime;
224 boolean shouldShutdown = true;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700225 PowerHandler powerHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800226 synchronized (this) {
227 startTime = mProcessingStartTime;
228 if (mCurrentState == null) {
229 return;
230 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700231 if (mCurrentState.mState != PowerHalService.STATE_SHUTDOWN_PREPARE) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800232 return;
233 }
234 if (mCurrentState.canEnterDeepSleep()) {
235 shouldShutdown = false;
236 if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < now) {
237 // already slept
238 return;
239 }
240 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700241 powerHandler = mHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800242 }
243 if ((startTime + processingTime) <= now) {
244 Log.i(CarLog.TAG_POWER, "Processing all done");
Pavel Maltsevddbff982017-03-22 14:49:02 -0700245 powerHandler.handleProcessingComplete(shouldShutdown);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800246 }
keunyoung4b0212c2015-10-29 17:11:57 -0700247 }
248
249 @Override
250 public void dump(PrintWriter writer) {
251 writer.println("*PowerManagementService*");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800252 writer.print("mCurrentState:" + mCurrentState);
253 writer.print(",mProcessingStartTime:" + mProcessingStartTime);
254 writer.println(",mLastSleepEntryTime:" + mLastSleepEntryTime);
255 writer.println("**PowerEventProcessingHandlers");
256 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
257 writer.println(wrapper.toString());
258 }
keunyoung4b0212c2015-10-29 17:11:57 -0700259 }
260
261 @Override
262 public void onApPowerStateChange(PowerState state) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700263 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800264 synchronized (this) {
265 mPendingPowerStates.addFirst(state);
Pavel Maltsevddbff982017-03-22 14:49:02 -0700266 handler = mHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800267 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700268 handler.handlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700269 }
270
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800271 private void doHandlePowerStateChange() {
272 PowerState state = null;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700273 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800274 synchronized (this) {
275 state = mPendingPowerStates.peekFirst();
276 mPendingPowerStates.clear();
277 if (state == null) {
278 return;
279 }
280 if (!needPowerStateChange(state)) {
281 return;
282 }
283 // now real power change happens. Whatever was queued before should be all cancelled.
284 releaseTimerLocked();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700285 handler = mHandler;
keunyoung4b0212c2015-10-29 17:11:57 -0700286 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700287 handler.cancelProcessingComplete();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800288
keunyoung4b0212c2015-10-29 17:11:57 -0700289 Log.i(CarLog.TAG_POWER, "Power state change:" + state);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700290 switch (state.mState) {
keunyoung4b0212c2015-10-29 17:11:57 -0700291 case PowerHalService.STATE_ON_DISP_OFF:
292 handleDisplayOff(state);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800293 notifyPowerOn(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700294 break;
295 case PowerHalService.STATE_ON_FULL:
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800296 handleFullOn(state);
297 notifyPowerOn(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700298 break;
299 case PowerHalService.STATE_SHUTDOWN_PREPARE:
300 handleShutdownPrepare(state);
301 break;
302 }
303 }
304
305 private void handleDisplayOff(PowerState newState) {
306 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800307 mSystemInterface.setDisplayState(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700308 }
309
310 private void handleFullOn(PowerState newState) {
311 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800312 mSystemInterface.setDisplayState(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700313 }
314
Yao Chendacd7242016-01-26 14:42:42 -0800315 @VisibleForTesting
316 protected void notifyPowerOn(boolean displayOn) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800317 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
318 wrapper.callOnPowerOn(displayOn);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800319 }
320 }
321
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800322 @VisibleForTesting
323 protected long notifyPrepareShutdown(boolean shuttingDown) {
324 long processingTimeMs = 0;
325 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
326 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
327 if (handlerProcessingTime > processingTimeMs) {
328 processingTimeMs = handlerProcessingTime;
329 }
330 }
331 return processingTimeMs;
332 }
333
keunyoung4b0212c2015-10-29 17:11:57 -0700334 private void handleShutdownPrepare(PowerState newState) {
335 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800336 mSystemInterface.setDisplayState(false);;
keunyoung4b0212c2015-10-29 17:11:57 -0700337 boolean shouldShutdown = true;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800338 if (mHal.isDeepSleepAllowed() && mSystemInterface.isSystemSupportingDeepSleep() &&
keunyoung4b0212c2015-10-29 17:11:57 -0700339 newState.canEnterDeepSleep()) {
340 Log.i(CarLog.TAG_POWER, "starting sleep");
341 shouldShutdown = false;
342 doHandlePreprocessing(shouldShutdown);
343 return;
344 } else if (newState.canPostponeShutdown()) {
345 Log.i(CarLog.TAG_POWER, "starting shutdown with processing");
346 doHandlePreprocessing(shouldShutdown);
347 } else {
348 Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800349 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700350 releaseTimerLocked();
351 }
352 doHandleShutdown();
353 }
354 }
355
356 private void releaseTimerLocked() {
357 if (mTimer != null) {
358 mTimer.cancel();
359 }
360 mTimer = null;
361 }
362
363 private void doHandlePreprocessing(boolean shuttingDown) {
364 long processingTimeMs = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800365 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
366 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
367 if (handlerProcessingTime > 0) {
368 wrapper.setProcessingTimeAndResetProcessingDone(handlerProcessingTime);
369 }
keunyoung4b0212c2015-10-29 17:11:57 -0700370 if (handlerProcessingTime > processingTimeMs) {
371 processingTimeMs = handlerProcessingTime;
372 }
373 }
374 if (processingTimeMs > 0) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800375 int pollingCount = (int)(processingTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
keunyoung4b0212c2015-10-29 17:11:57 -0700376 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for :" + processingTimeMs +
377 " ms, adding polling:" + pollingCount);
378 synchronized (this) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800379 mProcessingStartTime = SystemClock.elapsedRealtime();
keunyoung4b0212c2015-10-29 17:11:57 -0700380 releaseTimerLocked();
381 mTimer = new Timer();
382 mTimer.scheduleAtFixedRate(new ShutdownProcessingTimerTask(shuttingDown,
383 pollingCount),
384 0 /*delay*/,
385 SHUTDOWN_POLLING_INTERVAL_MS);
386 }
387 } else {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700388 PowerHandler handler;
389 synchronized (this) {
390 handler = mHandler;
391 }
392 handler.handleProcessingComplete(shuttingDown);
keunyoung4b0212c2015-10-29 17:11:57 -0700393 }
394 }
395
396 private void doHandleDeepSleep() {
Keun-young Park9d4cf622016-08-04 13:24:28 -0700397 // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
398 // enterDeepSleep should force sleep entry even if wake lock is kept.
399 mSystemInterface.switchToPartialWakeLock();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700400 PowerHandler handler;
401 synchronized (this) {
402 handler = mHandler;
403 }
404 handler.cancelProcessingComplete();
keunyoung4b0212c2015-10-29 17:11:57 -0700405 for (PowerServiceEventListener listener : mListeners) {
406 listener.onSleepEntry();
407 }
408 int wakeupTimeSec = getWakeupTime();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800409 mHal.sendSleepEntry();
410 synchronized (this) {
411 mLastSleepEntryTime = SystemClock.elapsedRealtime();
412 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700413 mSystemInterface.enterDeepSleep(wakeupTimeSec);
keunyoung4b0212c2015-10-29 17:11:57 -0700414 mHal.sendSleepExit();
415 for (PowerServiceEventListener listener : mListeners) {
416 listener.onSleepExit();
417 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800418 if (mSystemInterface.isWakeupCausedByTimer()) {
keunyoung4b0212c2015-10-29 17:11:57 -0700419 doHandlePreprocessing(false /*shuttingDown*/);
420 } else {
421 PowerState currentState = mHal.getCurrentPowerState();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700422 if (currentState != null && needPowerStateChange(currentState)) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800423 onApPowerStateChange(currentState);
keunyoung4b0212c2015-10-29 17:11:57 -0700424 } else { // power controller woke-up but no power state change. Just shutdown.
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800425 Log.w(CarLog.TAG_POWER, "external sleep wake up, but no power state change:" +
keunyoung4b0212c2015-10-29 17:11:57 -0700426 currentState);
427 doHandleShutdown();
428 }
429 }
430 }
431
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800432 private void doHandleNotifyPowerOn() {
433 boolean displayOn = false;
434 synchronized (this) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700435 if (mCurrentState != null && mCurrentState.mState == PowerHalService.STATE_ON_FULL) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800436 displayOn = true;
437 }
438 }
439 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
440 // wrapper will not send it forward if it is already called.
441 wrapper.callOnPowerOn(displayOn);
442 }
443 }
444
445 private boolean needPowerStateChange(PowerState newState) {
446 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700447 if (mCurrentState != null && mCurrentState.equals(newState)) {
448 return false;
449 }
450 return true;
451 }
452 }
453
keunyoung4b0212c2015-10-29 17:11:57 -0700454 private void doHandleShutdown() {
455 // now shutdown
456 for (PowerServiceEventListener listener : mListeners) {
457 listener.onShutdown();
458 }
459 int wakeupTimeSec = 0;
460 if (mHal.isTimedWakeupAllowed()) {
461 wakeupTimeSec = getWakeupTime();
462 }
463 mHal.sendShutdownStart(wakeupTimeSec);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700464 mSystemInterface.shutdown();
keunyoung4b0212c2015-10-29 17:11:57 -0700465 }
466
467 private int getWakeupTime() {
468 int wakeupTimeSec = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800469 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
470 int t = wrapper.handler.getWakeupTime();
keunyoung4b0212c2015-10-29 17:11:57 -0700471 if (t > wakeupTimeSec) {
472 wakeupTimeSec = t;
473 }
474 }
475 return wakeupTimeSec;
476 }
477
478 private void doHandleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800479 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700480 releaseTimerLocked();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800481 if (!shutdownWhenCompleted && mLastSleepEntryTime > mProcessingStartTime) {
482 // entered sleep after processing start. So this could be duplicate request.
483 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
484 return;
485 }
keunyoung4b0212c2015-10-29 17:11:57 -0700486 }
487 if (shutdownWhenCompleted) {
488 doHandleShutdown();
489 } else {
490 doHandleDeepSleep();
491 }
492 }
493
keunyoung4b0212c2015-10-29 17:11:57 -0700494 private synchronized void setCurrentState(PowerState state) {
495 mCurrentState = state;
496 }
497
498 @Override
499 public void onDisplayBrightnessChange(int brightness) {
Keun-young Parkf9215202016-10-10 12:34:08 -0700500 // TODO bug: 32065231
keunyoung4b0212c2015-10-29 17:11:57 -0700501 }
502
503 private void doHandleDisplayBrightnessChange(int brightness) {
Keun-young Parkf9215202016-10-10 12:34:08 -0700504 //TODO bug: 32065231
keunyoung4b0212c2015-10-29 17:11:57 -0700505 }
506
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800507 private void doHandleMainDisplayStateChange(boolean on) {
Keun-young Parkf9215202016-10-10 12:34:08 -0700508 //TODO bug: 32065231
keunyoung4b0212c2015-10-29 17:11:57 -0700509 }
510
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800511 public void handleMainDisplayChanged(boolean on) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700512 PowerHandler handler;
513 synchronized (this) {
514 handler = mHandler;
515 }
516 handler.handleMainDisplayStateChange(on);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800517 }
518
Pavel Maltsevddbff982017-03-22 14:49:02 -0700519 public synchronized Handler getHandler() {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800520 return mHandler;
521 }
522
keunyoung4b0212c2015-10-29 17:11:57 -0700523 private class PowerHandler extends Handler {
524
525 private final int MSG_POWER_STATE_CHANGE = 0;
526 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
527 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
528 private final int MSG_PROCESSING_COMPLETE = 3;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800529 private final int MSG_NOTIFY_POWER_ON = 4;
keunyoung4b0212c2015-10-29 17:11:57 -0700530
531 // Do not handle this immediately but with some delay as there can be a race between
532 // display off due to rear view camera and delivery to here.
533 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
534
535 private PowerHandler(Looper looper) {
536 super(looper);
537 }
538
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800539 private void handlePowerStateChange() {
540 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
keunyoung4b0212c2015-10-29 17:11:57 -0700541 sendMessage(msg);
542 }
543
544 private void handleDisplayBrightnessChange(int brightness) {
545 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
546 sendMessage(msg);
547 }
548
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800549 private void handleMainDisplayStateChange(boolean on) {
keunyoung4b0212c2015-10-29 17:11:57 -0700550 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800551 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on));
keunyoung4b0212c2015-10-29 17:11:57 -0700552 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS);
553 }
554
555 private void handleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800556 removeMessages(MSG_PROCESSING_COMPLETE);
keunyoung4b0212c2015-10-29 17:11:57 -0700557 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE, shutdownWhenCompleted ? 1 : 0, 0);
558 sendMessage(msg);
559 }
560
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800561 private void handlePowerOn() {
562 Message msg = obtainMessage(MSG_NOTIFY_POWER_ON);
563 sendMessage(msg);
564 }
565
566 private void cancelProcessingComplete() {
567 removeMessages(MSG_PROCESSING_COMPLETE);
568 }
569
keunyoung4b0212c2015-10-29 17:11:57 -0700570 private void cancelAll() {
571 removeMessages(MSG_POWER_STATE_CHANGE);
572 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
573 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
574 removeMessages(MSG_PROCESSING_COMPLETE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800575 removeMessages(MSG_NOTIFY_POWER_ON);
keunyoung4b0212c2015-10-29 17:11:57 -0700576 }
577
578 @Override
579 public void handleMessage(Message msg) {
580 switch (msg.what) {
581 case MSG_POWER_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800582 doHandlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700583 break;
584 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
585 doHandleDisplayBrightnessChange(msg.arg1);
586 break;
587 case MSG_MAIN_DISPLAY_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800588 doHandleMainDisplayStateChange((Boolean) msg.obj);
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800589 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700590 case MSG_PROCESSING_COMPLETE:
591 doHandleProcessingComplete(msg.arg1 == 1);
592 break;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800593 case MSG_NOTIFY_POWER_ON:
594 doHandleNotifyPowerOn();
595 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700596 }
597 }
598 }
599
keunyoung4b0212c2015-10-29 17:11:57 -0700600 private class ShutdownProcessingTimerTask extends TimerTask {
601 private final boolean mShutdownWhenCompleted;
602 private final int mExpirationCount;
603 private int mCurrentCount;
604
605 private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) {
606 mShutdownWhenCompleted = shutdownWhenCompleted;
607 mExpirationCount = expirationCount;
608 mCurrentCount = 0;
609 }
610
611 @Override
612 public void run() {
613 mCurrentCount++;
614 if (mCurrentCount > mExpirationCount) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700615 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800616 synchronized (CarPowerManagementService.this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700617 releaseTimerLocked();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700618 handler = mHandler;
keunyoung4b0212c2015-10-29 17:11:57 -0700619 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700620 handler.handleProcessingComplete(mShutdownWhenCompleted);
keunyoung4b0212c2015-10-29 17:11:57 -0700621 } else {
622 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
623 }
624 }
625 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800626
627 private static class PowerEventProcessingHandlerWrapper {
628 public final PowerEventProcessingHandler handler;
629 private long mProcessingTime = 0;
630 private boolean mProcessingDone = true;
631 private boolean mPowerOnSent = false;
Keun-young Parkd73afae2016-04-08 20:03:32 -0700632 private int mLastDisplayState = -1;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800633
634 public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) {
635 this.handler = handler;
636 }
637
638 public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) {
639 mProcessingTime = processingTime;
640 mProcessingDone = false;
641 }
642
643 public synchronized long getProcessingTime() {
644 return mProcessingTime;
645 }
646
647 public synchronized void markProcessingDone() {
648 mProcessingDone = true;
649 }
650
651 public synchronized boolean isProcessingDone() {
652 return mProcessingDone;
653 }
654
655 public void callOnPowerOn(boolean displayOn) {
Keun-young Parkd73afae2016-04-08 20:03:32 -0700656 int newDisplayState = displayOn ? 1 : 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800657 boolean shouldCall = false;
658 synchronized (this) {
Keun-young Parkd73afae2016-04-08 20:03:32 -0700659 if (!mPowerOnSent || (mLastDisplayState != newDisplayState)) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800660 shouldCall = true;
661 mPowerOnSent = true;
Keun-young Parkd73afae2016-04-08 20:03:32 -0700662 mLastDisplayState = newDisplayState;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800663 }
664 }
665 if (shouldCall) {
666 handler.onPowerOn(displayOn);
667 }
668 }
669
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800670 @Override
671 public String toString() {
672 return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime="
673 + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]";
674 }
675 }
keunyoung4b0212c2015-10-29 17:11:57 -0700676}