blob: 017a1e7a7b823b16e953089419099b09627c0086 [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 Paik388d7772018-02-12 10:54:51 -080018import java.io.PrintWriter;
19import java.util.LinkedList;
Steve Paik03124082018-02-16 11:19:26 -080020import java.util.Map;
Steve Paik388d7772018-02-12 10:54:51 -080021import java.util.Timer;
22import java.util.TimerTask;
Steve Paik03124082018-02-16 11:19:26 -080023import java.util.concurrent.ConcurrentHashMap;
Steve Paik388d7772018-02-12 10:54:51 -080024import java.util.concurrent.CopyOnWriteArrayList;
keunyoung4b0212c2015-10-29 17:11:57 -070025
26import com.android.car.hal.PowerHalService;
27import com.android.car.hal.PowerHalService.PowerState;
Enrico Granatab19bc322017-10-12 12:25:06 -070028import com.android.car.systeminterface.SystemInterface;
keunyoung4b0212c2015-10-29 17:11:57 -070029import com.android.internal.annotations.GuardedBy;
Yao Chendacd7242016-01-26 14:42:42 -080030import com.android.internal.annotations.VisibleForTesting;
keunyoung4b0212c2015-10-29 17:11:57 -070031
Steve Paik388d7772018-02-12 10:54:51 -080032import android.car.Car;
Steve Paik03124082018-02-16 11:19:26 -080033import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
Steve Paik388d7772018-02-12 10:54:51 -080034import android.car.hardware.power.ICarPower;
35import android.car.hardware.power.ICarPowerStateListener;
36import android.content.Context;
Steve Paik03124082018-02-16 11:19:26 -080037import android.os.Binder;
Steve Paik388d7772018-02-12 10:54:51 -080038import android.os.Handler;
39import android.os.HandlerThread;
Steve Paik03124082018-02-16 11:19:26 -080040import android.os.IBinder;
Steve Paik388d7772018-02-12 10:54:51 -080041import android.os.Looper;
42import android.os.Message;
Steve Paik03124082018-02-16 11:19:26 -080043import android.os.PowerManager;
44import android.os.RemoteCallbackList;
45import android.os.RemoteException;
Steve Paik388d7772018-02-12 10:54:51 -080046import android.os.SystemClock;
47import android.util.Log;
keunyoung4b0212c2015-10-29 17:11:57 -070048
Steve Paik388d7772018-02-12 10:54:51 -080049public class CarPowerManagementService extends ICarPower.Stub implements CarServiceBase,
keunyoung4b0212c2015-10-29 17:11:57 -070050 PowerHalService.PowerEventListener {
51
52 /**
53 * Listener for other services to monitor power events.
54 */
55 public interface PowerServiceEventListener {
56 /**
57 * Shutdown is happening
58 */
59 void onShutdown();
60
61 /**
62 * Entering deep sleep.
63 */
64 void onSleepEntry();
65
66 /**
67 * Got out of deep sleep.
68 */
69 void onSleepExit();
70 }
71
72 /**
73 * Interface for components requiring processing time before shutting-down or
74 * entering sleep, and wake-up after shut-down.
75 */
76 public interface PowerEventProcessingHandler {
77 /**
78 * Called before shutdown or sleep entry to allow running some processing. This call
79 * should only queue such task in different thread and should return quickly.
80 * Blocking inside this call can trigger watchdog timer which can terminate the
81 * whole system.
82 * @param shuttingDown whether system is shutting down or not (= sleep entry).
83 * @return time necessary to run processing in ms. should return 0 if there is no
84 * processing necessary.
85 */
Keun-young Park303ea1d2016-01-21 11:26:16 -080086 long onPrepareShutdown(boolean shuttingDown);
87
88 /**
89 * Called when power state is changed to ON state. Display can be either on or off.
90 * @param displayOn
91 */
92 void onPowerOn(boolean displayOn);
keunyoung4b0212c2015-10-29 17:11:57 -070093
94 /**
95 * Returns wake up time after system is fully shutdown. Power controller will power on
96 * the system after this time. This power on is meant for regular maintenance kind of
97 * operation.
98 * @return 0 of wake up is not necessary.
99 */
100 int getWakeupTime();
101 }
102
Steve Paik388d7772018-02-12 10:54:51 -0800103 private final Context mContext;
keunyoung4b0212c2015-10-29 17:11:57 -0700104 private final PowerHalService mHal;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700105 private final SystemInterface mSystemInterface;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800106
keunyoung4b0212c2015-10-29 17:11:57 -0700107 private final CopyOnWriteArrayList<PowerServiceEventListener> mListeners =
108 new CopyOnWriteArrayList<>();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800109 private final CopyOnWriteArrayList<PowerEventProcessingHandlerWrapper>
110 mPowerEventProcessingHandlers = new CopyOnWriteArrayList<>();
Steve Paik03124082018-02-16 11:19:26 -0800111 private final PowerManagerCallbackList mPowerManagerListeners = new PowerManagerCallbackList();
112 private final Map<IBinder, Integer> mPowerManagerListenerTokens = new ConcurrentHashMap<>();
113 private int mTokenValue = 1;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800114
115 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700116 private PowerState mCurrentState;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800117 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700118 private Timer mTimer;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800119 @GuardedBy("this")
120 private long mProcessingStartTime;
121 @GuardedBy("this")
122 private long mLastSleepEntryTime;
123 @GuardedBy("this")
124 private final LinkedList<PowerState> mPendingPowerStates = new LinkedList<>();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700125 @GuardedBy("this")
126 private HandlerThread mHandlerThread;
127 @GuardedBy("this")
128 private PowerHandler mHandler;
Steve Paik388d7772018-02-12 10:54:51 -0800129 private int mBootReason;
Steve Paik388d7772018-02-12 10:54:51 -0800130 private boolean mShutdownOnNextSuspend = false;
keunyoung4b0212c2015-10-29 17:11:57 -0700131
Steve Paik03124082018-02-16 11:19:26 -0800132 // TODO: Make this OEM configurable.
133 private final static int APP_EXTEND_MAX_MS = 10000;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700134 private final static int SHUTDOWN_POLLING_INTERVAL_MS = 2000;
135 private final static int SHUTDOWN_EXTEND_MAX_MS = 5000;
keunyoung4b0212c2015-10-29 17:11:57 -0700136
Steve Paik03124082018-02-16 11:19:26 -0800137 private class PowerManagerCallbackList extends RemoteCallbackList<ICarPowerStateListener> {
138 /**
139 * Old version of {@link #onCallbackDied(E, Object)} that
140 * does not provide a cookie.
141 */
142 @Override
143 public void onCallbackDied(ICarPowerStateListener listener) {
144 Log.i(CarLog.TAG_POWER, "binderDied " + listener.asBinder());
145 CarPowerManagementService.this.doUnregisterListener(listener);
146 }
147 }
148
Steve Paik388d7772018-02-12 10:54:51 -0800149 public CarPowerManagementService(Context context, PowerHalService powerHal,
150 SystemInterface systemInterface) {
151 mContext = context;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800152 mHal = powerHal;
153 mSystemInterface = systemInterface;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800154 }
155
156 /**
157 * Create a dummy instance for unit testing purpose only. Instance constructed in this way
158 * is not safe as members expected to be non-null are null.
Yao Chendacd7242016-01-26 14:42:42 -0800159 */
160 @VisibleForTesting
161 protected CarPowerManagementService() {
Steve Paik388d7772018-02-12 10:54:51 -0800162 mContext = null;
Yao Chendacd7242016-01-26 14:42:42 -0800163 mHal = null;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800164 mSystemInterface = null;
Yao Chendacd7242016-01-26 14:42:42 -0800165 mHandlerThread = null;
Keun-young Parkca013ae2016-02-10 16:22:25 -0800166 mHandler = new PowerHandler(Looper.getMainLooper());
Yao Chendacd7242016-01-26 14:42:42 -0800167 }
168
keunyoung4b0212c2015-10-29 17:11:57 -0700169 @Override
170 public void init() {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700171 synchronized (this) {
172 mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
173 mHandlerThread.start();
174 mHandler = new PowerHandler(mHandlerThread.getLooper());
175 }
176
keunyoung4b0212c2015-10-29 17:11:57 -0700177 mHal.setListener(this);
178 if (mHal.isPowerStateSupported()) {
179 mHal.sendBootComplete();
180 PowerState currentState = mHal.getCurrentPowerState();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700181 if (currentState != null) {
182 onApPowerStateChange(currentState);
183 } else {
184 Log.w(CarLog.TAG_POWER, "Unable to get get current power state during "
185 + "initialization");
186 }
keunyoung4b0212c2015-10-29 17:11:57 -0700187 } else {
188 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet.");
Keun-young Parkfad57922016-04-21 11:00:45 -0700189 onApPowerStateChange(new PowerState(PowerHalService.STATE_ON_FULL, 0));
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800190 mSystemInterface.switchToFullWakeLock();
keunyoung4b0212c2015-10-29 17:11:57 -0700191 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800192 mSystemInterface.startDisplayStateMonitoring(this);
keunyoung4b0212c2015-10-29 17:11:57 -0700193 }
194
195 @Override
196 public void release() {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700197 HandlerThread handlerThread;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800198 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700199 releaseTimerLocked();
200 mCurrentState = null;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700201 mHandler.cancelAll();
202 handlerThread = mHandlerThread;
203 }
204 handlerThread.quitSafely();
205 try {
206 handlerThread.join(1000);
207 } catch (InterruptedException e) {
208 Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join.");
keunyoung4b0212c2015-10-29 17:11:57 -0700209 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800210 mSystemInterface.stopDisplayStateMonitoring();
keunyoung4b0212c2015-10-29 17:11:57 -0700211 mListeners.clear();
Keun-young Park303ea1d2016-01-21 11:26:16 -0800212 mPowerEventProcessingHandlers.clear();
Steve Paik03124082018-02-16 11:19:26 -0800213 mPowerManagerListeners.kill();
214 mPowerManagerListenerTokens.clear();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800215 mSystemInterface.releaseAllWakeLocks();
keunyoung4b0212c2015-10-29 17:11:57 -0700216 }
217
218 /**
219 * Register listener to monitor power event. There is no unregister counter-part and the list
220 * will be cleared when the service is released.
221 * @param listener
222 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800223 public synchronized void registerPowerEventListener(PowerServiceEventListener listener) {
keunyoung4b0212c2015-10-29 17:11:57 -0700224 mListeners.add(listener);
225 }
226
227 /**
228 * Register PowerEventPreprocessingHandler to run pre-processing before shutdown or
229 * sleep entry. There is no unregister counter-part and the list
230 * will be cleared when the service is released.
231 * @param handler
232 */
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800233 public synchronized void registerPowerEventProcessingHandler(
234 PowerEventProcessingHandler handler) {
235 mPowerEventProcessingHandlers.add(new PowerEventProcessingHandlerWrapper(handler));
236 // onPowerOn will not be called if power on notification is already done inside the
237 // handler thread. So request it once again here. Wrapper will have its own
238 // gatekeeping to prevent calling onPowerOn twice.
239 mHandler.handlePowerOn();
keunyoung4b0212c2015-10-29 17:11:57 -0700240 }
241
242 /**
243 * Notifies earlier completion of power event processing. PowerEventProcessingHandler quotes
244 * time necessary from onPrePowerEvent() call, but actual processing can finish earlier than
245 * that, and this call can be called in such case to trigger shutdown without waiting further.
246 *
247 * @param handler PowerEventProcessingHandler that was already registered with
248 * {@link #registerPowerEventListener(PowerServiceEventListener)} call. If it was not
249 * registered before, this call will be ignored.
250 */
251 public void notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800252 long processingTime = 0;
253 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
254 if (wrapper.handler == handler) {
255 wrapper.markProcessingDone();
256 } else if (!wrapper.isProcessingDone()) {
257 processingTime = Math.max(processingTime, wrapper.getProcessingTime());
258 }
259 }
Steve Paik03124082018-02-16 11:19:26 -0800260 synchronized (mPowerManagerListenerTokens) {
261 if (!mPowerManagerListenerTokens.isEmpty()) {
262 processingTime += APP_EXTEND_MAX_MS;
263 }
264 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800265 long now = SystemClock.elapsedRealtime();
266 long startTime;
267 boolean shouldShutdown = true;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700268 PowerHandler powerHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800269 synchronized (this) {
270 startTime = mProcessingStartTime;
271 if (mCurrentState == null) {
272 return;
273 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700274 if (mCurrentState.mState != PowerHalService.STATE_SHUTDOWN_PREPARE) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800275 return;
276 }
Steve Paik03124082018-02-16 11:19:26 -0800277 if (mCurrentState.canEnterDeepSleep() && !mShutdownOnNextSuspend) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800278 shouldShutdown = false;
279 if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < now) {
280 // already slept
281 return;
282 }
283 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700284 powerHandler = mHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800285 }
286 if ((startTime + processingTime) <= now) {
287 Log.i(CarLog.TAG_POWER, "Processing all done");
Pavel Maltsevddbff982017-03-22 14:49:02 -0700288 powerHandler.handleProcessingComplete(shouldShutdown);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800289 }
keunyoung4b0212c2015-10-29 17:11:57 -0700290 }
291
292 @Override
293 public void dump(PrintWriter writer) {
294 writer.println("*PowerManagementService*");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800295 writer.print("mCurrentState:" + mCurrentState);
296 writer.print(",mProcessingStartTime:" + mProcessingStartTime);
297 writer.println(",mLastSleepEntryTime:" + mLastSleepEntryTime);
298 writer.println("**PowerEventProcessingHandlers");
299 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
300 writer.println(wrapper.toString());
301 }
keunyoung4b0212c2015-10-29 17:11:57 -0700302 }
303
304 @Override
Steve Paik110f95f2017-11-22 14:44:05 -0800305 public void onBootReasonReceived(int bootReason) {
Steve Paik388d7772018-02-12 10:54:51 -0800306 mBootReason = bootReason;
Steve Paik110f95f2017-11-22 14:44:05 -0800307 }
308
309 @Override
keunyoung4b0212c2015-10-29 17:11:57 -0700310 public void onApPowerStateChange(PowerState state) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700311 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800312 synchronized (this) {
313 mPendingPowerStates.addFirst(state);
Pavel Maltsevddbff982017-03-22 14:49:02 -0700314 handler = mHandler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800315 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700316 handler.handlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700317 }
318
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800319 private void doHandlePowerStateChange() {
320 PowerState state = null;
Pavel Maltsevddbff982017-03-22 14:49:02 -0700321 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800322 synchronized (this) {
323 state = mPendingPowerStates.peekFirst();
324 mPendingPowerStates.clear();
325 if (state == null) {
326 return;
327 }
328 if (!needPowerStateChange(state)) {
329 return;
330 }
331 // now real power change happens. Whatever was queued before should be all cancelled.
332 releaseTimerLocked();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700333 handler = mHandler;
keunyoung4b0212c2015-10-29 17:11:57 -0700334 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700335 handler.cancelProcessingComplete();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800336
keunyoung4b0212c2015-10-29 17:11:57 -0700337 Log.i(CarLog.TAG_POWER, "Power state change:" + state);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700338 switch (state.mState) {
keunyoung4b0212c2015-10-29 17:11:57 -0700339 case PowerHalService.STATE_ON_DISP_OFF:
340 handleDisplayOff(state);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800341 notifyPowerOn(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700342 break;
343 case PowerHalService.STATE_ON_FULL:
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800344 handleFullOn(state);
345 notifyPowerOn(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700346 break;
347 case PowerHalService.STATE_SHUTDOWN_PREPARE:
348 handleShutdownPrepare(state);
349 break;
350 }
351 }
352
353 private void handleDisplayOff(PowerState newState) {
354 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800355 mSystemInterface.setDisplayState(false);
keunyoung4b0212c2015-10-29 17:11:57 -0700356 }
357
358 private void handleFullOn(PowerState newState) {
359 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800360 mSystemInterface.setDisplayState(true);
keunyoung4b0212c2015-10-29 17:11:57 -0700361 }
362
Yao Chendacd7242016-01-26 14:42:42 -0800363 @VisibleForTesting
364 protected void notifyPowerOn(boolean displayOn) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800365 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
366 wrapper.callOnPowerOn(displayOn);
Keun-young Park303ea1d2016-01-21 11:26:16 -0800367 }
368 }
369
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800370 @VisibleForTesting
371 protected long notifyPrepareShutdown(boolean shuttingDown) {
372 long processingTimeMs = 0;
373 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
374 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
375 if (handlerProcessingTime > processingTimeMs) {
376 processingTimeMs = handlerProcessingTime;
377 }
378 }
Steve Paik03124082018-02-16 11:19:26 -0800379 // Add time for powerManager events
380 processingTimeMs += sendPowerManagerEvent(shuttingDown);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800381 return processingTimeMs;
382 }
383
keunyoung4b0212c2015-10-29 17:11:57 -0700384 private void handleShutdownPrepare(PowerState newState) {
385 setCurrentState(newState);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800386 mSystemInterface.setDisplayState(false);;
keunyoung4b0212c2015-10-29 17:11:57 -0700387 boolean shouldShutdown = true;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800388 if (mHal.isDeepSleepAllowed() && mSystemInterface.isSystemSupportingDeepSleep() &&
Steve Paik03124082018-02-16 11:19:26 -0800389 newState.canEnterDeepSleep() && !mShutdownOnNextSuspend) {
keunyoung4b0212c2015-10-29 17:11:57 -0700390 Log.i(CarLog.TAG_POWER, "starting sleep");
391 shouldShutdown = false;
392 doHandlePreprocessing(shouldShutdown);
393 return;
394 } else if (newState.canPostponeShutdown()) {
395 Log.i(CarLog.TAG_POWER, "starting shutdown with processing");
396 doHandlePreprocessing(shouldShutdown);
397 } else {
398 Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800399 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700400 releaseTimerLocked();
401 }
402 doHandleShutdown();
403 }
404 }
405
Andreas Gampe985ca2f2018-02-09 12:57:54 -0800406 @GuardedBy("this")
keunyoung4b0212c2015-10-29 17:11:57 -0700407 private void releaseTimerLocked() {
408 if (mTimer != null) {
409 mTimer.cancel();
410 }
411 mTimer = null;
412 }
413
414 private void doHandlePreprocessing(boolean shuttingDown) {
415 long processingTimeMs = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800416 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
417 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown);
418 if (handlerProcessingTime > 0) {
419 wrapper.setProcessingTimeAndResetProcessingDone(handlerProcessingTime);
420 }
keunyoung4b0212c2015-10-29 17:11:57 -0700421 if (handlerProcessingTime > processingTimeMs) {
422 processingTimeMs = handlerProcessingTime;
423 }
424 }
Steve Paik03124082018-02-16 11:19:26 -0800425 // Add time for powerManager events
426 processingTimeMs += sendPowerManagerEvent(shuttingDown);
keunyoung4b0212c2015-10-29 17:11:57 -0700427 if (processingTimeMs > 0) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800428 int pollingCount = (int)(processingTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1;
keunyoung4b0212c2015-10-29 17:11:57 -0700429 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for :" + processingTimeMs +
430 " ms, adding polling:" + pollingCount);
431 synchronized (this) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800432 mProcessingStartTime = SystemClock.elapsedRealtime();
keunyoung4b0212c2015-10-29 17:11:57 -0700433 releaseTimerLocked();
434 mTimer = new Timer();
435 mTimer.scheduleAtFixedRate(new ShutdownProcessingTimerTask(shuttingDown,
436 pollingCount),
437 0 /*delay*/,
438 SHUTDOWN_POLLING_INTERVAL_MS);
439 }
440 } else {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700441 PowerHandler handler;
442 synchronized (this) {
443 handler = mHandler;
444 }
445 handler.handleProcessingComplete(shuttingDown);
keunyoung4b0212c2015-10-29 17:11:57 -0700446 }
447 }
448
Steve Paik03124082018-02-16 11:19:26 -0800449 private long sendPowerManagerEvent(boolean shuttingDown) {
450 long processingTimeMs = 0;
451 int newState = shuttingDown ? CarPowerStateListener.SHUTDOWN_ENTER :
452 CarPowerStateListener.SUSPEND_ENTER;
453 synchronized (mPowerManagerListenerTokens) {
454 mPowerManagerListenerTokens.clear();
455 int i = mPowerManagerListeners.beginBroadcast();
456 while (i-- > 0) {
457 try {
458 ICarPowerStateListener listener = mPowerManagerListeners.getBroadcastItem(i);
459 listener.onStateChanged(newState, mTokenValue);
460 mPowerManagerListenerTokens.put(listener.asBinder(), mTokenValue);
461 mTokenValue++;
462 } catch (RemoteException e) {
463 // Its likely the connection snapped. Let binder death handle the situation.
464 Log.e(CarLog.TAG_POWER, "onStateChanged calling failed: " + e);
465 }
466 }
467 mPowerManagerListeners.finishBroadcast();
468 if (!mPowerManagerListenerTokens.isEmpty()) {
469 Log.i(CarLog.TAG_POWER, "mPowerMangerListenerTokens not empty, add APP_EXTEND_MAX_MS");
470 processingTimeMs += APP_EXTEND_MAX_MS;
471 }
472 }
473 return processingTimeMs;
474 }
475
keunyoung4b0212c2015-10-29 17:11:57 -0700476 private void doHandleDeepSleep() {
Keun-young Park9d4cf622016-08-04 13:24:28 -0700477 // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
478 // enterDeepSleep should force sleep entry even if wake lock is kept.
479 mSystemInterface.switchToPartialWakeLock();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700480 PowerHandler handler;
481 synchronized (this) {
482 handler = mHandler;
483 }
484 handler.cancelProcessingComplete();
keunyoung4b0212c2015-10-29 17:11:57 -0700485 for (PowerServiceEventListener listener : mListeners) {
486 listener.onSleepEntry();
487 }
488 int wakeupTimeSec = getWakeupTime();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800489 mHal.sendSleepEntry();
490 synchronized (this) {
491 mLastSleepEntryTime = SystemClock.elapsedRealtime();
492 }
Steve Paik0f9fc002018-02-09 17:42:00 -0800493 if (mSystemInterface.enterDeepSleep(wakeupTimeSec) == false) {
494 // System did not suspend. Need to shutdown
495 // TODO: Shutdown gracefully
Steve Paik03124082018-02-16 11:19:26 -0800496 Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Need to shutdown");
Steve Paik0f9fc002018-02-09 17:42:00 -0800497 }
keunyoung4b0212c2015-10-29 17:11:57 -0700498 mHal.sendSleepExit();
499 for (PowerServiceEventListener listener : mListeners) {
500 listener.onSleepExit();
501 }
Steve Paik03124082018-02-16 11:19:26 -0800502 // Notify applications
503 int i = mPowerManagerListeners.beginBroadcast();
504 while (i-- > 0) {
505 try {
506 ICarPowerStateListener listener = mPowerManagerListeners.getBroadcastItem(i);
507 listener.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, 0);
508 } catch (RemoteException e) {
509 // Its likely the connection snapped. Let binder death handle the situation.
510 Log.e(CarLog.TAG_POWER, "onStateChanged calling failed: " + e);
511 }
512 }
513 mPowerManagerListeners.finishBroadcast();
514
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800515 if (mSystemInterface.isWakeupCausedByTimer()) {
keunyoung4b0212c2015-10-29 17:11:57 -0700516 doHandlePreprocessing(false /*shuttingDown*/);
517 } else {
518 PowerState currentState = mHal.getCurrentPowerState();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700519 if (currentState != null && needPowerStateChange(currentState)) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800520 onApPowerStateChange(currentState);
keunyoung4b0212c2015-10-29 17:11:57 -0700521 } else { // power controller woke-up but no power state change. Just shutdown.
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800522 Log.w(CarLog.TAG_POWER, "external sleep wake up, but no power state change:" +
keunyoung4b0212c2015-10-29 17:11:57 -0700523 currentState);
524 doHandleShutdown();
525 }
526 }
527 }
528
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800529 private void doHandleNotifyPowerOn() {
530 boolean displayOn = false;
531 synchronized (this) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700532 if (mCurrentState != null && mCurrentState.mState == PowerHalService.STATE_ON_FULL) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800533 displayOn = true;
534 }
535 }
536 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
537 // wrapper will not send it forward if it is already called.
538 wrapper.callOnPowerOn(displayOn);
539 }
540 }
541
542 private boolean needPowerStateChange(PowerState newState) {
543 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700544 if (mCurrentState != null && mCurrentState.equals(newState)) {
545 return false;
546 }
547 return true;
548 }
549 }
550
keunyoung4b0212c2015-10-29 17:11:57 -0700551 private void doHandleShutdown() {
552 // now shutdown
553 for (PowerServiceEventListener listener : mListeners) {
554 listener.onShutdown();
555 }
556 int wakeupTimeSec = 0;
557 if (mHal.isTimedWakeupAllowed()) {
558 wakeupTimeSec = getWakeupTime();
559 }
560 mHal.sendShutdownStart(wakeupTimeSec);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700561 mSystemInterface.shutdown();
keunyoung4b0212c2015-10-29 17:11:57 -0700562 }
563
564 private int getWakeupTime() {
565 int wakeupTimeSec = 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800566 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) {
567 int t = wrapper.handler.getWakeupTime();
keunyoung4b0212c2015-10-29 17:11:57 -0700568 if (t > wakeupTimeSec) {
569 wakeupTimeSec = t;
570 }
571 }
572 return wakeupTimeSec;
573 }
574
575 private void doHandleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800576 synchronized (this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700577 releaseTimerLocked();
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800578 if (!shutdownWhenCompleted && mLastSleepEntryTime > mProcessingStartTime) {
579 // entered sleep after processing start. So this could be duplicate request.
580 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
581 return;
582 }
keunyoung4b0212c2015-10-29 17:11:57 -0700583 }
584 if (shutdownWhenCompleted) {
585 doHandleShutdown();
586 } else {
587 doHandleDeepSleep();
588 }
589 }
590
keunyoung4b0212c2015-10-29 17:11:57 -0700591 private synchronized void setCurrentState(PowerState state) {
592 mCurrentState = state;
593 }
594
595 @Override
596 public void onDisplayBrightnessChange(int brightness) {
Keun-young Parkf9215202016-10-10 12:34:08 -0700597 // TODO bug: 32065231
keunyoung4b0212c2015-10-29 17:11:57 -0700598 }
599
600 private void doHandleDisplayBrightnessChange(int brightness) {
Keun-young Parkf9215202016-10-10 12:34:08 -0700601 //TODO bug: 32065231
keunyoung4b0212c2015-10-29 17:11:57 -0700602 }
603
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800604 private void doHandleMainDisplayStateChange(boolean on) {
Keun-young Parkf9215202016-10-10 12:34:08 -0700605 //TODO bug: 32065231
keunyoung4b0212c2015-10-29 17:11:57 -0700606 }
607
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800608 public void handleMainDisplayChanged(boolean on) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700609 PowerHandler handler;
610 synchronized (this) {
611 handler = mHandler;
612 }
613 handler.handleMainDisplayStateChange(on);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800614 }
615
Pavel Maltsevddbff982017-03-22 14:49:02 -0700616 public synchronized Handler getHandler() {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800617 return mHandler;
618 }
619
Steve Paik388d7772018-02-12 10:54:51 -0800620 // Binder interface for CarPowerManager
621 @Override
622 public void registerListener(ICarPowerStateListener listener) {
623 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
Steve Paik03124082018-02-16 11:19:26 -0800624 mPowerManagerListeners.register(listener);
Steve Paik388d7772018-02-12 10:54:51 -0800625 }
626
627 @Override
628 public void unregisterListener(ICarPowerStateListener listener) {
629 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
Steve Paik03124082018-02-16 11:19:26 -0800630 doUnregisterListener(listener);
631 }
632
633 private void doUnregisterListener(ICarPowerStateListener listener) {
634 boolean found = mPowerManagerListeners.unregister(listener);
635
636 if (found) {
637 // Remove outstanding token if there is one
638 IBinder binder = listener.asBinder();
639 synchronized (mPowerManagerListenerTokens) {
640 if (mPowerManagerListenerTokens.containsKey(binder)) {
641 int token = mPowerManagerListenerTokens.get(binder);
642 finishedLocked(binder, token);
643 }
644 }
645 }
Steve Paik388d7772018-02-12 10:54:51 -0800646 }
647
648 @Override
649 public void requestShutdownOnNextSuspend() {
650 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
651 mShutdownOnNextSuspend = true;
652 }
653
654 @Override
655 public int getBootReason() {
656 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
657 // Return the most recent bootReason value
658 return mBootReason;
659 }
660
661 @Override
Steve Paik03124082018-02-16 11:19:26 -0800662 public void finished(ICarPowerStateListener listener, int token) {
Steve Paik388d7772018-02-12 10:54:51 -0800663 ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
Steve Paik03124082018-02-16 11:19:26 -0800664 synchronized (mPowerManagerListenerTokens) {
665 finishedLocked(listener.asBinder(), token);
666 }
667 }
668
669 private void finishedLocked(IBinder binder, int token) {
670 int currentToken = mPowerManagerListenerTokens.get(binder);
671 if (currentToken == token) {
672 mPowerManagerListenerTokens.remove(binder);
673 if (mPowerManagerListenerTokens.isEmpty() &&
674 (mCurrentState.mState == PowerHalService.STATE_SHUTDOWN_PREPARE)) {
675 // All apps are ready to shutdown/suspend.
676 Log.i(CarLog.TAG_POWER, "Apps are finished, call notifyPowerEventProcessingCompletion");
677 notifyPowerEventProcessingCompletion(null);
678 }
679 }
Steve Paik388d7772018-02-12 10:54:51 -0800680 }
681
keunyoung4b0212c2015-10-29 17:11:57 -0700682 private class PowerHandler extends Handler {
683
684 private final int MSG_POWER_STATE_CHANGE = 0;
685 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1;
686 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2;
687 private final int MSG_PROCESSING_COMPLETE = 3;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800688 private final int MSG_NOTIFY_POWER_ON = 4;
keunyoung4b0212c2015-10-29 17:11:57 -0700689
690 // Do not handle this immediately but with some delay as there can be a race between
691 // display off due to rear view camera and delivery to here.
692 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500;
693
694 private PowerHandler(Looper looper) {
695 super(looper);
696 }
697
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800698 private void handlePowerStateChange() {
699 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
keunyoung4b0212c2015-10-29 17:11:57 -0700700 sendMessage(msg);
701 }
702
703 private void handleDisplayBrightnessChange(int brightness) {
704 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0);
705 sendMessage(msg);
706 }
707
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800708 private void handleMainDisplayStateChange(boolean on) {
keunyoung4b0212c2015-10-29 17:11:57 -0700709 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800710 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on));
keunyoung4b0212c2015-10-29 17:11:57 -0700711 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS);
712 }
713
714 private void handleProcessingComplete(boolean shutdownWhenCompleted) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800715 removeMessages(MSG_PROCESSING_COMPLETE);
keunyoung4b0212c2015-10-29 17:11:57 -0700716 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE, shutdownWhenCompleted ? 1 : 0, 0);
717 sendMessage(msg);
718 }
719
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800720 private void handlePowerOn() {
721 Message msg = obtainMessage(MSG_NOTIFY_POWER_ON);
722 sendMessage(msg);
723 }
724
725 private void cancelProcessingComplete() {
726 removeMessages(MSG_PROCESSING_COMPLETE);
727 }
728
keunyoung4b0212c2015-10-29 17:11:57 -0700729 private void cancelAll() {
730 removeMessages(MSG_POWER_STATE_CHANGE);
731 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE);
732 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE);
733 removeMessages(MSG_PROCESSING_COMPLETE);
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800734 removeMessages(MSG_NOTIFY_POWER_ON);
keunyoung4b0212c2015-10-29 17:11:57 -0700735 }
736
737 @Override
738 public void handleMessage(Message msg) {
739 switch (msg.what) {
740 case MSG_POWER_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800741 doHandlePowerStateChange();
keunyoung4b0212c2015-10-29 17:11:57 -0700742 break;
743 case MSG_DISPLAY_BRIGHTNESS_CHANGE:
744 doHandleDisplayBrightnessChange(msg.arg1);
745 break;
746 case MSG_MAIN_DISPLAY_STATE_CHANGE:
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800747 doHandleMainDisplayStateChange((Boolean) msg.obj);
Keun-young Park1f4d6a72016-02-11 09:49:47 -0800748 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700749 case MSG_PROCESSING_COMPLETE:
750 doHandleProcessingComplete(msg.arg1 == 1);
751 break;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800752 case MSG_NOTIFY_POWER_ON:
753 doHandleNotifyPowerOn();
754 break;
keunyoung4b0212c2015-10-29 17:11:57 -0700755 }
756 }
757 }
758
keunyoung4b0212c2015-10-29 17:11:57 -0700759 private class ShutdownProcessingTimerTask extends TimerTask {
760 private final boolean mShutdownWhenCompleted;
761 private final int mExpirationCount;
762 private int mCurrentCount;
763
764 private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) {
765 mShutdownWhenCompleted = shutdownWhenCompleted;
766 mExpirationCount = expirationCount;
767 mCurrentCount = 0;
768 }
769
770 @Override
771 public void run() {
772 mCurrentCount++;
773 if (mCurrentCount > mExpirationCount) {
Pavel Maltsevddbff982017-03-22 14:49:02 -0700774 PowerHandler handler;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800775 synchronized (CarPowerManagementService.this) {
keunyoung4b0212c2015-10-29 17:11:57 -0700776 releaseTimerLocked();
Pavel Maltsevddbff982017-03-22 14:49:02 -0700777 handler = mHandler;
keunyoung4b0212c2015-10-29 17:11:57 -0700778 }
Pavel Maltsevddbff982017-03-22 14:49:02 -0700779 handler.handleProcessingComplete(mShutdownWhenCompleted);
keunyoung4b0212c2015-10-29 17:11:57 -0700780 } else {
781 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
782 }
783 }
784 }
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800785
786 private static class PowerEventProcessingHandlerWrapper {
787 public final PowerEventProcessingHandler handler;
788 private long mProcessingTime = 0;
789 private boolean mProcessingDone = true;
790 private boolean mPowerOnSent = false;
Keun-young Parkd73afae2016-04-08 20:03:32 -0700791 private int mLastDisplayState = -1;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800792
793 public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) {
794 this.handler = handler;
795 }
796
797 public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) {
798 mProcessingTime = processingTime;
799 mProcessingDone = false;
800 }
801
802 public synchronized long getProcessingTime() {
803 return mProcessingTime;
804 }
805
806 public synchronized void markProcessingDone() {
807 mProcessingDone = true;
808 }
809
810 public synchronized boolean isProcessingDone() {
811 return mProcessingDone;
812 }
813
814 public void callOnPowerOn(boolean displayOn) {
Keun-young Parkd73afae2016-04-08 20:03:32 -0700815 int newDisplayState = displayOn ? 1 : 0;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800816 boolean shouldCall = false;
817 synchronized (this) {
Keun-young Parkd73afae2016-04-08 20:03:32 -0700818 if (!mPowerOnSent || (mLastDisplayState != newDisplayState)) {
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800819 shouldCall = true;
820 mPowerOnSent = true;
Keun-young Parkd73afae2016-04-08 20:03:32 -0700821 mLastDisplayState = newDisplayState;
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800822 }
823 }
824 if (shouldCall) {
825 handler.onPowerOn(displayOn);
826 }
827 }
828
Keun-young Parkfd3fbf72016-01-22 17:00:17 -0800829 @Override
830 public String toString() {
831 return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime="
832 + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]";
833 }
834 }
keunyoung4b0212c2015-10-29 17:11:57 -0700835}