blob: 57ccf622c8921e6712e642705c1550426c2ff8b5 [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
Steve Paik87b36fd2018-03-13 19:25:47 -070018import android.car.Car;
19import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
20import android.car.hardware.power.ICarPower;
21import android.car.hardware.power.ICarPowerStateListener;
22import android.content.Context;
23import android.os.Handler;
24import android.os.HandlerThread;
25import android.os.IBinder;
26import android.os.Looper;
27import android.os.Message;
28import android.os.RemoteCallbackList;
29import android.os.RemoteException;
30import android.os.SystemClock;
31import android.util.Log;
keunyoung4b0212c2015-10-29 17:11:57 -070032
33import com.android.car.hal.PowerHalService;
34import com.android.car.hal.PowerHalService.PowerState;
Enrico Granatab19bc322017-10-12 12:25:06 -070035import com.android.car.systeminterface.SystemInterface;
keunyoung4b0212c2015-10-29 17:11:57 -070036import com.android.internal.annotations.GuardedBy;
Yao Chendacd7242016-01-26 14:42:42 -080037import com.android.internal.annotations.VisibleForTesting;
keunyoung4b0212c2015-10-29 17:11:57 -070038
Steve Paik87b36fd2018-03-13 19:25:47 -070039import java.io.PrintWriter;
40import java.util.LinkedList;
41import java.util.Map;
42import java.util.Timer;
43import java.util.TimerTask;
44import java.util.concurrent.ConcurrentHashMap;
45import java.util.concurrent.CopyOnWriteArrayList;
keunyoung4b0212c2015-10-29 17:11:57 -070046
Steve Paik388d7772018-02-12 10:54:51 -080047public class CarPowerManagementService extends ICarPower.Stub implements CarServiceBase,
keunyoung4b0212c2015-10-29 17:11:57 -070048 PowerHalService.PowerEventListener {
49
50 /**
51 * Listener for other services to monitor power events.
52 */
53 public interface PowerServiceEventListener {
54 /**
55 * Shutdown is happening
56 */
57 void onShutdown();
58
59 /**
60 * Entering deep sleep.
61 */
62 void onSleepEntry();
63
64 /**
65 * Got out of deep sleep.
66 */
67 void onSleepExit();
68 }
69
70 /**
71 * Interface for components requiring processing time before shutting-down or
72 * entering sleep, and wake-up after shut-down.
73 */
74 public interface PowerEventProcessingHandler {
75 /**
76 * Called before shutdown or sleep entry to allow running some processing. This call
77 * should only queue such task in different thread and should return quickly.
78 * Blocking inside this call can trigger watchdog timer which can terminate the
79 * whole system.
80 * @param shuttingDown whether system is shutting down or not (= sleep entry).
81 * @return time necessary to run processing in ms. should return 0 if there is no
82 * processing necessary.
83 */
Keun-young Park303ea1d2016-01-21 11:26:16 -080084 long onPrepareShutdown(boolean shuttingDown);
85
86 /**
87 * Called when power state is changed to ON state. Display can be either on or off.
88 * @param displayOn
89 */
90 void onPowerOn(boolean displayOn);
keunyoung4b0212c2015-10-29 17:11:57 -070091
92 /**
93 * Returns wake up time after system is fully shutdown. Power controller will power on
94 * the system after this time. This power on is meant for regular maintenance kind of
95 * operation.
96 * @return 0 of wake up is not necessary.
97 */
98 int getWakeupTime();
99 }
100
Steve Paik388d7772018-02-12 10:54:51 -0800101 private final Context mContext;
keunyoung4b0212c2015-10-29 17:11:57 -0700102 private final PowerHalService mHal;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700103 private final SystemInterface mSystemInterface;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800104
keunyoung4b0212c2015-10-29 17:11:57 -0700105 private final CopyOnWriteArrayList<PowerServiceEventListener> mListeners =
106 new CopyOnWriteArrayList<>();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800107 private final CopyOnWriteArrayList<PowerEventProcessingHandlerWrapper>
108 mPowerEventProcessingHandlers = new CopyOnWriteArrayList<>();
Steve Paik03124082018-02-16 11:19:26 -0800109 private final PowerManagerCallbackList mPowerManagerListeners = new PowerManagerCallbackList();
110 private final Map<IBinder, Integer> mPowerManagerListenerTokens = new ConcurrentHashMap<>();
111 private int mTokenValue = 1;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800112
113 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700114 private PowerState mCurrentState;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800115 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700116 private Timer mTimer;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800117 @GuardedBy("this")
118 private long mProcessingStartTime;
119 @GuardedBy("this")
120 private long mLastSleepEntryTime;
121 @GuardedBy("this")
122 private final LinkedList<PowerState> mPendingPowerStates = new LinkedList<>();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700123 @GuardedBy("this")
124 private HandlerThread mHandlerThread;
125 @GuardedBy("this")
126 private PowerHandler mHandler;
Steve Paik388d7772018-02-12 10:54:51 -0800127 private int mBootReason;
Steve Paik388d7772018-02-12 10:54:51 -0800128 private boolean mShutdownOnNextSuspend = false;
keunyoung4b0212c2015-10-29 17:11:57 -0700129
Steve Paik03124082018-02-16 11:19:26 -0800130 // TODO: Make this OEM configurable.
131 private final static int APP_EXTEND_MAX_MS = 10000;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700132 private final static int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
133 private final static int SHUTDOWN_EXTEND_MAX_MS = 5000;
keunyoung4b0212c2015-10-29 17:11:57 -0700134
Steve Paik03124082018-02-16 11:19:26 -0800135 private class PowerManagerCallbackList extends RemoteCallbackList<ICarPowerStateListener> {
136 /**
137 * Old version of {@link #onCallbackDied(E, Object)} that
138 * does not provide a cookie.
139 */
140 @Override
141 public void onCallbackDied(ICarPowerStateListener listener) {
142 Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder());
143 CarPowerManagementService.this.doUnregisterListener(listener);
144 }
145 }
146
Steve Paik388d7772018-02-12 10:54:51 -0800147 public CarPowerManagementService(Context context, PowerHalService powerHal,
148 SystemInterface systemInterface) {
149 mContext = context;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800150 mHal = powerHal;
151 mSystemInterface = systemInterface;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800152 }
153
154 /**
155 * Create a dummy instance for unit testing purpose only. Instance constructed in this way
156 * is not safe as members expected to be non-null are null.
Yao Chendacd7242016-01-26 14:42:42 -0800157 */
158 @VisibleForTesting
159 protected CarPowerManagementService() {
Steve Paik388d7772018-02-12 10:54:51 -0800160 mContext = null;
Yao Chendacd7242016-01-26 14:42:42 -0800161 mHal = null;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800162 mSystemInterface = null;
Yao Chendacd7242016-01-26 14:42:42 -0800163 mHandlerThread = null;
Keun-young Parkca013ae2016-02-10 16:22:25 -0800164 mHandler = new PowerHandler(Looper.getMainLooper());
Yao Chendacd7242016-01-26 14:42:42 -0800165 }
166
keunyoung4b0212c2015-10-29 17:11:57 -0700167 @Override
168 public void init() {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700169 synchronized (this) {
170 mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
171 mHandlerThread.start();
172 mHandler = new PowerHandler(mHandlerThread.getLooper());
173 }
174
keunyoung4b0212c2015-10-29 17:11:57 -0700175 mHal.setListener(this);
176 if (mHal.isPowerStateSupported()) {
177 mHal.sendBootComplete();
178 PowerState currentState = mHal.getCurrentPowerState();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700179 if (currentState != null) {
180 onApPowerStateChange(currentState);
181 } else {
182 Log.w(CarLog.TAG_POWER, "Unable to get get current power state during "
183 + "initialization");
184 }
keunyoung4b0212c2015-10-29 17:11:57 -0700185 } else {
186 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet.");
Keun-young Parkfad57922016-04-21 11:00:45 -0700187 onApPowerStateChange(new PowerState(PowerHalService.STATE_ON_FULL, 0));
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800188 mSystemInterface.switchToFullWakeLock();
keunyoung4b0212c2015-10-29 17:11:57 -0700189 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800190 mSystemInterface.startDisplayStateMonitoring(this);
keunyoung4b0212c2015-10-29 17:11:57 -0700191 }
192
193 @Override
194 public void release() {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700195 HandlerThread handlerThread;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800196 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700197 releaseTimerLocked();
198 mCurrentState = null;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700199 mHandler.cancelAll();
200 handlerThread = mHandlerThread;
201 }
202 handlerThread.quitSafely();
203 try {
204 handlerThread.join(1000);
205 } catch (InterruptedException e) {
206 Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join.");
keunyoung4b0212c2015-10-29 17:11:57 -0700207 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800208 mSystemInterface.stopDisplayStateMonitoring();
keunyoung4b0212c2015-10-29 17:11:57 -0700209 mListeners.clear();
Keun-young Park303ea1d2016-01-21 11:26:16 -0800210 mPowerEventProcessingHandlers.clear();
Steve Paik03124082018-02-16 11:19:26 -0800211 mPowerManagerListeners.kill();
212 mPowerManagerListenerTokens.clear();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800213 mSystemInterface.releaseAllWakeLocks();
keunyoung4b0212c2015-10-29 17:11:57 -0700214 }
215
216 /**
217 * Register listener to monitor power event. There is no unregister counter-part and the list
218 * will be cleared when the service is released.
219 * @param listener
220 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800221 public synchronized void registerPowerEventListener(PowerServiceEventListener listener) {
keunyoung4b0212c2015-10-29 17:11:57 -0700222 mListeners.add(listener);
223 }
224
225 /**
226 * Register PowerEventPreprocessingHandler to run pre-processing before shutdown or
227 * sleep entry. There is no unregister counter-part and the list
228 * will be cleared when the service is released.
229 * @param handler
230 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800231 public synchronized void registerPowerEventProcessingHandler(
232 PowerEventProcessingHandler handler) {
233 mPowerEventProcessingHandlers.add(new PowerEventProcessingHandlerWrapper(handler));
234 // onPowerOn will not be called if power on notification is already done inside the
235 // handler thread. So request it once again here. Wrapper will have its own
236 // gatekeeping to prevent calling onPowerOn twice.
237 mHandler.handlePowerOn();
keunyoung4b0212c2015-10-29 17:11:57 -0700238 }
239
240 /**
241 * Notifies earlier completion of power event processing. PowerEventProcessingHandler quotes
242 * time necessary from onPrePowerEvent() call, but actual processing can finish earlier than
243 * that, and this call can be called in such case to trigger shutdown without waiting further.
244 *
245 * @param handler PowerEventProcessingHandler that was already registered with
246 * {@link #registerPowerEventListener(PowerServiceEventListener)} call. If it was not
247 * registered before, this call will be ignored.
248 */
249 public void notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800250 long processingTime = 0;
251 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
252 if (wrapper.handler == handler) {
253 wrapper.markProcessingDone();
254 } else if (!wrapper.isProcessingDone()) {
255 processingTime = Math.max(processingTime, wrapper.getProcessingTime());
256 }
257 }
Steve Paik03124082018-02-16 11:19:26 -0800258 synchronized (mPowerManagerListenerTokens) {
259 if (!mPowerManagerListenerTokens.isEmpty()) {
260 processingTime += APP_EXTEND_MAX_MS;
261 }
262 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800263 long now = SystemClock.elapsedRealtime();
264 long startTime;
265 boolean shouldShutdown = true;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700266 PowerHandler powerHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800267 synchronized (this) {
268 startTime = mProcessingStartTime;
269 if (mCurrentState == null) {
270 return;
271 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700272 if (mCurrentState.mState != PowerHalService.STATE_SHUTDOWN_PREPARE) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800273 return;
274 }
Steve Paik03124082018-02-16 11:19:26 -0800275 if (mCurrentState.canEnterDeepSleep() && !mShutdownOnNextSuspend) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800276 shouldShutdown = false;
277 if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < now) {
278 // already slept
279 return;
280 }
281 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700282 powerHandler = mHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800283 }
284 if ((startTime + processingTime) <= now) {
285 Log.i(CarLog.TAG_POWER, "Processing all done");
Pavel Maltsevddbff982017-03-22 14:49:02 -0700286 powerHandler.handleProcessingComplete(shouldShutdown);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800287 }
keunyoung4b0212c2015-10-29 17:11:57 -0700288 }
289
290 @Override
291 public void dump(PrintWriter writer) {
292 writer.println("*PowerManagementService*");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800293 writer.print("mCurrentState:" + mCurrentState);
294 writer.print(",mProcessingStartTime:" + mProcessingStartTime);
295 writer.println(",mLastSleepEntryTime:" + mLastSleepEntryTime);
296 writer.println("**PowerEventProcessingHandlers");
297 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
298 writer.println(wrapper.toString());
299 }
keunyoung4b0212c2015-10-29 17:11:57 -0700300 }
301
302 @Override
Steve Paik110f95f2017-11-22 14:44:05 -0800303 public void onBootReasonReceived(int bootReason) {
Steve Paik388d7772018-02-12 10:54:51 -0800304 mBootReason = bootReason;
Steve Paik110f95f2017-11-22 14:44:05 -0800305 }
306
307 @Override
keunyoung4b0212c2015-10-29 17:11:57 -0700308 public void onApPowerStateChange(PowerState state) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700309 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800310 synchronized (this) {
311 mPendingPowerStates.addFirst(state);
Pavel Maltsevddbff982017-03-22 14:49:02 -0700312 handler = mHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800313 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700314 handler.handlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700315 }
316
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800317 private void doHandlePowerStateChange() {
318 PowerState state = null;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700319 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800320 synchronized (this) {
321 state = mPendingPowerStates.peekFirst();
322 mPendingPowerStates.clear();
323 if (state == null) {
324 return;
325 }
326 if (!needPowerStateChange(state)) {
327 return;
328 }
329 // now real power change happens. Whatever was queued before should be all cancelled.
330 releaseTimerLocked();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700331 handler = mHandler;
keunyoung4b0212c2015-10-29 17:11:57 -0700332 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700333 handler.cancelProcessingComplete();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800334
keunyoung4b0212c2015-10-29 17:11:57 -0700335 Log.i(CarLog.TAG_POWER, "Power state change:" + state);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700336 switch (state.mState) {
keunyoung4b0212c2015-10-29 17:11:57 -0700337 case PowerHalService.STATE_ON_DISP_OFF:
338 handleDisplayOff(state);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800339 notifyPowerOn(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700340 break;
341 case PowerHalService.STATE_ON_FULL:
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800342 handleFullOn(state);
343 notifyPowerOn(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700344 break;
345 case PowerHalService.STATE_SHUTDOWN_PREPARE:
346 handleShutdownPrepare(state);
347 break;
348 }
349 }
350
351 private void handleDisplayOff(PowerState newState) {
352 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800353 mSystemInterface.setDisplayState(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700354 }
355
356 private void handleFullOn(PowerState newState) {
357 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800358 mSystemInterface.setDisplayState(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700359 }
360
Yao Chendacd7242016-01-26 14:42:42 -0800361 @VisibleForTesting
362 protected void notifyPowerOn(boolean displayOn) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800363 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
364 wrapper.callOnPowerOn(displayOn);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800365 }
366 }
367
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800368 @VisibleForTesting
369 protected long notifyPrepareShutdown(boolean shuttingDown) {
370 long processingTimeMs = 0;
371 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
372 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
373 if (handlerProcessingTime > processingTimeMs) {
374 processingTimeMs = handlerProcessingTime;
375 }
376 }
Steve Paik03124082018-02-16 11:19:26 -0800377 // Add time for powerManager events
378 processingTimeMs += sendPowerManagerEvent(shuttingDown);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800379 return processingTimeMs;
380 }
381
keunyoung4b0212c2015-10-29 17:11:57 -0700382 private void handleShutdownPrepare(PowerState newState) {
383 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800384 mSystemInterface.setDisplayState(false);;
keunyoung4b0212c2015-10-29 17:11:57 -0700385 boolean shouldShutdown = true;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800386 if (mHal.isDeepSleepAllowed() && mSystemInterface.isSystemSupportingDeepSleep() &&
Steve Paik03124082018-02-16 11:19:26 -0800387 newState.canEnterDeepSleep() && !mShutdownOnNextSuspend) {
keunyoung4b0212c2015-10-29 17:11:57 -0700388 Log.i(CarLog.TAG_POWER, "starting sleep");
389 shouldShutdown = false;
390 doHandlePreprocessing(shouldShutdown);
391 return;
392 } else if (newState.canPostponeShutdown()) {
393 Log.i(CarLog.TAG_POWER, "starting shutdown with processing");
394 doHandlePreprocessing(shouldShutdown);
395 } else {
396 Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800397 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700398 releaseTimerLocked();
399 }
400 doHandleShutdown();
401 }
402 }
403
Andreas Gampe985ca2f2018-02-09 12:57:54 -0800404 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700405 private void releaseTimerLocked() {
406 if (mTimer != null) {
407 mTimer.cancel();
408 }
409 mTimer = null;
410 }
411
412 private void doHandlePreprocessing(boolean shuttingDown) {
413 long processingTimeMs = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800414 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
415 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
416 if (handlerProcessingTime > 0) {
417 wrapper.setProcessingTimeAndResetProcessingDone(handlerProcessingTime);
418 }
keunyoung4b0212c2015-10-29 17:11:57 -0700419 if (handlerProcessingTime > processingTimeMs) {
420 processingTimeMs = handlerProcessingTime;
421 }
422 }
Steve Paik03124082018-02-16 11:19:26 -0800423 // Add time for powerManager events
424 processingTimeMs += sendPowerManagerEvent(shuttingDown);
keunyoung4b0212c2015-10-29 17:11:57 -0700425 if (processingTimeMs > 0) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800426 int pollingCount = (int)(processingTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
keunyoung4b0212c2015-10-29 17:11:57 -0700427 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for :" + processingTimeMs +
428 " ms, adding polling:" + pollingCount);
429 synchronized (this) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800430 mProcessingStartTime = SystemClock.elapsedRealtime();
keunyoung4b0212c2015-10-29 17:11:57 -0700431 releaseTimerLocked();
432 mTimer = new Timer();
433 mTimer.scheduleAtFixedRate(new ShutdownProcessingTimerTask(shuttingDown,
434 pollingCount),
435 0 /*delay*/,
436 SHUTDOWN_POLLING_INTERVAL_MS);
437 }
438 } else {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700439 PowerHandler handler;
440 synchronized (this) {
441 handler = mHandler;
442 }
443 handler.handleProcessingComplete(shuttingDown);
keunyoung4b0212c2015-10-29 17:11:57 -0700444 }
445 }
446
Steve Paik03124082018-02-16 11:19:26 -0800447 private long sendPowerManagerEvent(boolean shuttingDown) {
448 long processingTimeMs = 0;
449 int newState = shuttingDown ? CarPowerStateListener.SHUTDOWN_ENTER :
450 CarPowerStateListener.SUSPEND_ENTER;
451 synchronized (mPowerManagerListenerTokens) {
452 mPowerManagerListenerTokens.clear();
453 int i = mPowerManagerListeners.beginBroadcast();
454 while (i-- > 0) {
455 try {
456 ICarPowerStateListener listener = mPowerManagerListeners.getBroadcastItem(i);
457 listener.onStateChanged(newState, mTokenValue);
458 mPowerManagerListenerTokens.put(listener.asBinder(), mTokenValue);
459 mTokenValue++;
460 } catch (RemoteException e) {
461 // Its likely the connection snapped. Let binder death handle the situation.
462 Log.e(CarLog.TAG_POWER, "onStateChanged calling failed: " + e);
463 }
464 }
465 mPowerManagerListeners.finishBroadcast();
466 if (!mPowerManagerListenerTokens.isEmpty()) {
467 Log.i(CarLog.TAG_POWER, "mPowerMangerListenerTokens not empty, add APP_EXTEND_MAX_MS");
468 processingTimeMs += APP_EXTEND_MAX_MS;
469 }
470 }
471 return processingTimeMs;
472 }
473
keunyoung4b0212c2015-10-29 17:11:57 -0700474 private void doHandleDeepSleep() {
Keun-young Park9d4cf622016-08-04 13:24:28 -0700475 // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
476 // enterDeepSleep should force sleep entry even if wake lock is kept.
477 mSystemInterface.switchToPartialWakeLock();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700478 PowerHandler handler;
479 synchronized (this) {
480 handler = mHandler;
481 }
482 handler.cancelProcessingComplete();
keunyoung4b0212c2015-10-29 17:11:57 -0700483 for (PowerServiceEventListener listener : mListeners) {
484 listener.onSleepEntry();
485 }
486 int wakeupTimeSec = getWakeupTime();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800487 mHal.sendSleepEntry();
488 synchronized (this) {
489 mLastSleepEntryTime = SystemClock.elapsedRealtime();
490 }
Steve Paik0f9fc002018-02-09 17:42:00 -0800491 if (mSystemInterface.enterDeepSleep(wakeupTimeSec) == false) {
492 // System did not suspend. Need to shutdown
493 // TODO: Shutdown gracefully
Steve Paik03124082018-02-16 11:19:26 -0800494 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Need to shutdown");
Steve Paik0f9fc002018-02-09 17:42:00 -0800495 }
keunyoung4b0212c2015-10-29 17:11:57 -0700496 mHal.sendSleepExit();
497 for (PowerServiceEventListener listener : mListeners) {
498 listener.onSleepExit();
499 }
Steve Paik03124082018-02-16 11:19:26 -0800500 // Notify applications
501 int i = mPowerManagerListeners.beginBroadcast();
502 while (i-- > 0) {
503 try {
504 ICarPowerStateListener listener = mPowerManagerListeners.getBroadcastItem(i);
505 listener.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, 0);
506 } catch (RemoteException e) {
507 // Its likely the connection snapped. Let binder death handle the situation.
508 Log.e(CarLog.TAG_POWER, "onStateChanged calling failed: " + e);
509 }
510 }
511 mPowerManagerListeners.finishBroadcast();
512
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800513 if (mSystemInterface.isWakeupCausedByTimer()) {
keunyoung4b0212c2015-10-29 17:11:57 -0700514 doHandlePreprocessing(false /*shuttingDown*/);
515 } else {
516 PowerState currentState = mHal.getCurrentPowerState();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700517 if (currentState != null && needPowerStateChange(currentState)) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800518 onApPowerStateChange(currentState);
keunyoung4b0212c2015-10-29 17:11:57 -0700519 } else { // power controller woke-up but no power state change. Just shutdown.
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800520 Log.w(CarLog.TAG_POWER, "external sleep wake up, but no power state change:" +
keunyoung4b0212c2015-10-29 17:11:57 -0700521 currentState);
522 doHandleShutdown();
523 }
524 }
525 }
526
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800527 private void doHandleNotifyPowerOn() {
528 boolean displayOn = false;
529 synchronized (this) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700530 if (mCurrentState != null && mCurrentState.mState == PowerHalService.STATE_ON_FULL) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800531 displayOn = true;
532 }
533 }
534 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
535 // wrapper will not send it forward if it is already called.
536 wrapper.callOnPowerOn(displayOn);
537 }
538 }
539
540 private boolean needPowerStateChange(PowerState newState) {
541 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700542 if (mCurrentState != null && mCurrentState.equals(newState)) {
543 return false;
544 }
545 return true;
546 }
547 }
548
keunyoung4b0212c2015-10-29 17:11:57 -0700549 private void doHandleShutdown() {
550 // now shutdown
551 for (PowerServiceEventListener listener : mListeners) {
552 listener.onShutdown();
553 }
554 int wakeupTimeSec = 0;
555 if (mHal.isTimedWakeupAllowed()) {
556 wakeupTimeSec = getWakeupTime();
557 }
558 mHal.sendShutdownStart(wakeupTimeSec);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700559 mSystemInterface.shutdown();
keunyoung4b0212c2015-10-29 17:11:57 -0700560 }
561
562 private int getWakeupTime() {
563 int wakeupTimeSec = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800564 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
565 int t = wrapper.handler.getWakeupTime();
keunyoung4b0212c2015-10-29 17:11:57 -0700566 if (t > wakeupTimeSec) {
567 wakeupTimeSec = t;
568 }
569 }
570 return wakeupTimeSec;
571 }
572
573 private void doHandleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800574 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700575 releaseTimerLocked();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800576 if (!shutdownWhenCompleted && mLastSleepEntryTime > mProcessingStartTime) {
577 // entered sleep after processing start. So this could be duplicate request.
578 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
579 return;
580 }
keunyoung4b0212c2015-10-29 17:11:57 -0700581 }
582 if (shutdownWhenCompleted) {
583 doHandleShutdown();
584 } else {
585 doHandleDeepSleep();
586 }
587 }
588
keunyoung4b0212c2015-10-29 17:11:57 -0700589 private synchronized void setCurrentState(PowerState state) {
590 mCurrentState = state;
591 }
592
593 @Override
594 public void onDisplayBrightnessChange(int brightness) {
Steve Paik87b36fd2018-03-13 19:25:47 -0700595 PowerHandler handler;
596 synchronized (this) {
597 handler = mHandler;
598 }
599 handler.handleDisplayBrightnessChange(brightness);
keunyoung4b0212c2015-10-29 17:11:57 -0700600 }
601
602 private void doHandleDisplayBrightnessChange(int brightness) {
Steve Paik87b36fd2018-03-13 19:25:47 -0700603 mSystemInterface.setDisplayBrightness(brightness);
keunyoung4b0212c2015-10-29 17:11:57 -0700604 }
605
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800606 private void doHandleMainDisplayStateChange(boolean on) {
Steve Paik47cdf7b2018-03-16 17:27:43 -0700607 Log.w(CarLog.TAG_POWER, "Unimplemented: doHandleMainDisplayStateChange() - on = " + on);
keunyoung4b0212c2015-10-29 17:11:57 -0700608 }
609
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800610 public void handleMainDisplayChanged(boolean on) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700611 PowerHandler handler;
612 synchronized (this) {
613 handler = mHandler;
614 }
615 handler.handleMainDisplayStateChange(on);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800616 }
617
Steve Paik47cdf7b2018-03-16 17:27:43 -0700618 /**
619 * Send display brightness to VHAL.
620 * @param brightness value 0-100%
621 */
622 public void sendDisplayBrightness(int brightness) {
623 mHal.sendDisplayBrightness(brightness);
624 }
625
Pavel Maltsevddbff982017-03-22 14:49:02 -0700626 public synchronized Handler getHandler() {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800627 return mHandler;
628 }
629
Steve Paik388d7772018-02-12 10:54:51 -0800630 // Binder interface for CarPowerManager
631 @Override
632 public void registerListener(ICarPowerStateListener listener) {
633 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
Steve Paik03124082018-02-16 11:19:26 -0800634 mPowerManagerListeners.register(listener);
Steve Paik388d7772018-02-12 10:54:51 -0800635 }
636
637 @Override
638 public void unregisterListener(ICarPowerStateListener listener) {
639 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
Steve Paik03124082018-02-16 11:19:26 -0800640 doUnregisterListener(listener);
641 }
642
643 private void doUnregisterListener(ICarPowerStateListener listener) {
644 boolean found = mPowerManagerListeners.unregister(listener);
645
646 if (found) {
647 // Remove outstanding token if there is one
648 IBinder binder = listener.asBinder();
649 synchronized (mPowerManagerListenerTokens) {
650 if (mPowerManagerListenerTokens.containsKey(binder)) {
651 int token = mPowerManagerListenerTokens.get(binder);
652 finishedLocked(binder, token);
653 }
654 }
655 }
Steve Paik388d7772018-02-12 10:54:51 -0800656 }
657
658 @Override
659 public void requestShutdownOnNextSuspend() {
660 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
661 mShutdownOnNextSuspend = true;
662 }
663
664 @Override
665 public int getBootReason() {
666 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
667 // Return the most recent bootReason value
668 return mBootReason;
669 }
670
671 @Override
Steve Paik03124082018-02-16 11:19:26 -0800672 public void finished(ICarPowerStateListener listener, int token) {
Steve Paik388d7772018-02-12 10:54:51 -0800673 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
Steve Paik03124082018-02-16 11:19:26 -0800674 synchronized (mPowerManagerListenerTokens) {
675 finishedLocked(listener.asBinder(), token);
676 }
677 }
678
679 private void finishedLocked(IBinder binder, int token) {
680 int currentToken = mPowerManagerListenerTokens.get(binder);
681 if (currentToken == token) {
682 mPowerManagerListenerTokens.remove(binder);
683 if (mPowerManagerListenerTokens.isEmpty() &&
684 (mCurrentState.mState == PowerHalService.STATE_SHUTDOWN_PREPARE)) {
685 // All apps are ready to shutdown/suspend.
686 Log.i(CarLog.TAG_POWER, "Apps are finished, call notifyPowerEventProcessingCompletion");
687 notifyPowerEventProcessingCompletion(null);
688 }
689 }
Steve Paik388d7772018-02-12 10:54:51 -0800690 }
691
keunyoung4b0212c2015-10-29 17:11:57 -0700692 private class PowerHandler extends Handler {
693
694 private final int MSG_POWER_STATE_CHANGE = 0;
695 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
696 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
697 private final int MSG_PROCESSING_COMPLETE = 3;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800698 private final int MSG_NOTIFY_POWER_ON = 4;
keunyoung4b0212c2015-10-29 17:11:57 -0700699
700 // Do not handle this immediately but with some delay as there can be a race between
701 // display off due to rear view camera and delivery to here.
702 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
703
704 private PowerHandler(Looper looper) {
705 super(looper);
706 }
707
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800708 private void handlePowerStateChange() {
709 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
keunyoung4b0212c2015-10-29 17:11:57 -0700710 sendMessage(msg);
711 }
712
713 private void handleDisplayBrightnessChange(int brightness) {
714 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
715 sendMessage(msg);
716 }
717
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800718 private void handleMainDisplayStateChange(boolean on) {
keunyoung4b0212c2015-10-29 17:11:57 -0700719 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800720 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on));
keunyoung4b0212c2015-10-29 17:11:57 -0700721 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS);
722 }
723
724 private void handleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800725 removeMessages(MSG_PROCESSING_COMPLETE);
keunyoung4b0212c2015-10-29 17:11:57 -0700726 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE, shutdownWhenCompleted ? 1 : 0, 0);
727 sendMessage(msg);
728 }
729
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800730 private void handlePowerOn() {
731 Message msg = obtainMessage(MSG_NOTIFY_POWER_ON);
732 sendMessage(msg);
733 }
734
735 private void cancelProcessingComplete() {
736 removeMessages(MSG_PROCESSING_COMPLETE);
737 }
738
keunyoung4b0212c2015-10-29 17:11:57 -0700739 private void cancelAll() {
740 removeMessages(MSG_POWER_STATE_CHANGE);
741 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
742 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
743 removeMessages(MSG_PROCESSING_COMPLETE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800744 removeMessages(MSG_NOTIFY_POWER_ON);
keunyoung4b0212c2015-10-29 17:11:57 -0700745 }
746
747 @Override
748 public void handleMessage(Message msg) {
749 switch (msg.what) {
750 case MSG_POWER_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800751 doHandlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700752 break;
753 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
754 doHandleDisplayBrightnessChange(msg.arg1);
755 break;
756 case MSG_MAIN_DISPLAY_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800757 doHandleMainDisplayStateChange((Boolean) msg.obj);
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800758 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700759 case MSG_PROCESSING_COMPLETE:
760 doHandleProcessingComplete(msg.arg1 == 1);
761 break;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800762 case MSG_NOTIFY_POWER_ON:
763 doHandleNotifyPowerOn();
764 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700765 }
766 }
767 }
768
keunyoung4b0212c2015-10-29 17:11:57 -0700769 private class ShutdownProcessingTimerTask extends TimerTask {
770 private final boolean mShutdownWhenCompleted;
771 private final int mExpirationCount;
772 private int mCurrentCount;
773
774 private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) {
775 mShutdownWhenCompleted = shutdownWhenCompleted;
776 mExpirationCount = expirationCount;
777 mCurrentCount = 0;
778 }
779
780 @Override
781 public void run() {
782 mCurrentCount++;
783 if (mCurrentCount > mExpirationCount) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700784 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800785 synchronized (CarPowerManagementService.this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700786 releaseTimerLocked();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700787 handler = mHandler;
keunyoung4b0212c2015-10-29 17:11:57 -0700788 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700789 handler.handleProcessingComplete(mShutdownWhenCompleted);
keunyoung4b0212c2015-10-29 17:11:57 -0700790 } else {
791 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
792 }
793 }
794 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800795
796 private static class PowerEventProcessingHandlerWrapper {
797 public final PowerEventProcessingHandler handler;
798 private long mProcessingTime = 0;
799 private boolean mProcessingDone = true;
800 private boolean mPowerOnSent = false;
Keun-young Parkd73afae2016-04-08 20:03:32 -0700801 private int mLastDisplayState = -1;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800802
803 public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) {
804 this.handler = handler;
805 }
806
807 public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) {
808 mProcessingTime = processingTime;
809 mProcessingDone = false;
810 }
811
812 public synchronized long getProcessingTime() {
813 return mProcessingTime;
814 }
815
816 public synchronized void markProcessingDone() {
817 mProcessingDone = true;
818 }
819
820 public synchronized boolean isProcessingDone() {
821 return mProcessingDone;
822 }
823
824 public void callOnPowerOn(boolean displayOn) {
Keun-young Parkd73afae2016-04-08 20:03:32 -0700825 int newDisplayState = displayOn ? 1 : 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800826 boolean shouldCall = false;
827 synchronized (this) {
Keun-young Parkd73afae2016-04-08 20:03:32 -0700828 if (!mPowerOnSent || (mLastDisplayState != newDisplayState)) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800829 shouldCall = true;
830 mPowerOnSent = true;
Keun-young Parkd73afae2016-04-08 20:03:32 -0700831 mLastDisplayState = newDisplayState;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800832 }
833 }
834 if (shouldCall) {
835 handler.onPowerOn(displayOn);
836 }
837 }
838
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800839 @Override
840 public String toString() {
841 return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime="
842 + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]";
843 }
844 }
keunyoung4b0212c2015-10-29 17:11:57 -0700845}